// Checkout screen — order bumps + external checkout redirect const CHECKOUT_API_URL = 'checkout-proxy.php'; // proxy PHP guarda a chave no servidor const SHOP_ASSET_BASE = 'https://panini-pt.shop'; const BUMPS = [ { id: 'b50', qty: 50, price: 19.99, original: 31.25, label: '+50 saquetas extra', best: false }, { id: 'b100', qty: 100, price: 34.99, original: 62.50, label: '+100 saquetas extra', best: true }, { id: 'b250', qty: 250, price: 74.99, original: 156.25, label: '+250 saquetas extra', best: false }, ]; window.BUMPS = BUMPS; function shopImageUrl(path) { if (!path) return ''; if (/^https?:\/\//i.test(path)) return path; return `${SHOP_ASSET_BASE}/${path.replace(/^\/+/, '')}`; } function Checkout({ kit, discount, onComplete, onBack }) { const [bumps, setBumps] = React.useState({}); const [extraOff, setExtraOff] = React.useState(0); // % bonus applied by retention const [showRetention, setShowRetention] = React.useState(false); const [retentionUsed, setRetentionUsed] = React.useState(false); const [isCreatingSession, setIsCreatingSession] = React.useState(false); const [checkoutError, setCheckoutError] = React.useState(''); const toggleBump = (id) => { window.Sound?.playCoin(); setBumps((b) => ({ ...b, [id]: !b[id] })); }; const handleBack = () => { if (!retentionUsed) { window.Sound?.playWhistle(); setShowRetention(true); } else { onBack(); } }; const kitPrice = +(kit.price * (1 - discount / 100)).toFixed(2); const bumpTotal = BUMPS.filter((b) => bumps[b.id]).reduce((s, b) => s + b.price, 0); const retentionBonus = +(((kitPrice + bumpTotal) * extraOff) / 100).toFixed(2); const shipping = 0; const total = +(kitPrice + bumpTotal + shipping - retentionBonus).toFixed(2); const selectedBumps = BUMPS.filter((b) => bumps[b.id]); const checkoutItems = [ { title: `Kit ${kit.name}`, price: +(kitPrice - retentionBonus).toFixed(2), quantity: 1, image: shopImageUrl(kit.img), }, ...selectedBumps.map((b) => ({ title: b.label, price: b.price, quantity: 1, image: shopImageUrl('uploads/saqueta.png'), })), ]; const createCheckoutSession = async () => { if (isCreatingSession) return; setCheckoutError(''); setIsCreatingSession(true); window.Sound?.playWhistle(); try { const sessionId = `c26_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`; const response = await fetch(CHECKOUT_API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ item_count: checkoutItems.reduce((sum, item) => sum + item.quantity, 0), total_price: +total.toFixed(2), currency: 'EUR', cartItems: checkoutItems, }), }); const data = await response.json().catch(() => ({})); if (!response.ok || !data?.checkout_url) { throw new Error(data?.message || 'Não foi possível iniciar o checkout.'); } window.location.href = data.checkout_url; } catch (err) { setCheckoutError(err.message || 'Não foi possível iniciar o checkout.'); setIsCreatingSession(false); window.Sound?.playWrong(); } }; return (
{/* Header bar */}
CHECKOUT SEGURO 🔒
-{discount}%
{/* Steps */}
{['Kit', 'Extras', 'Checkout'].map((s, i) => (
{s}
))}
{/* Selected kit */}
{`Kit
KIT {kit.name.toUpperCase()}
{kit.contents}
{kitPrice.toFixed(2)}€
{kit.original.toFixed(2)}€
{/* Order bumps */}
🎁 UPGRADE A TUA CAIXA · 50% OFF
{BUMPS.map((b) => { const on = !!bumps[b.id]; const savePct = Math.round((1 - b.price / b.original) * 100); const saveEur = (b.original - b.price).toFixed(2); return (
{b.best && (
★ MAIS ESCOLHIDA
)}
{/* saqueta stack */}
{[ { left: 13, top: 9, rot: -10, opacity: 0.72 }, { left: 8, top: 5, rot: -3, opacity: 0.88 }, { left: 3, top: 0, rot: 5, opacity: 1 }, ].map((pack, i) => ( ))}
+{b.qty}
SAQUETAS
{/* info */}
+{b.qty} CROMOS
{Math.round(b.qty / 7)} saquetas · envio junto ao kit
{b.price.toFixed(2)}€ {b.original.toFixed(2)}€ -{savePct}%
poupas {saveEur}€
{/* toggle */}
); })}
{/* Summary */}
RESUMO DA ENCOMENDA
{[ ['Kit ' + kit.name, kitPrice.toFixed(2)], ...selectedBumps.map((b) => [b.label, b.price.toFixed(2)]), ['Envio CTT', 'GRÁTIS'], ['Desconto quiz', `-${(kit.original - kitPrice).toFixed(2)}€`, true], ...(extraOff > 0 ? [['🎁 Bónus retenção', `-${retentionBonus.toFixed(2)}€`, true]] : []), ].map(([l, v, neg], i) => (
{l} {v === 'GRÁTIS' ? v : (neg ? v : v + '€')}
))}
TOTAL {total.toFixed(2)}€
{checkoutError && (
{checkoutError}
)} {isCreatingSession ? 'A abrir checkout...' : `🔒 Pagar agora · ${total.toFixed(2)}€`}
Vais finalizar a morada e o pagamento no checkout seguro externo
{/* Retention modal */} {showRetention && ( { window.Sound?.playGoal(); setExtraOff(5); setRetentionUsed(true); setShowRetention(false); }} onLeave={() => { setRetentionUsed(true); setShowRetention(false); onBack(); }} /> )}
); } function RetentionModal({ discount, onApply, onLeave }) { const [sec, setSec] = React.useState(120); React.useEffect(() => { const t = setInterval(() => setSec((s) => Math.max(0, s - 1)), 1000); return () => clearInterval(t); }, []); const mm = String(Math.floor(sec / 60)).padStart(2, '0'); const ss = String(sec % 60).padStart(2, '0'); return (
e.stopPropagation()} style={{ background: C.cream, borderRadius: 22, maxWidth: 360, width: '100%', overflow: 'hidden', boxShadow: '0 30px 80px rgba(0,0,0,0.5)', position: 'relative', }}> {/* Header */}
ESPERA! NÃO VÁS EMBORA
OFERTA SECRETA
SÓ AGORA
{/* Big bonus */}
BÓNUS DE RETENÇÃO
+5% OFF
Acumula com o teu desconto de {discount}% → total {discount + 5}% OFF
{/* Free gift */}
🎁
+ 3 cromos raros holográficos
oferecidos no envio · valor 9,90€
{/* Timer */}
⏱ EXPIRA EM {mm}:{ss}
✓ Aplicar bónus & continuar
); } Object.assign(window, { Checkout, BUMPS });