import React, { useMemo } from 'react'; import { Line, LineChart, ResponsiveContainer, Tooltip, XAxis } from 'recharts'; import { formatNumber, formatRatio } from '../utils/format.ts'; import type { View } from '../types/common.ts'; export type KpiStatus = 'ok' | 'warning' | 'critical' | 'na'; export type KpiTrendPoint = { value: number; /** Tooltip label, e.g. ``Hari 0 ยท 2 Sep 2026``. */ label: string; }; export type KpiCardModel = { key: string; title: string; value: number | null; unit: string; icon: string; trend?: KpiTrendPoint[]; status: KpiStatus; targetView?: View; }; const statusStyles: Record = { ok: { bg: 'bg-green-100', text: 'text-green-800', icon: 'text-green-600', line: '#16a34a' }, warning: { bg: 'bg-yellow-100', text: 'text-yellow-800', icon: 'text-yellow-600', line: '#f59e0b', }, critical: { bg: 'bg-red-100', text: 'text-red-800', icon: 'text-red-600', line: '#dc2626' }, na: { bg: 'bg-blue-50', text: 'text-blue-900', icon: 'text-blue-600', line: '#3b82f6' }, }; type Props = Omit & { onClick?: () => void; isLoading?: boolean; }; const KpiCard: React.FC = ({ title, value, unit, icon, trend, status, onClick, isLoading = false, }) => { const isNA = value === null; const styles = isNA ? statusStyles.na : statusStyles[status]; const trendData = useMemo( () => (trend ?? []).map((point) => ({ name: point.label, value: point.value })), [trend] ); const displayValue = () => { if (value === null) return 'N/A'; if (title.toUpperCase().includes('FCR') || title.toUpperCase().includes('EEF')) { return formatRatio(value, 3); } if (unit === 'gram' && value > 999) return formatNumber(value / 1000, 2); return formatNumber(value, 2); }; const displayUnit = () => { if (value !== null && unit === 'gram' && value > 999) return 'kg'; return unit; }; return (
{isLoading ? ( Memuat... ) : ( <> {displayValue()}{' '} {!isNA && {displayUnit()}} )}

{title}

{icon}
{!isNA && trendData.length > 0 ? ( [formatNumber(Number(val ?? 0), 2), title]} labelFormatter={(label) => String(label ?? '')} contentStyle={{ fontSize: 12, borderRadius: 8 }} /> ) : (
{isNA ? 'Data tidak tersedia' : ''}
)}
); }; export default KpiCard;