FinSight / frontend /src /components /ui /MetricCard.tsx
Sanjam19's picture
Deploy FinSight demo (single-container Docker Space)
d4f8959 verified
Raw
History Blame Contribute Delete
1.7 kB
import type { MetricValue } from '../../types/api';
import { ConfidenceBadge } from './ConfidenceBadge';
interface Props {
label: string;
value: MetricValue;
}
function formatLabel(key: string): string {
return key
.replace(/_/g, ' ')
.replace(/\b\w/g, (c) => c.toUpperCase());
}
function formatValue(v: number | string | null): string {
if (v === null || v === undefined) return '—';
if (typeof v === 'number') {
if (Math.abs(v) >= 1_000_000_000)
return `$${(v / 1_000_000_000).toFixed(2)}B`;
if (Math.abs(v) >= 1_000_000)
return `$${(v / 1_000_000).toFixed(2)}M`;
if (Math.abs(v) >= 1_000)
return v.toLocaleString();
// likely a ratio
return v.toFixed(2);
}
return String(v);
}
export function MetricCard({ label, value }: Props) {
const isObject = value !== null && typeof value === 'object';
if (!isObject) {
// plain number
return (
<div className="metric-card">
<span className="metric-card__label">{formatLabel(label)}</span>
<span className="metric-card__value">{formatValue(value as number | null)}</span>
</div>
);
}
const { value: v, confidence, needs_clarification } = value;
return (
<div className={`metric-card ${needs_clarification ? 'metric-card--flagged' : ''}`}>
<span className="metric-card__label">{formatLabel(label)}</span>
<span className="metric-card__value">{formatValue(v)}</span>
<div className="metric-card__meta">
<ConfidenceBadge confidence={confidence} />
{needs_clarification && (
<span className="metric-card__clarify" title="Needs clarification"></span>
)}
</div>
</div>
);
}