"use client"; import { useEffect, useRef, useState } from "react"; interface AnimatedCounterProps { end: number; duration?: number; suffix?: string; prefix?: string; className?: string; } export default function AnimatedCounter({ end, duration = 2000, suffix = "", prefix = "", className = "", }: AnimatedCounterProps) { const [count, setCount] = useState(0); const ref = useRef(null); const hasAnimated = useRef(false); useEffect(() => { const el = ref.current; if (!el) return; const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting && !hasAnimated.current) { hasAnimated.current = true; const startTime = performance.now(); const animate = (currentTime: number) => { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); // Ease out cubic const eased = 1 - Math.pow(1 - progress, 3); setCount(Math.floor(eased * end)); if (progress < 1) { requestAnimationFrame(animate); } }; requestAnimationFrame(animate); } }, { threshold: 0.5 } ); observer.observe(el); return () => observer.disconnect(); }, [end, duration]); return ( {prefix}{count}{suffix} ); }