"use client"; import React, { useEffect, useState } from "react"; import { motion } from "framer-motion"; import { Inbox, Send, Layers, HardDrive, Server, ShieldCheck, Globe, RefreshCw, Zap, } from "lucide-react"; import { useTranslations } from "../../../../i18n/provider"; import { Badge } from "../../../../components/ui/Badge"; import { Button } from "../../../../components/ui/Button"; /** Exactly the fields /api/v1/admin/dashboard returns - see dashboardStats(). */ interface DashboardMetrics { inbound_24h: number; outbound_24h: number; queue_depth: number; bounce_rate: number; domains_verified: number; domains_total: number; mailboxes_active: number; storage_used_bytes: number; storage_quota_bytes: number; } function formatBytes(bytes: number): string { if (!bytes) return "0 B"; const units = ["B", "KB", "MB", "GB", "TB"]; const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1); return `${(bytes / 1024 ** i).toFixed(i === 0 ? 0 : 1)} ${units[i]}`; } export default function AdminDashboardPage() { const t = useTranslations(); const [metrics, setMetrics] = useState(null); const [loading, setLoading] = useState(false); const fetchMetrics = () => { setLoading(true); fetch("/api/v1/admin/dashboard") .then((res) => (res.ok ? res.json() : null)) .then((data) => setMetrics(data)) .catch(() => setMetrics(null)) .finally(() => setLoading(false)); }; useEffect(() => { fetchMetrics(); }, []); /** * A missing figure reads as "no data", never as a number. * * Each of these used to fall back to an invented constant - 1420 received, * 890 sent, 3 queued, 18.4% disk - so an unreachable API produced a dashboard * of plausible traffic for a server that might not have delivered a single * message. Two of those fields (disk_used_percent, spam_score_avg) were never * returned by the endpoint at all, so the fake disk figure was what everyone * always saw. */ const shown = (value: number | undefined, format?: (n: number) => string) => value === undefined || value === null ? t("ui.noData") : format ? format(value) : String(value); /* The KPI tiles no longer each carry their own hue. Four colours across four numbers implied four kinds of thing; they are all just counts, and the one accent marks the icon. */ const kpis = [ { title: t("ui.inboundVolume"), value: shown(metrics?.inbound_24h), subtext: t("ui.messageVolume"), icon: Inbox, }, { title: t("ui.outboundDelivered"), value: shown(metrics?.outbound_24h), subtext: t("ui.daneVerified"), icon: Send, }, { title: t("ui.queueDepth"), value: shown(metrics?.queue_depth), subtext: t("ui.postgresRunner"), icon: Layers, }, { title: t("ui.diskUsed"), value: shown(metrics?.storage_used_bytes, formatBytes), subtext: metrics ? `${t("ui.storageQuota")}: ${formatBytes(metrics.storage_quota_bytes)}` : t("ui.localDisk"), icon: HardDrive, }, ]; const panel = "flex flex-col gap-3.5 rounded-2xl bg-dark-panel p-[18px] shadow-edge"; return (
{/* Header Bar */}

{t("admin.dashboardTitle")}

{t("admin.dashboardSubtitle")}

{/* Reports the count it can actually see. The old badge asserted "PREFLIGHT: HEALTHY" from a field the endpoint never sends, so it said healthy unconditionally. The real checks live on the security screen. */} {metrics && ( {t("ui.domainsVerified")}: {metrics.domains_verified}/{metrics.domains_total} )}
{/* KPI Grid */}
{kpis.map((kpi, idx) => { const Icon = kpi.icon; return (
{kpi.title}
{kpi.value}
{kpi.subtext}
); })}
{/* A single card of figures that are genuinely queried. What stood here were two cards of decoration: a "core services" panel that listed SMTP, IMAP, Rspamd and the cert watcher with a hardcoded "Online"/"4/4 active" and a pulsing green dot - nothing was ever polled, so it stayed green through any outage - and a domain panel pinned to "example.com" with "13 RECORDS VERIFIED" and a "last checked: just now" that was a literal string. Container liveness is now covered by the compose healthchecks, and the per-domain DNS state lives on the domains screen, which reads it from the database. */}

{t("ui.domainVerification")}

{metrics ? (
{t("ui.domainsVerified")}
{metrics.domains_verified} / {metrics.domains_total}
{t("ui.mailboxesActive")}
{metrics.mailboxes_active}
{t("ui.bounceRate")}
{(metrics.bounce_rate * 100).toFixed(1)}%
) : (
{t("ui.noData")}
)}
); }