// 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) => (
))}
{/* Selected 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) => (

))}
{/* 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 });