feat: Punkte-Reveal with confetti animation

Shows animated reveal overlay for unseen match results.
Exact match (3pts) triggers confetti explosion.
Each reveal shown only once (localStorage tracking).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ronny
2026-04-11 19:10:22 +02:00
parent 89046a2e29
commit f6ab2c719d
6 changed files with 199 additions and 0 deletions
@@ -0,0 +1,43 @@
import { useEffect, useRef } from 'react';
import confetti from 'canvas-confetti';
import { Match } from '../api/client';
import styles from './ConfettiReveal.module.css';
interface Props {
match: Match;
onDismiss: () => void;
}
export default function ConfettiReveal({ match, onDismiss }: Props) {
const didFire = useRef(false);
const tip = match.userTip!;
const points = tip.points!;
useEffect(() => {
if (points === 3 && !didFire.current) {
didFire.current = true;
confetti({ particleCount: 120, spread: 80, origin: { y: 0.6 } });
}
}, [points]);
const resultLabel = points === 3 ? 'EXAKT! 🎉' : points === 1 ? 'Richtige Tendenz! 👏' : 'Knapp daneben... 😅';
const badgeClass = points === 3 ? styles.badgeExact : points === 1 ? styles.badgeTendency : styles.badgeWrong;
return (
<div className={styles.overlay} onClick={onDismiss}>
<div className={styles.card} onClick={e => e.stopPropagation()}>
<div className={styles.result}>
{match.homeTeam.shortName} {match.score.home}:{match.score.away} {match.awayTeam.shortName}
</div>
<div className={styles.tipLine}>
Dein Tipp: {tip.home}:{tip.away}
</div>
<div className={`${styles.badge} ${badgeClass}`}>
{points} {points === 1 ? 'Punkt' : 'Punkte'}
</div>
<div className={styles.label}>{resultLabel}</div>
<button className={styles.dismissBtn} onClick={onDismiss}>Weiter</button>
</div>
</div>
);
}