"use client"; import { useState, useEffect } from "react"; import { Gamepad2, BarChart3, Users, AlertTriangle, MessageSquarePlus, TrendingUp, Shield, ShieldX, ShieldCheck, } from "lucide-react"; import { cn } from "@/lib/utils"; interface DashboardStats { overview: { totalGames: number; totalBenchmarks: number; totalUsers: number; pendingReports: number; pendingSuggestions: number; }; recent: { benchmarksLast30Days: number; gamesLast30Days: number; }; topContributors: Array<{ userId: string; name: string; count: number; }>; syncHealth: Record; gamesBySource: Record; playabilityDistribution: Record; } export function DashboardOverview() { const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetch("/api/dashboard/stats") .then((res) => res.json()) .then((data) => { setStats(data); setLoading(false); }) .catch(() => setLoading(false)); }, []); if (loading) { return
; } if (!stats) return null; const statCards = [ { label: "Total Games", value: stats.overview.totalGames, icon: Gamepad2, color: "text-blue-400", }, { label: "Total Benchmarks", value: stats.overview.totalBenchmarks, icon: BarChart3, color: "text-green-400", }, { label: "Total Users", value: stats.overview.totalUsers, icon: Users, color: "text-purple-400", }, { label: "Pending Reports", value: stats.overview.pendingReports, icon: AlertTriangle, color: "text-red-400", highlight: stats.overview.pendingReports > 0, }, { label: "Pending Suggestions", value: stats.overview.pendingSuggestions, icon: MessageSquarePlus, color: "text-amber-400", highlight: stats.overview.pendingSuggestions > 0, }, { label: "Benchmarks (30d)", value: stats.recent.benchmarksLast30Days, icon: TrendingUp, color: "text-emerald-400", }, { label: "New Games (30d)", value: stats.recent.gamesLast30Days, icon: Gamepad2, color: "text-cyan-400", }, ]; return (
{/* Stat Cards */}
{statCards.map((card) => { const Icon = card.icon; return (
{card.label}

{card.value.toLocaleString()}

); })}
{/* Grid: Top Contributors + Playability Distribution */}
{/* Top Contributors */}

Top Contributors

{stats.topContributors.slice(0, 5).map((contributor, i) => (
#{i + 1} {contributor.name}
{contributor.count} entries
))}
{/* Playability Distribution */}

Playability Distribution

{Object.entries(stats.playabilityDistribution).map(([status, count]) => { const config: Record = { great: { label: "Plays Great", color: "bg-emerald-500" }, playable: { label: "Playable", color: "bg-blue-500" }, needs_tweaks: { label: "Needs Tweaks", color: "bg-amber-500" }, unplayable: { label: "Unplayable", color: "bg-red-500" }, unknown: { label: "Unknown", color: "bg-zinc-500" }, }; const c = config[status] ?? config.unknown; return (
{c.label} {count}
); })}
{/* Sync Health */}

Steam Sync Health

{Object.entries(stats.syncHealth).map(([status, count]) => { const icons: Record = { synced: ShieldCheck, failed: ShieldX, pending: Shield, }; const colors: Record = { synced: "text-green-400", failed: "text-red-400", pending: "text-yellow-400", }; const Icon = icons[status] ?? Shield; const color = colors[status] ?? "text-zinc-400"; return (

{count}

{status}

); })}
); }