'use client'; import { useEffect, useState } from 'react'; import { getStats, type AdminStats } from '@/lib/api'; function KpiCard({ title, value, sub, }: { title: string; value: string | number; sub?: string; }) { return (

{title}

{value}

{sub &&

{sub}

}
); } function ReactionBar({ reactions }: { reactions: Record }) { const total = Object.values(reactions).reduce((a, b) => a + b, 0); if (total === 0) return

No reactions yet.

; const COLORS: Record = { done: 'bg-emerald-500', snooze: 'bg-yellow-400', dismiss: 'bg-red-500', }; return (
{Object.entries(reactions).map(([action, count]) => (
{action}
{count}
))}
); } export function OverviewDashboard() { const [stats, setStats] = useState(null); const [error, setError] = useState(null); useEffect(() => { getStats() .then(setStats) .catch((e) => setError(String(e.message))); }, []); if (error) { return

Failed to load stats: {error}

; } const activationPct = stats && stats.totalUsers > 0 ? ((stats.activatedUsers / stats.totalUsers) * 100).toFixed(1) : null; return (

Overview

Last 7 days unless noted

{/* KPI grid */}
{/* Reactions */}

Reactions last 7 days

{stats ? ( ) : (

Loading…

)}
{/* Activation funnel */}

Activation funnel

{stats ? (
a + b, 0)} max={stats.tipsServedLast7d} dimMax />
) : (

Loading…

)}
); } function FunnelRow({ label, value, max, dimMax, }: { label: string; value: number; max: number; dimMax?: boolean; }) { const pct = max > 0 ? (value / max) * 100 : 0; return (
{label}
{value} {!dimMax && max > 0 && ( {pct.toFixed(0)}% )}
); }