Tus Favoritos

Revisa, compara y decide más tarde. Gestiona tus servicios guardados y añádelos al carrito cuando estés listo.

Buscar usa el cuadro para filtrar Añadir al carrito o abrir detalle Quitar de favoritos

No tienes favoritos guardados aún. Explora nuestros servicios y guarda los que te interesen.

Tema
Oferta “Andina” termina en 00:00:00
Usamos cookies Para mejorar tu experiencia y analizar el uso. Puedes ajustar tus preferencias.
';}); function attachHeaderInteractions(){ const themeToggle = document.getElementById('globalThemeToggle'); if(themeToggle){ themeToggle.addEventListener('click', toggleTheme); } } const KEYS = { favs: 'ela_favorites', cart: 'ela_cart', cookie: 'ela_cookie_consent' }; function getFavs(){ try{ const raw = localStorage.getItem(KEYS.favs); const arr = raw ? JSON.parse(raw) : []; return Array.isArray(arr) ? arr : []; }catch(e){ return []; } } function setFavs(ids){ localStorage.setItem(KEYS.favs, JSON.stringify(Array.from(new Set(ids)))); updateEmptyState(); } function getCart(){ try{ return JSON.parse(localStorage.getItem(KEYS.cart)) || []; }catch(e){ return []; } } function setCart(items){ localStorage.setItem(KEYS.cart, JSON.stringify(items)); updateCartCount(); } function addToCart(id, qty=1){ const cart = getCart(); const i = cart.findIndex(x=>String(x.id)===String(id)); if(i>-1){ cart[i].qty += qty; } else { cart.push({id, qty}); } setCart(cart); toast('Añadido al carrito'); } function updateCartCount(){ const count = getCart().reduce((a,b)=>a+(b.qty||0),0); qs('#cartCount').textContent = count; } const state = { catalog: [], filtered: [], sort: null, lastOpenId: null }; async function loadCatalog(){ let data = []; try{ const r = await fetch('./catalog.json', {cache:'no-store'}); if(!r.ok) throw new Error('network'); data = await r.json(); }catch(e){ data = []; } if(!Array.isArray(data)){ data = []; } state.catalog = data.map(x=>({ id: x.id ?? x.ID ?? x.sku ?? String(Math.random()).slice(2), title: x.title ?? x.name ?? 'Servicio sin título', price: Number(x.price ?? x.precio ?? 0), image: x.image ?? (Array.isArray(x.images)? x.images[0] : null) ?? './images/maximum_ditailes_of_this_image.fotografia_producto_sin_imagen_placeholder_sobre_fondo_neutro_gris.jpg', category: x.category ?? x.categoria ?? 'General', description: x.description ?? x.descripcion ?? 'Consúltanos para más detalles.', currency: x.currency ?? 'CLP' })); render(); } const $list = qs('#favList'); const $tmpl = qs('#favItemTemplate'); const $empty = qs('#emptyState'); function formatPrice(val, curr='CLP'){ try{ return new Intl.NumberFormat('es-CL', {style:'currency', currency:curr}).format(val||0); }catch(e){ return '$' + (val||0).toLocaleString('es-CL'); } } function render(){ const favIds = new Set(getFavs().map(String)); const items = state.catalog.filter(p => favIds.has(String(p.id))); const term = (qs('#searchInput').value||'').trim().toLowerCase(); let filtered = items.filter(p=>{ if(!term) return true; return (p.title||'').toLowerCase().includes(term) || (p.category||'').toLowerCase().includes(term); }); if(state.sort==='price'){ filtered.sort((a,b)=>a.price-b.price); }else if(state.sort==='name'){ filtered.sort((a,b)=>String(a.title).localeCompare(String(b.title))); } state.filtered = filtered; $list.innerHTML = ''; filtered.forEach(p=>{ const node = $tmpl.content.firstElementChild.cloneNode(true); const img = node.querySelector('img'); img.src = p.image || './images/maximum_ditailes_of_this_image.fotografia_producto_sin_imagen_placeholder_sobre_fondo_neutro_gris.jpg'; img.alt = 'Servicio: ' + p.title; node.querySelector('.x-title').textContent = p.title; node.querySelector('.x-cat').textContent = p.category; node.querySelector('.x-price').textContent = formatPrice(p.price, p.currency); node.querySelector('.x-detail').addEventListener('click', ()=>openProductModal(p.id)); node.querySelector('.x-add').addEventListener('click', ()=>addToCart(p.id,1)); node.querySelector('.x-remove').addEventListener('click', ()=>removeFavorite(p.id)); $list.appendChild(node); }); updateEmptyState(); } function updateEmptyState(){ const favIds = getFavs(); if(!favIds.length){ $empty.classList.remove('m8a7q'); $list.innerHTML=''; }else{ $empty.classList.add('m8a7q'); } } function removeFavorite(id){ const favs = getFavs().filter(fid => String(fid)!==String(id)); setFavs(favs); render(); toast('Eliminado de favoritos'); } function clearFavorites(){ setFavs([]); render(); } qs('#clearFavsBtn').addEventListener('click', ()=>{ if(confirm('¿Vaciar todos los favoritos?')) clearFavorites(); }); qs('#addAllBtn').addEventListener('click', ()=>{ const favIds = getFavs(); if(!favIds.length) return; favIds.forEach(id=>addToCart(id,1)); toast('Todos añadidos al carrito'); }); qs('#exploreBtn').addEventListener('click', ()=>{ // If catalog page exists, we could navigate; otherwise open tips modal toast('Explora el catálogo desde el menú superior.'); }); qs('#sortPriceBtn').addEventListener('click', ()=>{ state.sort = 'price'; render(); }); qs('#sortNameBtn').addEventListener('click', ()=>{ state.sort = 'name'; render(); }); qs('#searchInput').addEventListener('input', ()=>{ render(); }); function openProductModal(id){ const p = state.catalog.find(x=>String(x.id)===String(id)); if(!p) return; state.lastOpenId = p.id; qs('#pmTitle').textContent = p.title; qs('#pmImage').src = p.image || './images/maximum_ditailes_of_this_image.fotografia_producto_sin_imagen_placeholder_sobre_fondo_neutro_gris.jpg'; qs('#pmCategory').textContent = p.category; qs('#pmPrice').textContent = formatPrice(p.price, p.currency); qs('#pmDesc').textContent = p.description; const favSet = new Set(getFavs().map(String)); const toggle = qs('#pmFavToggle'); toggle.textContent = favSet.has(String(p.id)) ? 'Quitar de favoritos' : 'Añadir a favoritos'; qs('#productModal').style.display='flex'; } function closeProductModal(){ qs('#productModal').style.display='none'; } qs('#pmClose').addEventListener('click', closeProductModal); qs('#pmClose2').addEventListener('click', closeProductModal); qs('#pmAddCart').addEventListener('click', ()=>{ if(state.lastOpenId) addToCart(state.lastOpenId,1); }); qs('#pmFavToggle').addEventListener('click', ()=>{ const id = state.lastOpenId; if(!id) return; const favs = getFavs(); const idx = favs.map(String).indexOf(String(id)); if(idx>-1){ favs.splice(idx,1); } else { favs.push(id); } setFavs(favs); render(); openProductModal(id); }); qs('#pmContact').addEventListener('click', ()=>{ closeProductModal(); openNotifyPanel(); }); function toggleTheme(){ const isDark = document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', isDark ? 'dark' : 'light'); } qs('#themeLight').addEventListener('click', ()=>{ document.documentElement.classList.remove('dark'); localStorage.setItem('theme','light'); }); qs('#themeDark').addEventListener('click', ()=>{ document.documentElement.classList.add('dark'); localStorage.setItem('theme','dark'); }); qs('#themeSys').addEventListener('click', ()=>{ localStorage.removeItem('theme'); const prefers = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; document.documentElement.classList.toggle('dark', prefers); }); function toast(msg){ let t = document.createElement('div'); t.style.position='fixed'; t.style.left='50%'; t.style.bottom='24px'; t.style.transform='translateX(-50%)'; t.style.background='var(--c-bg)'; t.style.color='var(--c-fg)'; t.style.border='1px solid rgba(148,163,184,.3)'; t.style.borderRadius='12px'; t.style.padding='10px 14px'; t.style.boxShadow='var(--shadow)'; t.style.zIndex='100'; t.textContent = msg; document.body.appendChild(t); setTimeout(()=>{ t.style.transition='opacity .3s'; t.style.opacity='0'; setTimeout(()=>t.remove(),300); }, 1600); } function startDealTimer(){ const end = Date.now() + 1000*60*45 + 1000*5; // 45m5s function tick(){ const left = Math.max(0, end - Date.now()); const h = Math.floor(left/3600000); const m = Math.floor((left%3600000)/60000); const s = Math.floor((left%60000)/1000); qs('#dealCountdown').textContent = String(h).padStart(2,'0')+':'+String(m).padStart(2,'0')+':'+String(s).padStart(2,'0'); if(left<=0){ clearInterval(intv); qs('#dealDot').style.background='var(--c-err)'; qs('#dealCountdown').textContent='00:00:00'; } } tick(); const intv = setInterval(tick, 1000); } function openNotifyPanel(){ const p = qs('#notifyPanel'); p.style.display='block'; p.setAttribute('aria-hidden','false'); } function closeNotifyPanel(){ const p = qs('#notifyPanel'); p.style.display='none'; p.setAttribute('aria-hidden','true'); } qs('#notifyBtn').addEventListener('click', openNotifyPanel); qs('#closeNotify').addEventListener('click', closeNotifyPanel); const nf = qs('#notifyForm'); nf.addEventListener('submit', (e)=>{ e.preventDefault(); const name = qs('#nfName').value.trim(); const email = qs('#nfEmail').value.trim(); const phone = qs('#nfPhone').value.trim(); let ok = true; const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i; const clPhone = /^\+?56\s?9\s?\d{4}\s?\d{4}$/; if(name.length<2){ ok=false; qs('#errName').style.display='block'; } else { qs('#errName').style.display='none'; } if(!emailRe.test(email)){ ok=false; qs('#errEmail').style.display='block'; } else { qs('#errEmail').style.display='none'; } if(!clPhone.test(phone)){ ok=false; qs('#errPhone').style.display='block'; } else { qs('#errPhone').style.display='none'; } if(ok){ qs('#notifySuccess').style.display='block'; setTimeout(()=>{ closeNotifyPanel(); nf.reset(); qs('#notifySuccess').style.display='none'; toast('Solicitud enviada'); }, 1200); } }); function cookieInit(){ try{ const consent = JSON.parse(localStorage.getItem(KEYS.cookie)||'null'); if(!consent){ qs('#cookieBar').style.display='block'; } qs('#cookieAccept').addEventListener('click', ()=>{ localStorage.setItem(KEYS.cookie, JSON.stringify({necessary:true, analytics:true, ts:Date.now()})); qs('#cookieBar').style.display='none'; toast('Preferencias guardadas'); }); qs('#cookieSettings').addEventListener('click', ()=>{ const choose = confirm('Activar cookies de analítica (necesarias siempre activas)?'); localStorage.setItem(KEYS.cookie', JSON.stringify({necessary:true, analytics:!!choose, ts:Date.now()})); qs('#cookieBar').style.display='none'; toast('Preferencias guardadas'); }); }catch(e){} } function initCartButton(){ qs('#cartButton').addEventListener('click', ()=>{ const items = getCart(); if(!items.length){ toast('Tu carrito está vacío'); return; } const lines = items.slice(0,5).map(it=>{ const p = state.catalog.find(x=>String(x.id)===String(it.id)); const name = p ? p.title : ('ID '+it.id); return '• '+name+' x'+it.qty; }); alert('Carrito actual:\n'+lines.join('\n')+(items.length>5?'\n…':'' )); }); } function initFavBootstrap(){ // Ensure favs exist key const raw = localStorage.getItem(KEYS.favs); if(!raw){ localStorage.setItem(KEYS.favs, JSON.stringify([])); } } // Accessibility: close modal on background click or ESC qs('#productModal').addEventListener('click', (e)=>{ if(e.target.id==='productModal') closeProductModal(); }); document.addEventListener('keydown', (e)=>{ if(e.key==='Escape'){ closeProductModal(); closeNotifyPanel(); } }); // Start initFavBootstrap(); startDealTimer(); cookieInit(); updateCartCount(); initCartButton(); loadCatalog(); })();