"use client"; export const dynamic = "force-dynamic"; import { useMemo } from "react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { Area, AreaChart, Bar, BarChart, CartesianGrid, Line, LineChart, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis, } from "recharts"; import { Activity, PenSquare, Timer, Users } from "lucide-react"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import DropdownSelect from "@/components/ui/dropdown-select"; import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; import { ApiError } from "@/api/mutator"; import { type dashboardMetricsApiV1MetricsDashboardGetResponse, useDashboardMetricsApiV1MetricsDashboardGet, } from "@/api/generated/metrics/metrics"; import type { DashboardMetricsApiV1MetricsDashboardGetRangeKey } from "@/api/generated/model/dashboardMetricsApiV1MetricsDashboardGetRangeKey"; import { parseApiDatetime } from "@/lib/datetime"; type RangeKey = DashboardMetricsApiV1MetricsDashboardGetRangeKey; type BucketKey = "hour" | "day" | "week" | "month"; type SeriesPoint = { period: string; value: number; }; type WipPoint = { period: string; inbox: number; in_progress: number; review: number; done: number; }; type RangeSeries = { range: RangeKey; bucket: BucketKey; points: SeriesPoint[]; }; type WipRangeSeries = { range: RangeKey; bucket: BucketKey; points: WipPoint[]; }; const hourFormatter = new Intl.DateTimeFormat("en-US", { hour: "numeric" }); const dayFormatter = new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", }); const monthFormatter = new Intl.DateTimeFormat("en-US", { month: "short", year: "numeric", }); const DASHBOARD_RANGE_OPTIONS: Array<{ value: RangeKey; label: string }> = [ { value: "24h", label: "24 hours" }, { value: "3d", label: "3 days" }, { value: "7d", label: "7 days" }, { value: "14d", label: "14 days" }, { value: "1m", label: "1 month" }, { value: "3m", label: "3 months" }, { value: "6m", label: "6 months" }, { value: "1y", label: "1 year" }, ]; const DASHBOARD_RANGE_SET = new Set( DASHBOARD_RANGE_OPTIONS.map((option) => option.value), ); const DEFAULT_RANGE: RangeKey = "7d"; const formatPeriod = (value: string, bucket: BucketKey) => { const date = parseApiDatetime(value); if (!date) return ""; if (bucket === "hour") return hourFormatter.format(date); if (bucket === "month") return monthFormatter.format(date); return dayFormatter.format(date); }; const formatNumber = (value: number) => value.toLocaleString("en-US"); const formatPercent = (value: number) => `${value.toFixed(1)}%`; const formatHours = (value: number | null) => value === null || !Number.isFinite(value) ? "--" : `${value.toFixed(1)}h`; const calcProgress = (values?: number[]) => { if (!values || values.length === 0) return 0; const max = Math.max(...values); if (!Number.isFinite(max) || max <= 0) return 0; const latest = values[values.length - 1] ?? 0; return Math.max(0, Math.min(100, Math.round((latest / max) * 100))); }; function buildSeries(series: RangeSeries) { return series.points.map((point) => ({ period: formatPeriod(point.period, series.bucket), value: Number(point.value ?? 0), })); } function buildWipSeries(series: WipRangeSeries) { return series.points.map((point) => ({ period: formatPeriod(point.period, series.bucket), inbox: Number(point.inbox ?? 0), in_progress: Number(point.in_progress ?? 0), review: Number(point.review ?? 0), done: Number(point.done ?? 0), })); } function buildSparkline(series: RangeSeries) { return { values: series.points.map((point) => Number(point.value ?? 0)), labels: series.points.map((point) => formatPeriod(point.period, series.bucket), ), bucket: series.bucket, }; } function buildWipSparkline(series: WipRangeSeries, key: keyof WipPoint) { return { values: series.points.map((point) => Number(point[key] ?? 0)), labels: series.points.map((point) => formatPeriod(point.period, series.bucket), ), bucket: series.bucket, }; } type TooltipProps = { active?: boolean; payload?: Array<{ value?: number; name?: string; color?: string }>; label?: string; formatter?: (value: number, name?: string) => string; }; function TooltipCard({ active, payload, label, formatter }: TooltipProps) { if (!active || !payload?.length) return null; return (
{label ?
Period: {label}
: null}
{payload.map((entry, index) => (
{entry.name ?? "Value"} Value: {formatter ? formatter(Number(entry.value ?? 0), entry.name) : entry.value}
))}
); } function KpiCard({ label, value, sublabel, icon, progress = 0, }: { label: string; value: string; sublabel?: string; icon: React.ReactNode; progress?: number; }) { return (

{label}

{icon}

{value}

{sublabel ? (

{sublabel}

) : null}
); } function ChartCard({ title, subtitle, children, }: { title: string; subtitle: string; children: React.ReactNode; }) { return (

{title}

{subtitle}

{children}
); } export default function DashboardPage() { const { isSignedIn } = useAuth(); const pathname = usePathname(); const router = useRouter(); const searchParams = useSearchParams(); const selectedRangeParam = searchParams.get("range"); const selectedRange: RangeKey = selectedRangeParam && DASHBOARD_RANGE_SET.has(selectedRangeParam as RangeKey) ? (selectedRangeParam as RangeKey) : DEFAULT_RANGE; const metricsQuery = useDashboardMetricsApiV1MetricsDashboardGet< dashboardMetricsApiV1MetricsDashboardGetResponse, ApiError >( { range_key: selectedRange }, { query: { enabled: Boolean(isSignedIn), refetchInterval: 15_000, refetchOnMount: "always", }, }, ); const metrics = metricsQuery.data?.status === 200 ? metricsQuery.data.data : null; const throughputSeries = useMemo( () => (metrics ? buildSeries(metrics.throughput.primary) : []), [metrics], ); const cycleSeries = useMemo( () => (metrics ? buildSeries(metrics.cycle_time.primary) : []), [metrics], ); const errorSeries = useMemo( () => (metrics ? buildSeries(metrics.error_rate.primary) : []), [metrics], ); const wipSeries = useMemo( () => (metrics ? buildWipSeries(metrics.wip.primary) : []), [metrics], ); const cycleSpark = useMemo( () => (metrics ? buildSparkline(metrics.cycle_time.primary) : null), [metrics], ); const errorSpark = useMemo( () => (metrics ? buildSparkline(metrics.error_rate.primary) : null), [metrics], ); const wipSpark = useMemo( () => metrics ? buildWipSparkline(metrics.wip.primary, "in_progress") : null, [metrics], ); const activeProgress = useMemo( () => (metrics ? Math.min(100, metrics.kpis.active_agents * 12.5) : 0), [metrics], ); const wipProgress = useMemo(() => calcProgress(wipSpark?.values), [wipSpark]); const errorProgress = useMemo( () => calcProgress(errorSpark?.values), [errorSpark], ); const cycleProgress = useMemo( () => calcProgress(cycleSpark?.values), [cycleSpark], ); return (

Dashboard

Monitor your mission control operations

{ const nextRange = value as RangeKey; const params = new URLSearchParams(searchParams.toString()); params.set("range", nextRange); router.replace(`${pathname}?${params.toString()}`); }} options={DASHBOARD_RANGE_OPTIONS} ariaLabel="Dashboard date range" placeholder="Select range" searchEnabled={false} triggerClassName="h-9 min-w-[150px] rounded-lg border border-slate-300 bg-white px-3 py-1.5 text-sm text-slate-700 shadow-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-100" contentClassName="rounded-lg border border-slate-200" />
{metricsQuery.error ? (
{metricsQuery.error.message}
) : null} {metricsQuery.isLoading && !metrics ? (
Loading dashboard metrics…
) : null} {metrics ? ( <>
} progress={activeProgress} /> } progress={wipProgress} /> } progress={errorProgress} /> } progress={cycleProgress} />
formatNumber(v)} /> } /> `${v.toFixed(1)}h`} /> } /> formatPercent(v)} /> } /> formatNumber(v)} /> } />
) : null}
); }