'use client' import { useState, useEffect } from 'react' import { motion, AnimatePresence } from 'motion/react' import { cn } from '@/lib/utils' interface LiveScoreAnimationProps { score: number | null maxScore: number label: string animate?: boolean theme?: 'dark' | 'light' | 'branded' } function getScoreColor(score: number, maxScore: number): string { const ratio = score / maxScore if (ratio >= 0.75) return 'text-green-500' if (ratio >= 0.5) return 'text-yellow-500' if (ratio >= 0.25) return 'text-orange-500' return 'text-red-500' } function getProgressColor(score: number, maxScore: number): string { const ratio = score / maxScore if (ratio >= 0.75) return 'stroke-green-500' if (ratio >= 0.5) return 'stroke-yellow-500' if (ratio >= 0.25) return 'stroke-orange-500' return 'stroke-red-500' } function getThemeClasses(theme: 'dark' | 'light' | 'branded') { switch (theme) { case 'dark': return { bg: 'bg-gray-900', text: 'text-white', label: 'text-gray-400', ring: 'stroke-gray-700', } case 'light': return { bg: 'bg-white', text: 'text-gray-900', label: 'text-gray-500', ring: 'stroke-gray-200', } case 'branded': return { bg: 'bg-[#053d57]', text: 'text-white', label: 'text-[#557f8c]', ring: 'stroke-[#053d57]/30', } } } export function LiveScoreAnimation({ score, maxScore, label, animate = true, theme = 'branded', }: LiveScoreAnimationProps) { const [displayScore, setDisplayScore] = useState(0) const themeClasses = getThemeClasses(theme) const radius = 40 const circumference = 2 * Math.PI * radius const targetScore = score ?? 0 const progress = maxScore > 0 ? targetScore / maxScore : 0 const offset = circumference - progress * circumference useEffect(() => { if (!animate || score === null) { setDisplayScore(targetScore) return } let frame: number const duration = 1200 const startTime = performance.now() const startScore = 0 const step = (currentTime: number) => { const elapsed = currentTime - startTime const progress = Math.min(elapsed / duration, 1) // Ease out cubic const eased = 1 - Math.pow(1 - progress, 3) const current = startScore + (targetScore - startScore) * eased setDisplayScore(Math.round(current * 10) / 10) if (progress < 1) { frame = requestAnimationFrame(step) } } frame = requestAnimationFrame(step) return () => cancelAnimationFrame(frame) }, [targetScore, animate, score]) if (score === null) { return (