/** * Margin — the ledger, per block and in total. * * The table scrolls inside its own pane on narrow screens rather than making * the page scroll sideways; a card list would lose the column comparison that * is the entire value of this view. */ import { useQuery } from '@tanstack/react-query'; import { compactNumber, get, money, moneyExact, percent } from '@/lib/api'; import { Card, CardContent, CardHeader, CardTitle, EmptyState, Skeleton, Stat } from '@/components/ui'; interface MarginReport { totals: { committedGpuHours: number; allocatedGpuHours: number; idleGpuHours: number; utilisation: number; costCents: number; revenueCents: number; grossMarginCents: number; grossMarginPct: number | null; marginPerAllocatedGpuHourCents: number | null; }; blocks: { commitmentId: string; name: string; gpuType: string; gpuCount: number; totalGpuHours: number; soldGpuHours: number; availableGpuHours: number; costPerGpuHourCents: number; utilisation: number; breakEvenPriceCents: number | null; }[]; } export function Margin() { const { data, isLoading } = useQuery({ queryKey: ['margin'], queryFn: () => get('/api/capacity/margin'), }); if (isLoading) return ; if (!data || data.blocks.length === 0) { return ( ); } const t = data.totals; return (

Margin

Revenue from what we sold, against the full cost of what we bought.

= 0 ? 'positive' : 'danger'} />
By commitment
{data.blocks.map((block) => ( ))}
Commitment Sold Free Utilisation Cost/hr Break even
{block.name}
{block.gpuCount}× {block.gpuType}
{compactNumber(block.soldGpuHours)} {compactNumber(block.availableGpuHours)} {percent(block.utilisation)} {moneyExact(block.costPerGpuHourCents)} {block.breakEvenPriceCents == null ? '—' : moneyExact(block.breakEvenPriceCents)}
); }