'use client' import { useState, useMemo } from 'react' import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, LineChart, Line, Area, AreaChart, } from 'recharts' import { TrendingUp, TrendingDown, Minus, BarChart2, Activity, Percent } from 'lucide-react' interface RawData { status_stunting: boolean tanggal_upload: string nama_posyandu: string } interface Props { data: RawData[] availableYears: number[] } const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Ags', 'Sep', 'Okt', 'Nov', 'Des'] const CustomTooltip = ({ active, payload, label }: any) => { if (active && payload && payload.length) { const stunting = payload.find((p: any) => p.dataKey === 'stunting')?.value ?? 0 const normal = payload.find((p: any) => p.dataKey === 'normal')?.value ?? 0 const total = stunting + normal const pct = total > 0 ? ((stunting / total) * 100).toFixed(1) : '0.0' return (

{label}

Stunting {stunting}
Normal {normal}
Prevalensi {pct}%
) } return null } export function StuntingChart({ data, availableYears }: Props) { const [selectedYear, setSelectedYear] = useState(availableYears[availableYears.length - 1] ?? 2026) const [chartType, setChartType] = useState<'bar' | 'area'>('bar') const [selectedPosyandu, setSelectedPosyandu] = useState('all') const posyanduList = useMemo(() => { return Array.from(new Set(data.map(d => d.nama_posyandu).filter(Boolean))).sort() }, [data]) const filteredData = useMemo(() => { if (selectedPosyandu === 'all') return data return data.filter(d => d.nama_posyandu === selectedPosyandu) }, [data, selectedPosyandu]) const chartData = useMemo(() => { return MONTHS.map((month, idx) => { const monthNum = idx + 1 const filtered = filteredData.filter(d => { if (!d.tanggal_upload) return false const date = new Date(d.tanggal_upload) return date.getFullYear() === selectedYear && date.getMonth() + 1 === monthNum }) const stunting = filtered.filter(d => d.status_stunting === true).length const normal = filtered.filter(d => d.status_stunting === false).length const total = stunting + normal const prevalensi = total > 0 ? parseFloat(((stunting / total) * 100).toFixed(1)) : 0 return { month, stunting, normal, total, prevalensi } }) }, [filteredData, selectedYear]) const totalStunting = chartData.reduce((s, d) => s + d.stunting, 0) const totalNormal = chartData.reduce((s, d) => s + d.normal, 0) const totalAll = totalStunting + totalNormal const prevalensiTotal = totalAll > 0 ? ((totalStunting / totalAll) * 100).toFixed(1) : '0.0' const prevYearData = filteredData.filter(d => { if (!d.tanggal_upload) return false return new Date(d.tanggal_upload).getFullYear() === selectedYear - 1 }) const prevStunting = prevYearData.filter(d => d.status_stunting === true).length const prevAll = prevYearData.length const hasPrevData = prevAll > 0 const prevPrevalensi = hasPrevData ? (prevStunting / prevAll) * 100 : null const currPrevalensiNum = totalAll > 0 ? (totalStunting / totalAll) * 100 : null const trend = hasPrevData && currPrevalensiNum !== null ? currPrevalensiNum > prevPrevalensi! ? 'up' : currPrevalensiNum < prevPrevalensi! ? 'down' : 'stable' : null return (

{selectedPosyandu === 'all' ? 'Data Tren Stunting Wilayah' : `Tren Stunting — ${selectedPosyandu}`}

Pantau statistik prevalensi stunting untuk memahami kondisi kesehatan anak di daerah Anda.

Periode:
Posyandu:

Total Pemeriksaan

{totalAll}

data balita

Stunting

{totalStunting}

kasus

Normal

{totalNormal}

anak

Prevalensi

{prevalensiTotal}%

{trend !== null && (
{trend === 'up' && <>Naik vs {selectedYear - 1}} {trend === 'down' && <>Turun vs {selectedYear - 1}} {trend === 'stable' && <>Stabil}
)}

Statistik Pertumbuhan Anak — {selectedYear}

Perbandingan Balita Stunting & Normal

{totalAll === 0 ? (

Data belum tersedia untuk tahun {selectedYear}

) : ( {chartType === 'bar' ? ( } cursor={{ fill: '#f8fafc' }} /> ) : ( } /> )} )}

Prevalensi Bulanan (%)

Ambang Batas Keamanan WHO: 20%

{totalAll === 0 ? (

Belum ada data prevalensi

) : ( { if (active && payload && payload.length) { const val = payload[0].value as number return (

{label} {selectedYear}

= 20 ? 'bg-red-500' : 'bg-emerald-500'}`} /> {val}%

{val >= 20 ? '🛑 Tinggi' : '✅ Aman'}

) } return null }} /> ( = 20 ? '#ef4444' : '#10b981'} stroke="white" strokeWidth={2} /> )} />
)}
) }