import React, { useMemo } from 'react'; import { Bar, CartesianGrid, ComposedChart, Legend, Line, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts'; import type { ChickenWeight } from '../../types/api.ts'; import { formatDateId } from '../../utils/format.ts'; import { formatWeight, getTargetGainForAge } from '../../utils/weight.ts'; interface DailyWeightGainChartProps { rows: ChickenWeight[]; docWeight: number; } type GainStatus = 'above' | 'near' | 'below' | 'none'; type ChartPoint = { day: number; date: string; gain: number | null; targetGain: number | null; status: GainStatus; }; const DailyWeightGainChart: React.FC = ({ rows, docWeight }) => { const chartData = useMemo( () => [...rows].reverse().map((row) => { const targetGain = getTargetGainForAge(row.age, docWeight); const gain = row.average_daily_gain; let status: GainStatus = 'none'; if (gain != null && targetGain != null) { const threshold = Math.abs(targetGain) * 0.1; if (gain >= targetGain + threshold) status = 'above'; else if (gain >= targetGain - threshold) status = 'near'; else status = 'below'; } return { day: row.age, date: row.date, gain, targetGain, status }; }), [rows, docWeight] ); const hasNoData = chartData.length === 0; const CustomLegend = () => (
Pertumbuhan Aktual
Target Pertumbuhan
); const CustomTooltip = ({ active, payload, }: { active?: boolean; payload?: Array<{ payload: ChartPoint }>; }) => { if (!active || !payload?.length) return null; const point = payload[0]?.payload; if (!point || point.gain == null) return null; const hasTarget = point.targetGain != null; const gainDiff = hasTarget ? point.gain - point.targetGain! : null; return (

Hari ke-{point.day}

{formatDateId(point.date)}

Pertumbuhan Aktual:{' '} {formatWeight(point.gain, { stripTrailingZeros: true })}

{hasTarget ? ( <>

Target Pertumbuhan:{' '} {formatWeight(point.targetGain!, { stripTrailingZeros: true })}

Selisih:{' '} = 0 ? 'text-green-600' : 'text-orange-600'}> {gainDiff! >= 0 ? '+' : ''} {formatWeight(Math.abs(gainDiff!), { stripTrailingZeros: true })}

Status:{' '} {point.status === 'above' ? 'Di Atas Target' : point.status === 'near' ? 'Mendekati Target' : 'Di Bawah Target'}

) : (

Target:{' '} Belum ada data standar

)}
); }; return (

Grafik Kenaikan Berat Harian

{hasNoData ? (

Tidak ada data tersedia

Data pertumbuhan belum tersedia

) : ( formatWeight(value, { stripTrailingZeros: true })} /> } /> } /> )}
); }; export default DailyWeightGainChart;