"use client"; import { ArrowDownIcon, ArrowUpIcon } from "lucide-react"; import { useTranslations } from "next-intl"; import { Card, CardContent } from "../../../shadcnui"; import { cn } from "../../../utils"; import type { TokenUsageAdminSummaryInterface } from "../data/tokenusage-admin-summary.interface"; import type { Metric } from "../data/tokenusage-admin.types"; import { useUsageFormatters } from "../lib/formatters"; import { cacheHitPercentage, metricValue, percentageDelta, type TokenUsageMetrics } from "../lib/metrics"; type Props = { /** The six summary rows: {customer, platform, total} × {current, previous}. */ summary: TokenUsageAdminSummaryInterface[]; metric: Metric; /** True when a company filter is applied — platform spend is then meaningless. */ singleCustomerMode: boolean; }; const ZERO: TokenUsageMetrics = { cost: 0, credits: 0, tokensIn: 0, tokensOut: 0, cached: 0, calls: 0 }; /** * The KPI header of the administrative token-usage page. * * Two lead tiles carry the cost centres — customer spend and platform spend — * each with its delta against the equal-length preceding window. Three * supporting tiles below carry the totals that give those two numbers context. * * The backend always returns both windows, which is why no tile has to branch on * a missing row: an absent scope is simply zero-filled here. */ export function TokenUsageAdminTiles({ summary, metric, singleCustomerMode }: Props) { const t = useTranslations(); const { decimal, metricValue: formatValue, currency, percent } = useUsageFormatters(); const rowFor = (scope: string, window: string): TokenUsageMetrics => summary.find((r) => r.scope === scope && r.window === window) ?? ZERO; const customerCurrent = rowFor("customer", "current"); const customerPrevious = rowFor("customer", "previous"); const platformCurrent = rowFor("platform", "current"); const platformPrevious = rowFor("platform", "previous"); const totalCurrent = rowFor("total", "current"); const totalPrevious = rowFor("total", "previous"); const averagePerCall = totalCurrent.calls ? totalCurrent.cost / totalCurrent.calls : 0; const cacheHit = cacheHitPercentage(totalCurrent.cached, totalCurrent.tokensIn); return (
{!singleCustomerMode && ( )}
); } function LeadTile({ testId, label, value, delta, previousLabel, decimal, }: { testId: string; label: string; value: string; delta: number | undefined; previousLabel: string; /** Passed down because `Delta` is a plain function, not a component: it cannot call the hook itself. */ decimal: (value: number, decimals: number) => string; }) { return ( {label} {value} {previousLabel} ); } function SupportingTile({ testId, label, value, delta, decimal, }: { testId: string; label: string; value: string; delta?: number | undefined; /** Passed down because `Delta` is a plain function, not a component: it cannot call the hook itself. */ decimal: (value: number, decimals: number) => string; }) { return ( {label} {value} {delta !== undefined && } ); } /** * The delta slot. An undefined delta means the previous window was zero: an * em dash says "not comparable" where a percentage would say "infinite growth". */ function Delta({ testId, delta, decimal, }: { testId: string; delta: number | undefined; decimal: (value: number, decimals: number) => string; }) { if (delta === undefined) { return ( ); } const increased = delta >= 0; const Icon = increased ? ArrowUpIcon : ArrowDownIcon; return ( {decimal(Math.abs(delta), 0)} % ); }