import { useEffect, useRef, useState } from 'react'; import { motion } from 'framer-motion'; import type { Stat } from '@/types'; interface StatsCardProps { stat: Stat; delay?: number; } function useCountUp(target: number, duration: number = 1800, start: boolean = false) { const [count, setCount] = useState(0); useEffect(() => { if (!start) return; let startTime: number | null = null; const step = (timestamp: number) => { if (!startTime) startTime = timestamp; const progress = Math.min((timestamp - startTime) / duration, 1); const ease = 1 - Math.pow(1 - progress, 3); // ease-out cubic setCount(Math.floor(ease * target)); if (progress < 1) requestAnimationFrame(step); }; requestAnimationFrame(step); }, [target, duration, start]); return count; } export default function StatsCard({ stat, delay = 0 }: StatsCardProps) { const [isVisible, setIsVisible] = useState(false); const ref = useRef(null); const count = useCountUp(stat.value, 1800, isVisible); useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setIsVisible(true); observer.disconnect(); } }, { threshold: 0.2 } ); if (ref.current) observer.observe(ref.current); return () => observer.disconnect(); }, []); return ( {/* Corner Bracket Decorations from Reference Image */}
{count} {stat.suffix}
{stat.label}
); }