'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[0] ?? 2026) const [chartType, setChartType] = useState<'bar' | 'area'>('bar') const [selectedPosyandu, setSelectedPosyandu] = useState('all') // Unique posyandu list const posyanduList = useMemo(() => { return Array.from(new Set(data.map(d => d.nama_posyandu).filter(Boolean))).sort() }, [data]) // Active data after posyandu filter const filteredData = useMemo(() => { if (selectedPosyandu === 'all') return data return data.filter(d => d.nama_posyandu === selectedPosyandu) }, [data, selectedPosyandu]) // Process data for the selected year into 12 months 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]) // Summary stats for selected year 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' // Trend: compare current year vs previous year prevalensi const prevYearTotal = filteredData.filter(d => { if (!d.tanggal_upload) return false return new Date(d.tanggal_upload).getFullYear() === selectedYear - 1 }) const prevStunting = prevYearTotal.filter(d => d.status_stunting === true).length const prevAll = prevYearTotal.length const hasPrevData = prevAll > 0 const prevPrevalensi = hasPrevData ? (prevStunting / prevAll) * 100 : null const currPrevalensiNum = totalAll > 0 ? (totalStunting / totalAll) * 100 : null const trend: 'up' | 'down' | 'stable' | null = hasPrevData && currPrevalensiNum !== null ? currPrevalensiNum > prevPrevalensi! ? 'up' : currPrevalensiNum < prevPrevalensi! ? 'down' : 'stable' : null return (
{/* Dynamic Card Title */}

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

{selectedPosyandu === 'all' ? 'Menampilkan data dari semua posyandu · Pilih posyandu untuk melihat per lokasi' : `Filter aktif: ${selectedPosyandu} · Pilih "Semua Posyandu" untuk melihat keseluruhan`}

{/* Controls Row */}
{/* Filters */}
{/* Year Filter */}
Periode:
{/* Posyandu Filter */}
Posyandu:
{/* Chart Type Toggle */}
{/* Stats Row */}
{/* Total Data */}

Total Data

{totalAll}

pemeriksaan

{/* Stunting */}

Stunting

{totalStunting}

kasus

{/* Normal */}

Normal

{totalNormal}

anak

{/* Prevalensi */}

Prevalensi

{prevalensiTotal}%

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

Tren Stunting Semua Posyandu — {selectedYear}

Berdasarkan tanggal upload data

{totalAll === 0 ? (

Tidak ada data untuk tahun {selectedYear}

) : ( {chartType === 'bar' ? ( } /> val === 'stunting' ? 'Stunting' : 'Normal'} /> ) : ( } /> val === 'stunting' ? 'Stunting' : 'Normal'} /> )} )}
{/* Prevalensi (%) Line Chart */}

Prevalensi Stunting Per Bulan (%) — {selectedYear}

Persentase kasus stunting dari total pemeriksaan per bulan

{totalAll === 0 ? (

Tidak ada data untuk ditampilkan

) : ( `${v}%`} domain={[0, 100]} /> { if (active && payload && payload.length) { const val = payload[0]?.value as number return (

{label}

Prevalensi: = 20 ? 'text-red-600' : 'text-emerald-600'}`}>{val}%

{val >= 20 ? '⚠️ Di atas ambang batas (20%)' : '✓ Di bawah ambang batas (20%)'}

) } return null }} /> {/* Reference line 20% */} ( = 20 ? '#ef4444' : '#10b981'} stroke="white" strokeWidth={2} /> )} activeDot={{ r: 7, stroke: '#f59e0b', strokeWidth: 2 }} />
)}

● Merah = prevalensi ≥ 20% (tinggi)  |  ● Hijau = prevalensi < 20% (aman)

Bulan Total Stunting Normal Prevalensi
{chartData.map((row, idx) => (
{row.month} {selectedYear} {row.total} {row.stunting} {row.normal} {row.total > 0 ? ( = 20 ? 'bg-red-50 border-red-200 text-red-700' : 'bg-emerald-50 border-emerald-200 text-emerald-700' }`}> {row.prevalensi}% ) : ( )}
))}
) }