'use client'; import { useState, useEffect, useCallback } from 'react'; interface DrawAnimationProps { winnerName?: string; winningTicket?: number; potAmount?: number; onComplete: () => void; // If true, show "drawing" animation without winner info isDrawing?: boolean; } export function DrawAnimation({ winnerName, winningTicket, potAmount, onComplete, isDrawing = false, }: DrawAnimationProps) { const [phase, setPhase] = useState<'spinning' | 'revealing' | 'winner' | 'no-winner' | 'done'>('spinning'); const [displayTicket, setDisplayTicket] = useState(0); const [showConfetti, setShowConfetti] = useState(false); const hasWinner = winnerName !== undefined && winningTicket !== undefined && potAmount !== undefined; // Generate random ticket numbers during spin useEffect(() => { if (phase !== 'spinning') return; const spinInterval = setInterval(() => { setDisplayTicket(Math.floor(Math.random() * 999999999) + 1); }, 50); // After 2.5 seconds, start revealing (only if we have winner info) const revealTimeout = setTimeout(() => { if (hasWinner) { setPhase('revealing'); } // If no winner, keep spinning until we get data or timeout }, 2500); return () => { clearInterval(spinInterval); clearTimeout(revealTimeout); }; }, [phase, hasWinner]); // When winner info becomes available during spinning, transition to revealing useEffect(() => { if (phase === 'spinning' && hasWinner) { const timer = setTimeout(() => { setPhase('revealing'); }, 500); return () => clearTimeout(timer); } }, [phase, hasWinner]); // If isDrawing becomes false and we have no winner, show no-winner phase useEffect(() => { if (!isDrawing && !hasWinner && phase === 'spinning') { setPhase('no-winner'); } }, [isDrawing, hasWinner, phase]); // Slow down and reveal actual number useEffect(() => { if (phase !== 'revealing' || !winningTicket) return; let speed = 50; let iterations = 0; const maxIterations = 15; const slowDown = () => { if (iterations >= maxIterations) { setDisplayTicket(winningTicket); setPhase('winner'); return; } speed += 30; iterations++; setDisplayTicket(Math.floor(Math.random() * 999999999) + 1); setTimeout(slowDown, speed); }; slowDown(); }, [phase, winningTicket]); // Show winner and confetti useEffect(() => { if (phase !== 'winner') return; setShowConfetti(true); // Auto-dismiss after 15 seconds (give time to load next cycle) const dismissTimeout = setTimeout(() => { setPhase('done'); onComplete(); }, 15000); return () => clearTimeout(dismissTimeout); }, [phase, onComplete]); // Handle no-winner phase useEffect(() => { if (phase !== 'no-winner') return; // Auto-dismiss after 3 seconds const dismissTimeout = setTimeout(() => { setPhase('done'); onComplete(); }, 3000); return () => clearTimeout(dismissTimeout); }, [phase, onComplete]); const handleDismiss = useCallback(() => { setPhase('done'); onComplete(); }, [onComplete]); if (phase === 'done') return null; return (
{/* Confetti Effect */} {showConfetti && (
{[...Array(50)].map((_, i) => (
))}
)}
{/* Spinning Phase */} {(phase === 'spinning' || phase === 'revealing') && ( <>
🎰 Drawing Winner...
Ticket Number
#{displayTicket.toLocaleString()}
)} {/* Winner Phase */} {phase === 'winner' && hasWinner && (
🎉🏆🎉
We Have a Winner!
Winner
{winnerName || 'Anon'}
Winning Ticket
#{winningTicket!.toLocaleString()}
Prize
{potAmount!.toLocaleString()} sats
Tap anywhere to continue
)} {/* No Winner Phase (no tickets sold) */} {phase === 'no-winner' && (
😔
No Tickets This Round
No tickets were sold for this draw.
Next draw starting soon!
Tap anywhere to continue
)}
); }