Carrinho de compras
Seu carrinho está vazio

Atendimento

Frete Grátis

Compras Acima de 1200

Pague com Pix e Ganhe

10% de Desconto

Pague com cartão

em até 12x s/ juros

Tire suas dúvidas

por Whatsapp

Como comprar

Para comprar em nossa loja é muito fácil:

1) Basta navegar entre as diversas páginas de produtos ( categorias, novidades, ofertas, destaques) e clicar sobre o icone Comprar. Ou clique em Ver Detalhes para maiores informações sobre o produto. Após isso o produto será inserido em seu carrinho de compras

2) Continue navegando em nosso site até escolher todos os produtos que você deseja adquirir. Agora basta clicar no link a direita Finalizar que você estará concluindo sua compra.

3) Agora entre com o seu email e senha. Caso não for cadastrado, cadastre-se rapidamente clicando no link de Cadastro.

4) Feito isso, escolha a forma de envio do produto. Trabalhamos com envio via Correio. Você pode optar por sedex ou encomenda simples, sendo que o sedex é mais caro só que muito mais ágil logo, recomendamos escolher J&T Express.

5) Agora basta escolher a forma de pagamento.

6) Demais instruções serão enviadas via email para você após a finalização de sua venda.

';anchor.parentNode.insertBefore(bar,anchor);} var pct=Math.min(100,Math.round(val/FREE_SHIP*100)),rem=Math.max(0,FREE_SHIP-val); var html=(rem<=0)?(String.fromCodePoint(0x1F389)+' Você ganhou frete grátis!'):('Faltam '+brl(rem)+' para o frete grátis '+String.fromCodePoint(0x1F69A)); var key=html+'|'+pct+'|on'; if(bar.getAttribute('data-st')===key)return; /* nada mudou: não reescreve (evita re-disparar o observer) */ bar.setAttribute('data-st',key); bar.style.display=''; bar.classList.toggle('is-free',rem<=0); bar.querySelector('.ab-freeship__msg').innerHTML=html; bar.querySelector('.ab-freeship__fill').style.width=pct+'%'; } if(window.__abCart)return; window.__abCart=true; /* Frete grátis: acha a linha grátis na tabela de estimativa, realça, vira badge e move pro TOPO (a mais barata é grátis mas some no meio -> pessoa não vê). */ /* IMPORTANTE: regex 100% ASCII. O inline script e servido em iso-8859-1 e acentos viram mojibake (o [aa] com acento quebrava). "gr.tis" casa "gratis"/"gratis-com-acento" pois o "." casa o caractere do meio. */ function highlightFreeShipping(){ var tables=document.querySelectorAll('.shipping-rates-table'); var reFree=/gr.tis/i; for(var i=0;i✓ $1'); } } } } if(free && firstData && free!==firstData){ tbody.insertBefore(free, firstData); } /* Clarity: captura CEP (prefixo 5) + prazo do frete gratis, 1x por calculo, pra entender se prazo longo e distancia (CEP) ou transportadora lenta. */ if(window.clarity && free && !tables[i].__abTracked){ tables[i].__abTracked=true; try{ var cepEl=document.querySelector('#zip'); var cepv=cepEl?String(cepEl.value||'').replace(/\D/g,''):''; if(cepv.length>=8) window.clarity('set','frete_cep', cepv.slice(0,5)+'-'+cepv.slice(5,8)); var dm=(free.textContent||'').match(/(\d{2})\/(\d{2})\/(\d{4})/g); if(dm && dm.length){ var pp=dm[dm.length-1].split('/'); var days=Math.round((new Date(+pp[2],+pp[1]-1,+pp[0]) - new Date())/86400000); window.clarity('set','frete_prazo_dias', String(days)); window.clarity('set','frete_prazo', days<=3?'1-3 dias':days<=7?'4-7 dias':days<=14?'8-14 dias':'15+ dias'); } }catch(_){} } } } function run(){ /* realce do frete grátis na tabela de estimativa (produto) */ try{ highlightFreeShipping(); }catch(e){} /* nome do produto abreviado + "ler mais" no modal do carrinho */ try{ abTruncateNames(); }catch(e){} /* precos do order bump com centavos (BRL) */ try{ abFixRecPrices(); }catch(e){} /* "Finalizar compra" + "Limpar carrinho" no modal */ try{ abEnhanceCartModal(); }catch(e){} /* Pix (a vista) no item e no total do carrinho */ try{ abCartPix(); }catch(e){} /* mesmo Pix no carrinho lateral (sidebar) */ try{ abSidebarPix(); }catch(e){} /* carrinho vazio: renomeia "Fechar carrinho" -> "Continuar comprando" (o texto vem do JS nativo do tema; so trocamos o texto, o handler de fechar continua o mesmo) */ try{ var rc=document.querySelector('.plugoo-cart-preview-sidebar .pg-return-nocart'); if(rc && /fechar/i.test(rc.textContent||'')) rc.textContent='Continuar comprando'; }catch(e){} /* acessibilidade: cards de noticia (blog) sao injetados por JS e o link da imagem (#noticia_imagem a) fica sem texto/alt -> leitor de tela nao entende. Aplicamos o titulo da noticia como aria-label do link + alt da imagem. Puramente aditivo. */ try{ abFixNewsA11y(); }catch(e){} /* modal nativo (popup de adicionar) */ var body=document.querySelector('.cart-preview-body'); if(body){ wire(body); update(body); var modal=(body.closest&&body.closest('.modal-content'))||body.parentElement; var msub=modal&&modal.querySelector('.cart-preview-subtotal'); if(msub) applyBar(modal, msub.textContent, body); } /* sidebar do tema (ícone do carrinho) */ var sb=document.querySelector('.plugoo-cart-preview-sidebar'); if(sb){ var sval=sb.querySelector('.cart-preview-footer .total .value'), content=sb.querySelector('.cart-preview-content'); if(sval&&content) applyBar(sb, sval.textContent, content); } } /* Acessibilidade dos cards de noticia do blog (injetados por JS): o link da imagem (#noticia_imagem a) envolve so a imagem, sem texto -> "link sem nome". Pegamos o titulo da noticia no card e usamos como aria-label do link + alt da imagem. So adiciona atributo quando falta; nunca sobrescreve nem remove nada. */ function abFixNewsA11y(){ var boxes=document.querySelectorAll('.box-noticia'); for(var i=0;i apos clicar comprar, re-buscamos e reinjetamos no modal. Tudo ASCII (mojibake). */ function refreshCartModalWithGifts(tries){ tries=tries||1; var cur=document.querySelector('.cart-preview-body'); if(!cur || /brinde/i.test(cur.textContent||'')) return; /* sem modal ou ja tem brinde */ var url=(typeof window.mountCartUrl==='function')?window.mountCartUrl():'/mvc/store/element/snippets/cart_preview/'; fetch(url,{headers:{'X-Requested-With':'XMLHttpRequest'}}).then(function(r){return r.arrayBuffer();}).then(function(buf){ var html; try{ html=new TextDecoder('iso-8859-1').decode(buf); }catch(_){ html=new TextDecoder().decode(buf); } var fresh=new DOMParser().parseFromString(html,'text/html').querySelector('.cart-preview-body'); var c=document.querySelector('.cart-preview-body'); if(!fresh||!c) return; if(/brinde/i.test(fresh.textContent||'')){ if(!/brinde/i.test(c.textContent||'')) c.innerHTML=fresh.innerHTML; } else if(tries<3){ setTimeout(function(){ refreshCartModalWithGifts(tries+1); }, 800); } }).catch(function(){}); } document.addEventListener('click', function(e){ var b=e.target && e.target.closest && e.target.closest('#button-buy, .botao-comprar'); if(b){ [700,1500,2600].forEach(function(ms){ setTimeout(function(){ try{refreshCartModalWithGifts(1);}catch(_){} }, ms); }); } }, true); /* Abre o MODAL NATIVO da Tray (.modal.cart-preview) com o order bump "Recomendamos para voce" -- o mesmo que aparece na pagina do produto. Passos: (1) re-busca o partial do carrinho (mountCartUrl) que ja traz item novo + brinde + order bump + recomendacoes, e reinjeta o MODAL INTEIRO (o order bump fica FORA do .cart-preview-body, entao trocar so o body nao bastava); (2) abre via Bootstrap modal('show'). Fallback: showCart (sidebar). Os handlers de remover ([data-cart-preview-del]) e checkout sao delegados no document -> sobrevivem a troca de innerHTML. Ja os forms do order bump (.related-product-buy-form) tem submit ligado DIRETO -> quebram; por isso ha um interceptor de submit mais abaixo que manda pro data-fallback (pagina do produto). Tudo ASCII por causa do mojibake iso-8859-1. */ function abOpenNativeCartModal(tries){ tries=tries||1; var showIt=function(){ try{ var lb=document.querySelector('.ab-buy-black.loading'); if(lb) lb.classList.remove('loading'); }catch(_){} try{ abTruncateNames(); }catch(_){} try{ abFixRecPrices(); }catch(_){} try{ abEnhanceCartModal(); }catch(_){} try{ abCartPix(); }catch(_){} try{ if(window.jQuery && jQuery.fn && jQuery.fn.modal){ jQuery('.modal.cart-preview').modal('show'); return; } }catch(_){} try{ if(window.cart && cart.showCart){ cart.showCart(); } }catch(_){} }; /* mountCartUrl e definido por um script nativo que as vezes ainda nao carregou no clique (fica undefined) -> por isso usamos o path fixo do partial como fallback (a sessao vai pelo cookie, nao pela URL). */ var url=(typeof window.mountCartUrl==='function')?window.mountCartUrl():'/mvc/store/element/snippets/cart_preview/'; fetch(url,{headers:{'X-Requested-With':'XMLHttpRequest'}}).then(function(r){return r.arrayBuffer();}).then(function(buf){ var html; try{ html=new TextDecoder('iso-8859-1').decode(buf); }catch(_){ html=new TextDecoder().decode(buf); } var fresh=new DOMParser().parseFromString(html,'text/html').querySelector('.modal.cart-preview'); /* se o add ainda nao propagou (partial vazio), re-tenta antes de mostrar */ if(fresh){ var freshEmpty = /vazio/i.test(fresh.textContent||'') || fresh.querySelectorAll('.cart-preview-item').length===0; if(freshEmpty && tries<=6){ setTimeout(function(){ abOpenNativeCartModal(tries+1); }, 300); return; } } var live=document.querySelector('.modal.cart-preview'); if(fresh && live){ live.innerHTML=fresh.innerHTML; } showIt(); }).catch(function(){ showIt(); }); } /* Order bump reinjetado: o submit nativo do .related-product-buy-form fica ligado direto no form, entao ao trocar o innerHTML ele quebra e faria um POST bruto (pagina de erro). Interceptamos aqui (delegado no document -> sobrevive): - SEM variacao obrigatoria (data-required-variant vazio) -> adiciona DIRETO no carrinho via /web_api/cart e recarrega o modal (nao sai da pagina); - COM variacao (data-required-variant="1") -> vai pro data-fallback (pagina do produto), pois nao da pra adivinhar qual variacao adicionar. */ document.addEventListener('submit', function(e){ var f=e.target && e.target.closest && e.target.closest('.modal.cart-preview .related-product-buy-form'); if(!f) return; e.preventDefault(); if(f.getAttribute('data-busy')) return; var reqVar=f.getAttribute('data-required-variant'); var fallback=f.getAttribute('data-fallback'); if(reqVar==='1'){ if(fallback) window.location.href=fallback; return; } var pidEl=f.querySelector('input[name="product_id"]'); var pid=pidEl?pidEl.value:''; if(!pid){ if(fallback) window.location.href=fallback; return; } var qtyEl=f.querySelector('input[name="quant"], input[name="quantity"]'); var qty=(qtyEl && qtyEl.value)?qtyEl.value:'1'; var session=document.querySelector('html').getAttribute('data-session'); f.setAttribute('data-busy','1'); setTimeout(function(){ f.removeAttribute('data-busy'); }, 2500); var buyBtn=f.querySelector('.buy-link, button[type="submit"]'); if(buyBtn) buyBtn.classList.add('loading'); fetch('/web_api/cart/',{method:'POST',headers:{'Content-Type':'application/json; charset=utf-8'},body:JSON.stringify({Cart:{session_id:session,product_id:pid,quantity:qty}})}) .then(function(r){ return r.json(); }) .then(function(){ abOpenNativeCartModal(); }) .catch(function(){ if(buyBtn) buyBtn.classList.remove('loading'); if(fallback) window.location.href=fallback; }); }, true); /* Setas do order bump reinjetado: sem slick, as setas nativas (.related-product-custom-*) ficam mortas. Ligamos aqui (rola o trilho em 1 "pagina" = clientWidth). So atua quando o slick nao inicializou -> na pagina do produto o slick nativo cuida das setas. */ document.addEventListener('click', function(e){ var pv=e.target.closest && e.target.closest('.modal.cart-preview .related-products-wrapper:not(.slick-initialized) .related-product-custom-prev'); var nx=e.target.closest && e.target.closest('.modal.cart-preview .related-products-wrapper:not(.slick-initialized) .related-product-custom-next'); if(!pv && !nx) return; e.preventDefault(); var wrap=(pv||nx).closest('.related-products-wrapper'); var track=wrap && wrap.querySelector('.related-product-slide-content'); if(!track) return; var step=track.clientWidth || 300; var max=track.scrollWidth - track.clientWidth; var target=track.scrollLeft + (nx ? step : -step); target=Math.max(0, Math.min(target, max)); /* smooth nao funciona neste elemento (snap); animamos manualmente via rAF */ var start=track.scrollLeft, dist=target-start, t0=null, dur=280; function anim(ts){ if(!t0) t0=ts; var p=Math.min((ts-t0)/dur,1); track.scrollLeft=start+dist*(0.5-Math.cos(p*Math.PI)/2); if(p<1) requestAnimationFrame(anim); } requestAnimationFrame(anim); }, true); /* Nome do produto no carrinho: os nomes sao longos (6+ linhas). Trunca em 30 chars por padrao e injeta um "ler mais"/"ler menos". Usa … (…) em ASCII pra evitar mojibake iso-8859-1. Roda no modal nativo (produto e vitrine) -> igual nos dois. */ var AB_NAME_LIMIT=25; var AB_TRASH_SVG=''; function abTruncateNames(){ var items=document.querySelectorAll('.modal.cart-preview .cart-preview-item'); for(var i=0;iAB_NAME_LIMIT){ el.setAttribute('data-full', full); el.textContent=full.slice(0,AB_NAME_LIMIT).trim()+'\u2026'; var btn=document.createElement('span'); btn.className='ab-ler-mais'; btn.textContent='ler mais'; btn.setAttribute('data-exp','0'); /* logo depois do nome -> "nome… ler mais" na 1a linha; a cor (small block) cai na linha de baixo naturalmente */ el.insertAdjacentElement('afterend', btn); } } var del=item.querySelector('.cart-preview-item-delete'); if(del && !del.__abTrash){ del.__abTrash=1; del.classList.add('ab-trash'); del.setAttribute('title','Remover'); del.innerHTML=AB_TRASH_SVG; } } } /* Precos do order bump ("Recomendamos") vem crus do partial: principal em [data-reference^="price-"] (ex "219") e original em .related-product-original-price span (ex "299.99") -- sem centavos e com ponto. Reformata pra BRL (219,00 / 299,99). */ function abFixRecPrices(){ var modal=document.querySelector('.modal.cart-preview'); if(!modal) return; var sps=modal.querySelectorAll('.related-product-principal-price [data-reference^="price-"], .related-product-principal-price span, .related-product-original-price span'); for(var i=0;i ignora */ sp.__abPrice=1; var n=parseFloat(raw); if(isNaN(n)) continue; sp.textContent=n.toLocaleString('pt-BR',{minimumFractionDigits:2,maximumFractionDigits:2}); } } /* Modal do carrinho: (1) "Avancar" -> "Finalizar compra" (consistente com o carrinho lateral); (2) injeta "Limpar carrinho" no fim do rodape (igual o lateral tem). */ function abEnhanceCartModal(){ var modal=document.querySelector('.modal.cart-preview'); if(!modal) return; var av=modal.querySelector('.botao-prosseguir-compra .botao-commerce-img'); if(av && /avan/i.test(av.textContent||'')) av.textContent='Finalizar compra'; /* "Limpar carrinho" a esquerda do Subtotal (o CSS poe a linha em flex) */ var subt=modal.querySelector('.cart-preview-subtotal'); if(subt && !subt.querySelector('.ab-limpar-modal')){ var btn=document.createElement('button'); btn.type='button'; btn.className='ab-limpar-modal'; btn.textContent='Limpar carrinho'; subt.insertBefore(btn, subt.firstChild); } /* order bump: itens COM variacao (data-required-variant=1) nao podem ser adicionados direto (nao da pra saber a cor), entao o botao vai pra pagina do produto -> deixamos o texto "Escolher cor" (igual a vitrine), mais claro que "Adicionar"/"Comprar". */ modal.querySelectorAll('.related-product-buy-form[data-required-variant="1"] .buy-link, .related-product-buy-form[data-required-variant="1"] button[type="submit"]').forEach(function(bb){ if(bb.__abRelabel) return; bb.__abRelabel=1; var t=(bb.textContent||'').trim(); if(t && !/escolher/i.test(t)) bb.textContent='Escolher cor'; }); } /* Order bump / carrinho: mostra o PIX (a vista) igual as telas de produto. O modal so tem o preco cheio -> calculamos o Pix = cheio * (1 - %/100), usando o % da loja guardado em window.__abPixPct (setado pelo JS de preco). Aditivo (nunca reescreve o nativo). Guardas __abPixItem/__abPixTotal evitam duplicar. Tudo ASCII (mojibake iso-8859-1). */ function abCartPix(){ var modal=document.querySelector('.modal.cart-preview'); if(!modal) return; var pct=window.__abPixPct; if(pct==null) return; /* sem % -> nao injeta (gracioso) */ function money(t){ if(!t) return 0; var m=String(t).replace(/[^0-9.,]/g,'').replace(/\./g,'').replace(',','.'); var n=parseFloat(m); return isNaN(n)?0:n; } function fmt(n){ return n.toLocaleString('pt-BR',{minimumFractionDigits:2,maximumFractionDigits:2}); } function brl(n){ return 'R$ '+fmt(n); } /* troca SO o numero (ultimo text node com digitos) dentro do elemento, preservando "R$"/"Subtotal" */ function setNum(el, txt){ var w=document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null), last=null, nd; while(nd=w.nextNode()){ if(/\d/.test(nd.nodeValue)) last=nd; } if(last) last.nodeValue=' '+txt; } /* troca o valor formatado oldN por newN no primeiro text node que o contem (preserva "cada)") */ function replaceMoney(el, oldN, newN){ var of=fmt(oldN), nf=fmt(newN), w=document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null), nd; while(nd=w.nextNode()){ if(nd.nodeValue.indexOf(of)>-1){ nd.nodeValue=nd.nodeValue.replace(of, nf); return; } } } /* por item: preco (total da linha) vira o PIX; o "(R$ X cada)" vira o unitario PIX. Brinde (0) pulado. */ var items=modal.querySelectorAll('.cart-preview-item'); for(var i=0;i pula */ it.__abPixItem=1; var cadaEl=pbox.querySelector('small'); /* "(R$ 1.599,00 cada)" -> unitario */ if(cadaEl){ var uf=money(cadaEl.textContent); if(uf>0) replaceMoney(cadaEl, uf, uf*(1-pct/100)); } setNum(bItem, fmt(full*(1-pct/100))); var lab=document.createElement('div'); lab.className='ab-item-pix'; lab.textContent='\u00c0 vista no Pix'; pbox.appendChild(lab); /* dentro da coluna do preco -> fica ABAIXO do valor */ } /* subtotal: valor vira o PIX; label "A vista no PIX" (sem valor) + "ou a prazo R$Y em ate Nx sem juros de R$Z" */ var subt=modal.querySelector('.cart-preview-subtotal'); if(subt && !subt.__abPixTotal){ var bSub=subt.querySelector('b'); var stFull=bSub?money(bSub.textContent):0; if(bSub && stFull>0){ subt.__abPixTotal=1; setNum(bSub, fmt(stFull*(1-pct/100))); var nmax=window.__abMaxParc||0; var box=document.createElement('div'); box.className='ab-cart-pix-total'; var html='
\u00c0 vista no Pix
'; html+='
ou \u00e0 prazo '+brl(stFull)+''; if(nmax>1){ html+=' em at\u00e9 '+nmax+'x sem juros de '+brl(stFull/nmax)+''; } html+='
'; box.innerHTML=html; subt.insertAdjacentElement('afterend', box); } } } /* Mesma coisa no CARRINHO SIDEBAR (.plugoo-cart-preview-sidebar) — classes diferentes do modal: item = div.price (folha "R$ X"); total = .cart-preview-footer .total .value. Reusa .ab-item-pix / .ab-cart-pix-total (mesma fonte/estilo do order bump). ASCII. */ function abSidebarPix(){ var sb=document.querySelector('.plugoo-cart-preview-sidebar'); if(!sb) return; var pct=window.__abPixPct; if(pct==null) return; function money(t){ if(!t) return 0; var m=String(t).replace(/[^0-9.,]/g,'').replace(/\./g,'').replace(',','.'); var n=parseFloat(m); return isNaN(n)?0:n; } function fmt(n){ return n.toLocaleString('pt-BR',{minimumFractionDigits:2,maximumFractionDigits:2}); } function brl(n){ return 'R$ '+fmt(n); } /* helper RE-APLICAVEL: poe o Pix num campo "R$X" (folha). Guarda cheio/pix em data-attrs. Se a Tray resetar o texto (re-render do sidebar), recalcula do valor nativo; senao mantem. Assim nao e sobrescrito. */ function pixField(el){ if(!el) return 0; var cur=money(el.textContent); var lp=el.getAttribute('data-abpix'); lp=(lp!=null&&lp!=='')?parseFloat(lp):null; var full=(lp!=null && Math.abs(cur-lp)<0.01) ? parseFloat(el.getAttribute('data-abfull')) : cur; if(!(full>0)) return 0; var pixv=full*(1-pct/100); el.setAttribute('data-abfull', full); el.setAttribute('data-abpix', pixv); var txt=brl(pixv); if((el.textContent||'').replace(/\s+/g,' ').trim()!==txt) el.textContent=txt; return full; } /* itens: qty>1 -> preco mostra o TOTAL da linha (Pix) + "(R$ unit cada)"; qty==1 -> unit Pix. Tracking (data-abunit/abshown) p/ nao ser sobrescrito pelo re-render da Tray. Brinde (0) pulado. */ var items=sb.querySelectorAll('.cart-preview-item'); for(var i=0;i0)) continue; /* brinde/gratis */ var unitPix=unit*(1-pct/100); var shown=qty>1?unitPix*qty:unitPix; pe.setAttribute('data-abunit', unit); pe.setAttribute('data-abshown', shown); var stxt=brl(shown); if((pe.textContent||'').replace(/\s+/g,' ').trim()!==stxt) pe.textContent=stxt; var cada=it.querySelector('.ab-cada'); if(qty>1){ var ctxt='('+brl(unitPix)+' cada)'; if(!cada){ cada=document.createElement('span'); cada.className='ab-cada'; pe.insertAdjacentElement('afterend', cada); } if(cada.textContent!==ctxt) cada.textContent=ctxt; } else if(cada && cada.parentNode){ cada.parentNode.removeChild(cada); } if(!it.querySelector('.ab-item-pix')){ var lab=document.createElement('div'); lab.className='ab-item-pix'; lab.textContent='\u00c0 vista no Pix'; (cada||pe).insertAdjacentElement('afterend', lab); } } /* total: valor vira Pix + "A vista no Pix" + "ou a prazo R$Y em ate Nx sem juros de R$Z" */ var tot=sb.querySelector('.cart-preview-footer .total'); if(tot){ var full=pixField(tot.querySelector('.value')); if(full>0){ var nmax=window.__abMaxParc||0; var box=tot.parentElement.querySelector('.ab-cart-pix-total'); if(!box){ box=document.createElement('div'); box.className='ab-cart-pix-total'; tot.insertAdjacentElement('afterend', box); } var html='
\u00c0 vista no Pix
'; html+='
ou \u00e0 prazo '+brl(full)+''; if(nmax>1){ html+=' em at\u00e9 '+nmax+'x sem juros de '+brl(full/nmax)+''; } html+='
'; if(box.getAttribute('data-st')!==html){ box.innerHTML=html; box.setAttribute('data-st',html); } } } } /* Limpar carrinho (modal): usa o clearProduct nativo e fecha o modal (o clearProduct atualiza o lateral, nao o modal -> fechamos pra nao ficar conteudo velho). */ document.addEventListener('click', function(e){ var t=e.target && e.target.closest && e.target.closest('.ab-limpar-modal'); if(!t) return; e.preventDefault(); try{ if(window.cart && cart.clearProduct) cart.clearProduct(); }catch(_){} try{ if(window.jQuery && jQuery.fn && jQuery.fn.modal) jQuery('.modal.cart-preview').modal('hide'); }catch(_){} }, true); document.addEventListener('click', function(e){ var t=e.target && e.target.closest && e.target.closest('.ab-ler-mais'); if(!t) return; e.preventDefault(); e.stopPropagation(); var box=t.closest('.cart-preview-item-name-box')||t.parentElement; var el=box && box.querySelector('.cart-preview-item-name'); if(!el) return; var full=el.getAttribute('data-full')||''; if(t.getAttribute('data-exp')==='1'){ el.textContent=full.slice(0,AB_NAME_LIMIT).trim()+'\u2026'; t.textContent='ler mais'; t.setAttribute('data-exp','0'); } else { el.textContent=full; t.textContent='ler menos'; t.setAttribute('data-exp','1'); } }, true); /* Vitrine: "Comprar (Preta)" no produto SOLO com variacao -> adiciona a variante preta via /web_api/cart (o quick-buy nativo nao passa variacao) e abre o carrinho. variant_id vem do data-variant (a preta = reference == SKU do produto). Tudo ASCII. */ document.addEventListener('click', function(e){ var b = e.target && e.target.closest && e.target.closest('.ab-buy-black'); if(!b) return; e.preventDefault(); if(b.getAttribute('data-busy')) return; b.setAttribute('data-busy','1'); setTimeout(function(){ b.removeAttribute('data-busy'); }, 2500); /* feedback igual ao botao nativo do kit: classe 'loading' esconde o texto e mostra o spinner (.botao.loading::after). Removida quando o modal abre (dentro do showIt). */ b.classList.add('loading'); var pid=b.getAttribute('data-product'), vid=b.getAttribute('data-variant'); var box=b.closest('.actions')||b.closest('.flex')||b.parentElement; var qtyEl=box?box.querySelector('input[name="qty"]'):null; var qty=(qtyEl && qtyEl.value)?qtyEl.value:'1'; var session=document.querySelector('html').getAttribute('data-session'); fetch('/web_api/cart/',{method:'POST',headers:{'Content-Type':'application/json; charset=utf-8'},body:JSON.stringify({Cart:{session_id:session,product_id:pid,quantity:qty,variant_id:vid}})}) /* Guarda o STATUS HTTP junto do corpo. ⚠️ ARMADILHA: no SUCESSO a Tray devolve 201 {message:'Created', id, code:201}. O `code` no sucesso é 201 (nao é erro!) — por isso NAO da pra usar `j.code` como sinal de erro (dava falso "Indisponivel" mesmo adicionando). Sinal de erro correto = HTTP >=400 OU corpo com Bad Request/causes. Erro de estoque = HTTP 400 {code:400,name:'Bad Request',causes:[...]}. */ .then(function(r){ return r.json().then(function(j){ return {ok:r.ok, status:r.status, j:j}; }, function(){ return {ok:r.ok, status:r.status, j:null}; }); }) .then(function(res){ var j = res.j || {}; var failed = !res.ok || j.name === 'Bad Request' || (j.causes && j.causes.length); if(failed){ b.classList.remove('loading'); var cz = (j.causes && j.causes.join ? j.causes.join(' ') : '') || ''; var esgot = /estoque|esgot|indispon/i.test(cz); b.textContent = esgot ? 'Preta esgotada' : 'Indisponivel'; b.style.opacity = '.55'; b.style.pointerEvents = 'none'; /* volta ao normal depois de alguns segundos (cliente pode usar "Escolher cor" ao lado) */ setTimeout(function(){ b.textContent = 'Comprar (Preta)'; b.style.opacity = ''; b.style.pointerEvents = ''; }, 4000); return; } b.textContent='Adicionado'; b.classList.add('ab-added'); abOpenNativeCartModal(); }) .catch(function(){ b.classList.remove('loading'); }); }, true); /* Vitrine: abrir o carrinho tambem no fastBuy (Comprar / Comprar (Preta) do kit), pra ficar consistente com o botao do solo. Delay pequeno pro add completar. Mira so os forms de compra-rapida da vitrine (nao o #button-buy da pagina do produto). */ document.addEventListener('click', function(e){ var f=e.target && e.target.closest && e.target.closest('form.add-to-cart[data-app="product.buy-button"]'); if(!f) return; setTimeout(abOpenNativeCartModal, 1600); }, true); /* Carrinho sidebar: "Continuar comprando" fecha o carrinho e volta a comprar. Tenta store.continueShopping(); fallback: clica a seta de voltar ou o overlay. */ document.addEventListener('click', function(e){ var b=e.target && e.target.closest && e.target.closest('.ab-continuar-comprando'); if(!b) return; e.preventDefault(); try{ if(window.store && typeof store.continueShopping==='function'){ store.continueShopping(); return; } }catch(_){} var back=document.querySelector('.plugoo-cart-preview-sidebar .pg-return-cart'); if(back){ back.click(); return; } var shadow=document.querySelector('.shadow-cart'); if(shadow){ shadow.click(); } }, true); if(document.body){boot();}else{document.addEventListener('DOMContentLoaded',boot);} })();