import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useQuery } from "@tanstack/react-query"; import { api, type AdminQuotaRow } from "../lib/api"; import { quotaActionLabel } from "../lib/format"; const RANGES = [7, 30, 90] as const; export default function Stats() { const { t } = useTranslation(); const [days, setDays] = useState(30); const q = useQuery({ queryKey: ["admin-quota", days], queryFn: () => api.adminQuota(days), }); const data = q.data; const maxDaily = Math.max(1, ...(data?.daily ?? []).map((d) => d.total)); const grandTotal = (data?.rows ?? []).reduce((s, r) => s + r.total, 0); return (

{t("stats.title")}

{RANGES.map((d) => ( ))}

{t("stats.introBefore")} {t("stats.introSystem")} {t("stats.introAfter")}

{q.isLoading ? (
{t("stats.loading")}
) : !data ? (
{t("stats.noData")}
) : ( <> {/* Daily totals (instance-wide, Pacific days) */}
{t("stats.dailyTotal", { count: data.range_days, units: grandTotal.toLocaleString(), })}
{data.daily.length === 0 ? (
{t("stats.noUsageInRange")}
) : (
{data.daily.map((d) => ( // Each day gets a full-height track so the column is always visible // (even on near-zero days); the accent fill renders the value on top.
))}
)}
{/* Per-user breakdown */}
{data.rows.length === 0 ? (
{t("stats.noUsageInRange")}
) : ( data.rows.map((r) => ( )) )}
)}
); } function UserRow({ row, max }: { row: AdminQuotaRow; max: number }) { const { t } = useTranslation(); const [open, setOpen] = useState(false); const actions = Object.entries(row.by_action).sort((a, b) => b[1] - a[1]); const isSystem = row.user_id === null; return (
{/* Proportion bar */}
{open && actions.length > 0 && (
{actions.map(([action, units]) => (
{quotaActionLabel(action)} {units.toLocaleString()}
))}
)}
); }