"use client"; import Link from "next/link"; import { Activity, Database, ShieldAlert, Timer } from "lucide-react"; import { useAdminQuery } from "@/components/admin/use-query"; import type { DashboardResponse } from "@/components/admin/types"; import { PageHeader, RefreshButton, StatTile, StatGrid, Panel, DataTable, ErrorState, TileSkeleton, type Column, Mono } from "@/components/admin/primitives"; import { compact, dateTime, duration, int, ms, multiplier, pct, sc } from "@/components/admin/format"; import { cn } from "@/lib/utils"; type TopGame = DashboardResponse["topGames"][number]; type HighWin = DashboardResponse["highestWins"][number]; const topGameCols: Column[] = [ { key: "slug", header: "Game", render: (r) => {r.slug} }, { key: "spins", header: "Spins", align: "right", render: (r) => int(r.spins) }, { key: "wagered", header: "Wagered", align: "right", render: (r) => sc(r.wagered) }, { key: "won", header: "Won", align: "right", render: (r) => sc(r.won) }, { key: "rtp", header: "RTP", align: "right", render: (r) => 1.02 || r.rtp < 0.9) ? "text-[#ffc46b]" : "")}>{pct(r.rtp)} }, ]; const highWinCols: Column[] = [ { key: "at", header: "When", render: (r) => {dateTime(r.at)} }, { key: "username", header: "Player", render: (r) => r.username }, { key: "game", header: "Game", render: (r) => {r.game} }, { key: "bet", header: "Bet", align: "right", render: (r) => sc(r.bet) }, { key: "win", header: "Win", align: "right", render: (r) => {sc(r.win)} }, { key: "multiplier", header: "×", align: "right", render: (r) => multiplier(r.multiplier) }, { key: "roundId", header: "Round", mono: true, render: (r) => {r.roundId} }, ]; export default function AdminDashboardPage() { const q = useAdminQuery("/api/admin/dashboard", { refreshMs: 30_000 }); const d = q.data; return ( <> void q.refresh()} loading={q.refreshing} />} /> {q.error && !d ? ( void q.refresh()} /> ) : !d ? (
) : (
{compact(d.users.dau)} / {compact(d.users.wau)} / {compact(d.users.mau)}} sub="Distinct players with rounds" /> 1.02 || d.today.effectiveRtp < 0.9 ? "danger" : "success"} sub="won ÷ wagered" /> } /> 250 ? "danger" : "neutral"} /> 0 ? "danger" : "success"} sub="Last 24 h" icon={} />
All analytics →}> r.slug} dense empty="No rounds recorded in the last 7 days." /> r.roundId} dense empty="No rounds yet." />
} label="DB latency" value={d.health.dbLatencyMs < 0 ? "down" : ms(d.health.dbLatencyMs)} tone={d.health.dbLatencyMs < 0 ? "danger" : d.health.dbLatencyMs > 50 ? "warn" : "ok"} /> } label="High-severity 24 h" value={int(d.health.highSeverityEvents24h)} tone={d.health.highSeverityEvents24h > 0 ? "danger" : "ok"} /> } label="Uptime" value={duration(d.health.uptimeSec)} tone="ok" /> v{d.health.version}} /> {d.health.node}} />
)} ); } function HealthCell({ icon, label, value, tone }: { icon?: React.ReactNode; label: string; value: React.ReactNode; tone?: "ok" | "warn" | "danger" }) { return (
{tone ? : }
{icon} {label}
{value}
); }