// Buyer toast — fixed at top, appears every 8s, stays 4s const TOAST_BUYERS = [ { name: 'João Silva', city: 'Braga', kit: 'Campeão', img: 'uploads/homem-1.jpg' }, { name: 'Sofia Almeida', city: 'Porto', kit: 'Inicial', img: 'uploads/mulher-1.jpg' }, { name: 'Miguel Costa', city: 'Lisboa', kit: 'Colecionador', img: 'uploads/homem-2.jpg' }, { name: 'Rita Fernandes', city: 'Coimbra', kit: 'Campeão', img: 'uploads/avatar-rita.png' }, { name: 'André Pereira', city: 'Faro', kit: 'Inicial', img: 'uploads/homem-3.jpg' }, { name: 'Carolina Dias', city: 'Aveiro', kit: 'Basic', img: 'uploads/mulher-2.jpg' }, { name: 'Bruno Oliveira', city: 'Setúbal', kit: 'Campeão', img: 'uploads/avatar-carlos.png' }, { name: 'Inês Martins', city: 'Funchal', kit: 'Colecionador', img: 'uploads/mulher-3.jpg' }, { name: 'Tiago Ribeiro', city: 'Évora', kit: 'Campeão', img: 'uploads/avatar-roberto.png' }, ]; function BuyerAvatar({ buyer, size = 44 }) { const [errored, setErrored] = React.useState(false); const colors = [ [C.green, C.gold], [C.red, C.gold], [C.greenDeep, C.cream], [C.gold, C.red], [C.green, C.cream], ]; const [c1, c2] = colors[buyer.name.charCodeAt(0) % colors.length]; if (buyer.img && !errored) { return ( {buyer.name} setErrored(true)} style={{ width: size, height: size, borderRadius: '50%', objectFit: 'cover', flexShrink: 0, border: `2px solid ${C.gold}`, background: '#eee', }} /> ); } return (
{buyer.name.split(' ').map(n => n[0]).slice(0,2).join('')}
); } function BuyerToast() { const [idx, setIdx] = React.useState(0); const [visible, setVisible] = React.useState(false); const [secondsAgo, setSecondsAgo] = React.useState(0); // First appearance delayed slightly React.useEffect(() => { const initial = setTimeout(() => setVisible(true), 1800); return () => clearTimeout(initial); }, []); // Rhythm: visible 4s → hidden 4s → next buyer React.useEffect(() => { if (visible) { setSecondsAgo(Math.floor(2 + Math.random() * 40)); const t = setTimeout(() => setVisible(false), 4000); return () => clearTimeout(t); } else { const t = setTimeout(() => { setIdx((i) => i + 1); setVisible(true); }, 4000); return () => clearTimeout(t); } }, [visible]); const buyer = TOAST_BUYERS[idx % TOAST_BUYERS.length]; return (
{/* Pulse dot */}
{buyer.name.split(' ')[0]} de {buyer.city}
comprou o Kit {buyer.kit}
há {secondsAgo}s · pagamento confirmado ✓
); } // Landing / Hero screen function Landing({ onStart }) { const [tick, setTick] = React.useState(0); const [buyerIdx, setBuyerIdx] = React.useState(0); const [buyerVisible, setBuyerVisible] = React.useState(true); const [secondsAgo, setSecondsAgo] = React.useState(12); React.useEffect(() => { const t = setInterval(() => setTick((x) => x + 1), 1000); return () => clearInterval(t); }, []); // Buyer notification rotates every 9–14s with a fade transition React.useEffect(() => { let active = true; const cycle = () => { if (!active) return; const wait = 9000 + Math.random() * 5000; setTimeout(() => { if (!active) return; setBuyerVisible(false); setTimeout(() => { if (!active) return; setBuyerIdx((i) => i + 1); setSecondsAgo(Math.floor(2 + Math.random() * 30)); setBuyerVisible(true); cycle(); }, 400); }, wait); }; cycle(); return () => { active = false; }; }, []); // Tick the "há Xs" counter up while a buyer is showing React.useEffect(() => { const t = setInterval(() => setSecondsAgo((s) => s + 1), 1000); return () => clearInterval(t); }, [buyerIdx]); // Countdown to a fixed future date const deadline = React.useMemo(() => Date.now() + 1000 * 60 * 60 * 23 + 1000 * 47 * 60 + 1000 * 12, []); const remaining = Math.max(0, deadline - Date.now()); const hh = String(Math.floor(remaining / 3600000)).padStart(2, '0'); const mm = String(Math.floor((remaining % 3600000) / 60000)).padStart(2, '0'); const ss = String(Math.floor((remaining % 60000) / 1000)).padStart(2, '0'); // Rotating "just bought" notifications const buyers = [ { name: 'João', city: 'Braga', kit: 'Campeão', img: 'uploads/homem-1.jpg' }, { name: 'Sofia', city: 'Porto', kit: 'Inicial', img: 'uploads/mulher-1.jpg' }, { name: 'Miguel', city: 'Lisboa', kit: 'Colecionador', img: 'uploads/homem-2.jpg' }, { name: 'Rita', city: 'Coimbra', kit: 'Campeão', img: 'uploads/avatar-rita.png' }, { name: 'André', city: 'Faro', kit: 'Inicial', img: 'uploads/homem-3.jpg' }, { name: 'Carolina', city: 'Aveiro', kit: 'Basic', img: 'uploads/mulher-2.jpg' }, ]; const buyer = buyers[buyerIdx % buyers.length]; return (
{/* Top notice strip */}
⚡ ENVIO PARA TODO PORTUGAL · STOCK LIMITADO ⚡
{/* Hero */}
{/* Subtle stadium stripes */}
{/* Countdown */}
OFERTA TERMINA EM {hh}:{mm}:{ss}
{/* Headline */}
MUNDIAL · NORTE AMÉRICA · 2026
COLECIONA
O MUNDIAL
INTEIRO
Álbum + saquetas de cromos · 48 seleções · 736 craques.
Faz o quiz e desbloqueia até 35% OFF.
{/* Floating cromo trio */}
🎯 Fazer Quiz · Ganhar Desconto
✓ Stock em PT ✓ Envio 24-48h ✓ MB Way
{/* Live buyer ticker */}
{buyer.name} de {buyer.city} acabou de comprar
Kit {buyer.kit} · há {secondsAgo < 60 ? `${secondsAgo}s` : `${Math.floor(secondsAgo / 60)}min`}
{/* Social proof stats */}
{[ ['12 384', 'Colecionadores'], ['4,9★', '1 207 reviews'], ['48h', 'Envio máx.'], ].map(([n, l]) => (
{n}
{l}
))}
{/* Why */}
A coleção oficial da temporada} />
{[ { i: '⚽', t: '736 craques', d: 'Todos os 48 plantéis do Mundial 2026' }, { i: '✨', t: 'Cromos raros', d: 'Holográficos, foil, lendas e edições limitadas' }, { i: '📦', t: 'Saquetas seladas', d: 'Diretamente do fornecedor — sem cromos repetidos garantidos por kit' }, { i: '🇵🇹', t: 'Stock em Portugal', d: 'Envio CTT 24-48h · Pagamento MB Way' }, ].map((f, i) => (
{f.i}
{f.t.toUpperCase()}
{f.d}
))}
Quero o meu desconto →
🔒 Pagamento seguro · Garantia 30 dias
); } function SoundToggle() { const [muted, setMuted] = React.useState(false); return ( ); } Object.assign(window, { Landing, SoundToggle });