import { useBillingHealth, type BillingHealthSummary } from '@szl-holdings/billing-client'; import { AlertTriangle, CreditCard, DollarSign, FileText, RefreshCw, RotateCcw, } from 'lucide-react'; import { Link } from 'wouter'; function isDemoMode(): boolean { try { const env = (import.meta as unknown as { env?: Record }).env; return env?.VITE_BILLING_DEMO_MODE === 'true' || env?.VITE_BILLING_DEMO_MODE === true; } catch { return false; } } function fmtCurrency(cents: number, currency = 'usd'): string { return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency.toUpperCase(), maximumFractionDigits: 0, }).format(cents / 100); } interface MetricChipProps { icon: React.ElementType; label: string; value: string | number; accent?: string; alert?: boolean; } function MetricChip({ icon: Icon, label, value, accent = '#d4a054', alert = false }: MetricChipProps) { return (
{label}
{value}
); } export function BillingHealthCard() { const { data: health, loading, error, refetch } = useBillingHealth(); // Demo badge ONLY when explicitly opted in via the env flag, OR the API // hands us back demo fixtures (e.g. when the server side runs without a // live Stripe key and signals it). Live data must never carry the badge. const envDemo = isDemoMode(); const showDemo = envDemo || (health?.demo === true); const summary: BillingHealthSummary | null = health ?? null; return (

Billing Health

{showDemo && ( demo )}
View billing →
{summary ? ( <>
0} /> 0} /> 0} />
{(summary.pastDueCount > 0 || summary.refundQueueDepth > 0) && (
{summary.pastDueCount > 0 && ( {summary.pastDueCount} past-due {summary.pastDueCount === 1 ? 'account requires' : 'accounts require'} attention. )} {summary.refundQueueDepth > 0 && ( {summary.refundQueueDepth} refund {summary.refundQueueDepth === 1 ? 'request' : 'requests'} pending. )}
)} ) : (
{error ? `Billing data unavailable — ${error}` : loading ? 'Loading billing data…' : 'Billing data unavailable — configure the API server to see live metrics.'}
)}
); }