import type { ReactNode } from 'react'; import { useEffect, useRef, useState } from 'react'; import { useLang } from '../context/LanguageContext'; import { useData } from '../context/DataContext'; import { BookOpen, Award, Globe2 } from 'lucide-react'; /* ── Animated counter hook ─────────────────────────────────────────────── */ function useCountUp(target: number, duration = 1600) { const [count, setCount] = useState(0); const elRef = useRef(null); const triggered = useRef(false); useEffect(() => { triggered.current = false; let animationFrameId: number; let observer: IntersectionObserver; observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting && !triggered.current) { triggered.current = true; let startTimestamp: number | null = null; const step = (timestamp: number) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); // easeOutQuart easing function const easeProgress = 1 - Math.pow(1 - progress, 4); setCount(Math.round(target * easeProgress)); if (progress < 1) { animationFrameId = requestAnimationFrame(step); } else { setCount(target); } }; animationFrameId = requestAnimationFrame(step); } }, { threshold: 0.4 }, ); if (elRef.current) observer.observe(elRef.current); return () => { observer.disconnect(); if (animationFrameId) cancelAnimationFrame(animationFrameId); }; }, [target, duration]); return { count, elRef }; } /* ── Big stat ──────────────────────────────────────────────────────────── */ function BigStat({ value, label }: { value: number; label: string }) { const { count, elRef } = useCountUp(value); return (
{count}
{label}
); } /* ── Level row ──────────────────────────────────────────────────────────── */ function LevelRow({ label, value, delay = 0 }: { label: string; value: number; delay?: number }) { const { count, elRef } = useCountUp(value, 1600 + delay); return (
{label} {count}
); } /* ── Dividers ───────────────────────────────────────────────────────────── */ function VDivider() { return (
); } function HDivider() { return
; } /* ── Main export ────────────────────────────────────────────────────────── */ export default function Stats() { const { t, lang } = useLang(); const { achievements, projects } = useData(); const totalPrestasi = achievements.length; const totalProyek = projects.length; const internasional = achievements.filter(a => a.level === 'Internasional').length; const nasional = achievements.filter(a => a.level === 'Nasional').length; const regional = achievements.filter(a => a.level === 'Regional').length; const today = new Date().toLocaleDateString( lang === 'id' ? 'id-ID' : 'en-US', { day: 'numeric', month: 'long', year: 'numeric' } ); const dataNote = lang === 'id' ? `Data Terkumpul Per ${today}` : `Data Collected As Of ${today}`; return (
{/* ── Stats bar ─────────────────────────────────────────────────── */}
{/* ① Total Prestasi */}
{/* ② Total Proyek */}
{/* ③ Level breakdown */}
{/* Keterangan tanggal — di luar kotak, rata kanan */}

{dataNote}

); } /* ── Fact card helper ───────────────────────────────────────────────────── */ function FactCard({ icon, label, value }: { icon: ReactNode; label: string; value: string }) { return (
{icon}

{label}

{value}

); }