import { useEffect, useState } from 'react'; import { get } from '../lib/api'; import type { Stats } from '../lib/types'; import { RefreshCw } from '../components/Icons'; export function Dashboard() { const [stats, setStats] = useState(null); const [err, setErr] = useState(null); const [loading, setLoading] = useState(false); const load = async () => { setLoading(true); setErr(null); try { const data = await get('/stats'); setStats(data); } catch (e) { setErr((e as Error).message); } finally { setLoading(false); } }; useEffect(() => { load(); const id = setInterval(load, 10_000); return () => clearInterval(id); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return (

Dashboard

Server snapshot, refreshed every 10s.

{err &&
{err}
}

Top rooms by visits

All-time visit counts.

{stats?.rooms.topByVisits.map(r => ( ))} {!stats && }
Room Visits Visitors Cheers
{r.name} {r.visitCount.toLocaleString()} {r.visitorCount.toLocaleString()} {r.cheerCount.toLocaleString()}
loading…

Recent signups

Latest 10 accounts.

{stats?.recentJoins.map(j => ( ))} {!stats && }
Username Joined
{j.username} #{j.id} {new Date(j.createdAt).toLocaleString()}
loading…

Server time: {stats ? new Date(stats.serverTime).toLocaleString() : '—'}

); } function Stat({ label, value, sub, accent }: { label: string; value: number | undefined; sub?: string | null; accent: 'success' | 'danger' | 'warn' | 'neutral' }) { const accentRing = { success: 'before:bg-success', danger: 'before:bg-danger', warn: 'before:bg-warn', neutral: 'before:bg-brand-500', }[accent]; return (
{label}
{value?.toLocaleString() ?? '—'}
{sub &&
{sub}
}
); }