Files
apps-registry/workloads/ecommerce/assets/js/app.js
T
devops 1c74220c88
Build and Push Frontend / build (push) Successful in 2m30s
feat(ecommerce): release Ari Shopping Frontend v2.1 real catalog
2026-07-19 13:41:37 -05:00

1 line
8.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(()=>{"use strict";const KEY="ari-shopping-cart-v2-1";const state={store:null,products:[],category:"Todos",collection:"",query:"",sort:"featured",cart:read()};const $=(s,r=document)=>r.querySelector(s),$$=(s,r=document)=>[...r.querySelectorAll(s)];const e={grid:$("#productGrid"),tpl:$("#productTemplate"),chips:$("#filterChips"),sort:$("#sortSelect"),summary:$("#catalogSummary"),empty:$("#emptyState"),reset:$("#resetButton"),searchOpen:$("#searchOpen"),searchPanel:$("#searchPanel"),searchInput:$("#searchInput"),searchClose:$("#searchClose"),cartBtn:$("#cartButton"),drawer:$("#cartDrawer"),cartClose:$("#cartClose"),cartItems:$("#cartItems"),cartCount:$("#cartCount"),checkout:$("#checkoutButton"),clear:$("#clearCart"),overlay:$("#overlay"),dialog:$("#productDialog"),dialogClose:$("#dialogClose"),dialogContent:$("#dialogContent"),toast:$("#toastRegion"),availability:$("#availabilityLink")};function read(){try{return JSON.parse(localStorage.getItem(KEY))||{}}catch{return{}}}function save(){localStorage.setItem(KEY,JSON.stringify(state.cart))}function norm(v){return String(v||"").toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").trim()}function esc(v){return String(v??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}async function load(){try{state.store=await(await fetch("data/store.json",{cache:"no-store"})).json();state.products=(await(await fetch(state.store.catalogUrl,{cache:"no-store"})).json()).products||[];e.availability.href=state.store.whatsappUrl;renderFilters();renderAll()}catch(err){console.error(err);e.summary.textContent="No se pudo cargar el catálogo.";e.empty.hidden=false}}function cats(){return["Todos",...new Set(state.products.map(p=>p.category))]}function renderFilters(){e.chips.innerHTML=cats().map(c=>`<button class="filter-chip ${state.category===c&&!state.collection?"active":""}" type="button" data-filter-category="${esc(c)}">${esc(c)}</button>`).join("")}function filtered(){const q=norm(state.query);return state.products.filter(p=>{if(state.category!=="Todos"&&p.category!==state.category)return false;if(state.collection&&p.collection!==state.collection)return false;if(!q)return true;return norm([p.name,p.category,p.collection,p.description,p.dimensions].join(" ")).includes(q)}).sort((a,b)=>state.sort==="name"?a.name.localeCompare(b.name,"es"):state.sort==="newest"?Number(!!b.new)-Number(!!a.new):Number(!!b.featured)-Number(!!a.featured)||Number(!!b.new)-Number(!!a.new)||a.name.localeCompare(b.name,"es"))}function renderProducts(){const list=filtered();e.grid.innerHTML="";e.empty.hidden=!!list.length;e.summary.textContent=`${list.length} producto${list.length===1?"":"s"} reales de Ari Shopping`;list.forEach(p=>{const f=e.tpl.content.cloneNode(true),card=$(".product-card",f);card.dataset.productId=p.id;const img=$("img",f);img.src=p.images[0];img.alt=p.name;$(".product-category",f).textContent=p.category;$(".product-collection",f).textContent=p.collection;$(".product-name",f).textContent=p.name;$(".product-description",f).textContent=p.description;$$(".product-open",f).forEach(b=>b.addEventListener("click",()=>openProduct(p.id)));$(".add-button",f).addEventListener("click",()=>add(p.id));e.grid.appendChild(f)})}function byId(id){return state.products.find(p=>p.id===id)}function add(id){const p=byId(id);if(!p)return;state.cart[id]=Number(state.cart[id]||0)+1;save();renderCart();toast(`${p.name} agregado al pedido.`)}function update(id,q){if(q<=0)delete state.cart[id];else state.cart[id]=q;save();renderCart()}function entries(){return Object.entries(state.cart).map(([id,q])=>({product:byId(id),quantity:Number(q)})).filter(x=>x.product&&x.quantity>0)}function renderCart(){const list=entries();e.cartCount.textContent=String(list.reduce((s,x)=>s+x.quantity,0));if(!list.length){e.cartItems.innerHTML='<div class="cart-empty"><strong>Tu selección está vacía</strong><p>Agrega productos para preparar el pedido.</p></div>';e.checkout.disabled=true;return}e.checkout.disabled=false;e.cartItems.innerHTML=list.map(({product:p,quantity:q})=>`<article class="cart-line" data-product-id="${esc(p.id)}"><img src="${esc(p.images[0])}" alt=""><div><strong>${esc(p.name)}</strong><small>${esc(p.collection)} · Consultar precio</small><div class="qty"><button type="button" data-change="-1"></button><span>${q}</span><button type="button" data-change="1">+</button></div></div><button type="button" data-remove>×</button></article>`).join("");$$("[data-change]",e.cartItems).forEach(b=>b.addEventListener("click",()=>{const id=b.closest("[data-product-id]").dataset.productId;update(id,Number(state.cart[id])+Number(b.dataset.change))}));$$("[data-remove]",e.cartItems).forEach(b=>b.addEventListener("click",()=>update(b.closest("[data-product-id]").dataset.productId,0)))}function orderText(list){return["Hola Ari Shopping 👋","Quiero consultar disponibilidad para:","",...list.map(({product:p,quantity:q})=>`• ${q} x ${p.name}`),"","Nombre:","Ciudad:","Forma de entrega:"].join("\n")}async function checkout(){const list=entries();if(!list.length)return;try{await navigator.clipboard.writeText(orderText(list));toast("Pedido copiado. Se abrirá WhatsApp.")}catch{toast("Se abrirá WhatsApp para continuar.")}window.open(state.store.whatsappUrl,"_blank","noopener")}function openProduct(id){const p=byId(id);if(!p)return;e.dialogContent.innerHTML=`<div class="dialog-layout"><img src="${esc(p.images[0])}" alt="${esc(p.name)}"><div class="dialog-copy"><span class="eyebrow">${esc(p.category)} · ${esc(p.collection)}</span><h2>${esc(p.name)}</h2><p>${esc(p.description)}</p><div class="detail-list"><span><strong>Precio</strong> Consultar disponibilidad</span><span><strong>Entrega</strong> Coordinar con Ari Shopping</span>${p.dimensions?`<span><strong>Medidas</strong> ${esc(p.dimensions)}</span>`:""}</div><div class="dialog-actions"><button class="button primary" type="button" data-dialog-add>Agregar al pedido</button><a class="button text" href="${esc(state.store.whatsappUrl)}" target="_blank" rel="noopener">Consultar por WhatsApp</a></div></div></div>`;$("[data-dialog-add]",e.dialogContent).addEventListener("click",()=>{add(id);e.dialog.close();openCart()});e.dialog.showModal()}function filter(category="Todos",collection=""){state.category=category;state.collection=collection;renderFilters();renderProducts();$("#productos").scrollIntoView({behavior:"smooth"})}function reset(){state.category="Todos";state.collection="";state.query="";e.searchInput.value="";renderFilters();renderProducts()}function openCart(){e.drawer.classList.add("open");e.drawer.setAttribute("aria-hidden","false");e.overlay.hidden=false;document.body.classList.add("locked")}function closeCart(){e.drawer.classList.remove("open");e.drawer.setAttribute("aria-hidden","true");e.overlay.hidden=true;document.body.classList.remove("locked")}function toast(m){const n=document.createElement("div");n.className="toast";n.textContent=m;e.toast.appendChild(n);setTimeout(()=>n.remove(),3200)}function renderAll(){renderProducts();renderCart()}e.chips.addEventListener("click",ev=>{const b=ev.target.closest("[data-filter-category]");if(b)filter(b.dataset.filterCategory)});$$("[data-category]").forEach(b=>b.addEventListener("click",()=>filter(b.dataset.category)));$$("[data-collection]").forEach(b=>b.addEventListener("click",()=>filter("Todos",b.dataset.collection)));$$("[data-nav-category]").forEach(b=>b.addEventListener("click",()=>filter(b.dataset.navCategory)));$$("[data-nav-collection]").forEach(b=>b.addEventListener("click",()=>filter("Todos",b.dataset.navCollection)));e.sort.addEventListener("change",ev=>{state.sort=ev.target.value;renderProducts()});e.reset.addEventListener("click",reset);e.searchOpen.addEventListener("click",()=>{e.searchPanel.hidden=false;e.searchInput.focus()});e.searchClose.addEventListener("click",()=>e.searchPanel.hidden=true);e.searchInput.addEventListener("input",ev=>{state.query=ev.target.value;renderProducts()});e.cartBtn.addEventListener("click",openCart);e.cartClose.addEventListener("click",closeCart);e.overlay.addEventListener("click",closeCart);e.checkout.addEventListener("click",checkout);e.clear.addEventListener("click",()=>{state.cart={};save();renderCart()});e.dialogClose.addEventListener("click",()=>e.dialog.close());document.addEventListener("keydown",ev=>{if(ev.key==="Escape")closeCart()});load()})();