40 lines
1.3 KiB
TypeScript
40 lines
1.3 KiB
TypeScript
|
|
'use client';
|
|||
|
|
|
|||
|
|
/* KpiCardMobile — phase 03 (DASH-01).
|
|||
|
|
*
|
|||
|
|
* Phone-sized KPI card for the 2×2 dashboard grid. Renders a label,
|
|||
|
|
* a large numeric value, and an optional caption. tone="attention"
|
|||
|
|
* adds a left-edge destructive border for SLA breaches > 0.
|
|||
|
|
*
|
|||
|
|
* Pure presentational — no fetch, no state. Parent provides values. */
|
|||
|
|
|
|||
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|||
|
|
import { cn } from '@/lib/utils';
|
|||
|
|
|
|||
|
|
export type KpiTone = 'default' | 'attention';
|
|||
|
|
|
|||
|
|
interface KpiCardMobileProps {
|
|||
|
|
label: string;
|
|||
|
|
value: number | string;
|
|||
|
|
caption?: string;
|
|||
|
|
tone?: KpiTone;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const TONE_BORDER: Record<KpiTone, string> = {
|
|||
|
|
default: 'border-l-transparent',
|
|||
|
|
attention: 'border-l-destructive',
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export function KpiCardMobile({ label, value, caption, tone = 'default' }: KpiCardMobileProps) {
|
|||
|
|
const display = typeof value === 'number' ? value.toLocaleString() : value;
|
|||
|
|
return (
|
|||
|
|
<Card className={cn('h-full border-l-2', TONE_BORDER[tone])}>
|
|||
|
|
<CardContent className="p-4 flex flex-col gap-1">
|
|||
|
|
<p className="text-[11px] font-semibold text-muted-foreground uppercase tracking-wider">{label}</p>
|
|||
|
|
<p className="text-3xl font-bold tabular-nums">{display}</p>
|
|||
|
|
{caption && <p className="text-xs text-muted-foreground">{caption}</p>}
|
|||
|
|
</CardContent>
|
|||
|
|
</Card>
|
|||
|
|
);
|
|||
|
|
}
|