Files
dtf-system/web/site-cart.js
Cauê Faleiros b6a90411f1
All checks were successful
Build and deploy / Validate source (push) Successful in 5s
Build and deploy / Integration suite on a real stack (push) Successful in 2m2s
Build and deploy / Secret scan and release gate (push) Successful in 4s
Build and deploy / Publish images (push) Successful in 1m33s
feat: let customers remove items and empty the cart, with undo
Each cart item has a visible "Remover" button instead of a faint ×, and
carts with two or more items get "Esvaziar carrinho". Both show a
"Desfazer" notice for 8 seconds, so a wrong click costs nothing. The
browser test covers remove and undo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 18:18:10 -03:00

142 lines
6.9 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.
/* Site DTF — Cart totals and the order summary.
Extracted verbatim from the single inline script in web/index.html.
Loaded as classic scripts in the order listed there: they share one global
scope and run top to bottom, exactly as the original did. */
// ── carrinho
let itemAtual=null;
function invalidaItemAtual(){
if(!itemAtual) return;
itemAtual=null;
$('atual').style.display='none';
$('carrLin').innerHTML='';
pintaPedido();
}
function itemPodeEnviar(item){
return item.qualityStatus==='ok' || item.qualityStatus==='unverified' ||
(item.qualityStatus==='warning' && item.qualityAcknowledged===true);
}
function cartPodeEnviar(){
const items=[...pedido,...(itemAtual?[itemAtual]:[])];
return items.length>0 && items.every(itemPodeEnviar);
}
function limpaPaineis(){
invalidaItemAtual();
['qual','prev'].forEach(id=>$(id).classList.remove('on'));
if(!pedido.length){ $('carr').classList.remove('on'); }
}
// O carrinho junta itens de produtos diferentes e cobra uma vez só.
function pintaPedido(){
$('itens').innerHTML = pedido.map((it,i)=>
'<div class="item"><div class="nm2"><b>'+escapeHTML(it.tit)+'</b><span>'+escapeHTML(it.desc)+'</span></div>'+
'<div class="vl2">'+rs(it.total)+'</div>'+
'<button type="button" class="x" data-rmi="'+i+'" aria-label="Remover '+escapeHTML(it.tit)+'">Remover</button></div>').join('');
$('itens').querySelectorAll('[data-rmi]').forEach(b=>b.addEventListener('click',()=>{
const i=+b.dataset.rmi, [item]=pedido.splice(i,1);
pintaPedido();
avisaDesfazer(item.tit+' saiu do carrinho.',()=>{
pedido.splice(Math.min(i,pedido.length),0,item); pintaPedido();
});
}));
$('bEsvaziar').hidden = pedido.length+(itemAtual?1:0) < 2;
const itens = pedido.reduce((t,it)=>t+it.total,0) + (itemAtual? itemAtual.total : 0);
const frete = entrega.tipo==='frete' && entrega.cotado ? entrega.valor : 0;
const soma = itens + frete;
const n = pedido.length + (itemAtual?1:0);
const eco = [...pedido, ...(itemAtual?[itemAtual]:[])]
.reduce((t,it)=>t+(TABELA[it.modo]-it.unit)*it.cob, 0);
$('resLin').innerHTML =
'<div class="l"><span>'+n+(n===1?' item':' itens')+'</span><b>'+rs(itens+eco)+'</b></div>'+
(eco>0.01? '<div class="l" style="color:var(--verde-ml)"><span>Desconto pela nota</span>'+
'<b style="color:var(--verde-ml)">− '+rs(eco)+'</b></div>' : '')+
'<div class="l"><span>Frete</span><b>'+
(entrega.tipo==='retira' ? '<span style="color:var(--verde-ml)">Grátis</span>'
: entrega.cotado ? rs(frete) : 'a cotar')+'</b></div>'+
'<div class="l"><span>Revisão e reencaixe</span>'+
'<b><span style="color:var(--verde-ml)">Grátis</span></b></div>';
$('carrTot').textContent=rs(soma);
$('bPagar').textContent = (pedido.length + (itemAtual?1:0))>1
? 'Pagar os '+(pedido.length+(itemAtual?1:0))+' itens de uma vez'
: 'Ir para o pagamento';
$('bPagar').disabled = !cartPodeEnviar() || !entrega.cotado || !clienteOk() || !enderecoOk();
if(pedido.length || itemAtual) $('carr').classList.add('on');
if($('cartLink')) $('cartLink').textContent='Carrinho ('+n+')';
window.dispatchEvent(new Event('dtf-cart-changed'));
}
function carrinho(){
const base=precoBase(nota), cob=cobrar(metros);
const unit=base, tot=cob*unit, sobra=+(cob-metros).toFixed(2);
$('carr').classList.add('on');
let l='<div class="l"><span>'+MODOS[modo].tit+'</span><b>'+rs(base)+'/m</b></div>';
{
const teto=TABELA[modo], eco=(teto-base)*cob;
l = '<div class="l"><span>'+MODOS[modo].tit+' · tabela</span><b>'+rs(teto)+'/m</b></div>';
l += eco>0.01
? '<div class="l" style="color:#7FD4A0"><span>Desconto pela nota '+nota+'</span><b>−'+rs(eco)+'</b></div>'
: '<div class="l" style="color:#8D9AB0"><span>Nota '+nota+' · sem desconto</span><b>—</b></div>';
}
if(!ehFolha()) l += '<div class="l" style="color:#8D9AB0"><span>Montagem da folha</span>'+
'<b>inclusa · '+rs(MONTAGEM[modo])+'/m</b></div>';
l += '<div class="l"><span>Metragem'+(sobra>0.001?' · arredondada para 10 cm':'')+
'</span><b>'+fmtM(cob)+' m</b></div>';
l += '<div class="l"><span>Preço final do metro</span><b>'+rs(unit)+'</b></div>'+
'<div class="l" style="color:var(--laranja2)"><span>Revisão e reencaixe</span><b>grátis</b></div>';
$('carrLin').innerHTML=l;
$('atual').style.display='';
const sources=(ehFolha()?folhas:artes).map(x=>ehFolha()
? {kind:'sheet',width_cm:x.med?.larg||larguraFilme(),length_cm:+(x.m*100).toFixed(4),
copies:x.rep||1,rotation_degrees:0,mirrored:false,
measurement:x.med?'file':'customer'}
: {kind:'artwork',width_cm:x.cm,length_cm:+(x.cm*propDe(x)).toFixed(4),
copies:x.q,rotation_degrees:x.giro||0,mirrored:!!x.esp,
measurement:x.src?'file':'customer'});
let layout;
if(ehFolha()){
let y=0;
const placements=[];
sources.forEach((source,source_index)=>{
for(let copy_index=0;copy_index<source.copies;copy_index++){
placements.push({source_index,copy_index,x_cm:0,y_cm:+y.toFixed(4),
width_cm:source.width_cm,length_cm:source.length_cm,
rotation_degrees:0,mirrored:false});
y+=source.length_cm;
}
});
layout={height_cm:+y.toFixed(4),placements};
}else{
if(!montagemLayout) return;
layout=montagemLayout;
}
itemAtual={modo, tit:MODOS[modo].tit, nota, metros, cob, unit, total:tot,
localFiles:(ehFolha()?folhas:artes).map(x=>x.f),
production:{version:2,film_width_cm:larguraFilme(),sources,...layout},
qualityStatus:$('ciente').classList.contains('recusa')?'rejected':
$('ciente').classList.contains('on')?'warning':nota===0?'unverified':'ok',
qualityAcknowledged:false,
desc:fmtM(cob)+' m · '+rs(unit)+'/m · nota '+nota};
pintaPedido();
previa();
if(nota<90){
const piso=pisoEscada(), ganho=(base-piso)*cob;
if(ganho>0.5) qm('<b>Dá para chegar ao melhor preço.</b> Corrigindo os pontos e chegando a 90, '+
'o metro cai para '+rs(piso)+' — são '+rs(ganho)+' a menos neste pedido.','var(--verde)');
}
}
// Removing is one click, and a wrong click is undone from the notice that follows.
let desfazerAcao=null, desfazerTimer=null;
function avisaDesfazer(texto,acao){
desfazerAcao=acao; clearTimeout(desfazerTimer);
$('desfazerTxt').textContent=texto; $('desfazer').hidden=false;
desfazerTimer=setTimeout(fechaDesfazer,8000);
}
function fechaDesfazer(){ clearTimeout(desfazerTimer); desfazerAcao=null; $('desfazer').hidden=true; }
addEventListener('dtf-page-changed',fechaDesfazer);
$('desfazerBtn').addEventListener('click',()=>{ const acao=desfazerAcao; fechaDesfazer(); if(acao) acao(); });
$('bEsvaziar').addEventListener('click',()=>{
const antes=pedido.slice();
pedido=[]; invalidaItemAtual(); pintaPedido();
avisaDesfazer('Carrinho esvaziado.',()=>{ pedido=antes; pintaPedido(); });
});
function qm(t,c){ const m=$('qmsg'); m.style.display='block'; m.style.color=c||'var(--verde)'; m.innerHTML=t; }