'use client'; import { useEffect, useState } from 'react'; import dynamic from 'next/dynamic'; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { useTheme } from "next-themes"; import { ExternalLink } from "lucide-react"; import Link from "next/link"; // Import ApexCharts secara dinamis untuk menghindari masalah SSR const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); interface MahasiswaStatistik { tahun_angkatan: number; total_mahasiswa: number; pria: number; wanita: number; } interface StatistikMahasiswaChartProps { height?: string; showDetailButton?: boolean; } export default function StatistikMahasiswaChart({ height = "h-[300px] sm:h-[350px] md:h-[300px]", showDetailButton = true }: StatistikMahasiswaChartProps) { const { theme } = useTheme(); const [statistikData, setStatistikData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [chartOptions, setChartOptions] = useState({ chart: { type: 'bar' as const, stacked: true, toolbar: { show: true, tools: { download: true, selection: true, zoom: true, zoomin: true, zoomout: true, pan: true, reset: true }, }, zoom: { enabled: true, type: 'x' as const, autoScaleYaxis: true }, }, markers: { size: 10, shape: 'circle' as const, strokeWidth: 0, hover: { size: 10 } }, plotOptions: { bar: { horizontal: false, columnWidth: '55%', }, }, dataLabels: { enabled: true, formatter: function (val: number, opts: any) { const seriesIndex = opts.seriesIndex; const dataPointIndex = opts.dataPointIndex; // Hitung total dari Laki-laki (index 0) dan Perempuan (index 1) const lakiLakiData = opts.w.config.series[0]?.data || []; const perempuanData = opts.w.config.series[1]?.data || []; const totalValue = (lakiLakiData[dataPointIndex] || 0) + (perempuanData[dataPointIndex] || 0); if (totalValue === 0 || val === 0) return '0%'; const percentage = ((val / totalValue) * 100).toFixed(1); return percentage + '%'; }, position: 'top', style: { fontSize: '12px', colors: ['#000'] }, }, stroke: { show: true, width: 2, colors: ['transparent', 'transparent'], curve: 'straight' as const }, xaxis: { categories: [] as number[], title: { text: 'Tahun Angkatan', style: { fontSize: '14px', fontWeight: 'bold', color: '#000' } }, labels: { style: { fontSize: '12px', colors: '#000' } } }, yaxis: [ { title: { text: 'Jumlah Mahasiswa', style: { fontSize: '14px', fontWeight: 'bold', color: '#000' } }, labels: { style: { fontSize: '12px', colors: '#000' } }, min:0, tickAmount: 5 } ], fill: { opacity: 1 }, legend: { position: 'top' as const, fontSize: '14px', markers: { size: 12, }, itemMargin: { horizontal: 10, }, labels: { colors: '#000' } }, colors: ['#3B82F6', '#EC4899'], tooltip: { theme: 'light', shared: true, intersect: false, custom: function({ series, seriesIndex, dataPointIndex, w }: any) { const lakiLaki = series[0][dataPointIndex]; const perempuan = series[1][dataPointIndex]; const total = lakiLaki + perempuan; const tahun = w.globals.labels[dataPointIndex]; return `
Angkatan ${tahun}
Laki-laki ${lakiLaki}
Perempuan ${perempuan}
Total ${total}
`; } } }); useEffect(() => { const fetchData = async () => { try { const statistikResponse = await fetch('/api/mahasiswa/statistik', { cache: 'no-store', }); if (!statistikResponse.ok) { throw new Error('Failed to fetch statistik data'); } const statistikData = await statistikResponse.json(); setStatistikData(statistikData); } catch (err) { setError(err instanceof Error ? err.message : 'Terjadi kesalahan'); console.error('Error fetching data:', err); } finally { setLoading(false); } }; fetchData(); }, []); // Perbarui tema saat berubah useEffect(() => { const currentTheme = theme; const textColor = currentTheme === 'dark' ? '#fff' : '#000'; const tooltipTheme = currentTheme === 'dark' ? 'dark' : 'light'; setChartOptions(prev => ({ ...prev, chart: { ...prev.chart, background: currentTheme === 'dark' ? '#0F172B' : '#fff', }, dataLabels: { ...prev.dataLabels, formatter: function (val: number, opts: any) { const dataPointIndex = opts.dataPointIndex; const lakiLakiData = opts.w.config.series[0]?.data || []; const perempuanData = opts.w.config.series[1]?.data || []; const totalValue = (lakiLakiData[dataPointIndex] || 0) + (perempuanData[dataPointIndex] || 0); if (totalValue === 0 || val === 0) return '0%'; const percentage = ((val / totalValue) * 100).toFixed(0); return percentage + '%'; }, style: { ...prev.dataLabels.style, colors: [textColor] }, }, xaxis: { ...prev.xaxis, title: { ...prev.xaxis.title, style: { ...prev.xaxis.title.style, color: textColor } }, labels: { ...prev.xaxis.labels, style: { ...prev.xaxis.labels.style, colors: textColor } } }, yaxis: [ { ...prev.yaxis[0], title: { ...prev.yaxis[0].title, style: { ...prev.yaxis[0].title.style, color: textColor } }, labels: { ...prev.yaxis[0].labels, style: { ...prev.yaxis[0].labels.style, colors: textColor } } } ], legend: { ...prev.legend, labels: { ...prev.legend.labels, colors: textColor } }, tooltip: { ...prev.tooltip, theme: tooltipTheme, custom: function({ series, seriesIndex, dataPointIndex, w }: any) { const lakiLaki = series[0][dataPointIndex]; const perempuan = series[1][dataPointIndex]; const total = lakiLaki + perempuan; const tahun = w.globals.labels[dataPointIndex]; const isDark = currentTheme === 'dark'; return `
Angkatan ${tahun}
Laki-laki ${lakiLaki}
Perempuan ${perempuan}
Total ${total}
`; } } })); }, [theme]); // Perbarui kategori saat data berubah useEffect(() => { if (statistikData.length > 0) { setChartOptions(prev => ({ ...prev, xaxis: { ...prev.xaxis, categories: statistikData.map(item => item.tahun_angkatan) }, yaxis: [ { ...prev.yaxis[0], } ] })); } }, [statistikData]); const chartSeries = [ { name: 'Laki-laki', type: 'bar' as const, data: statistikData.map(item => item.pria) }, { name: 'Perempuan', type: 'bar' as const, data: statistikData.map(item => item.wanita) } ]; if (loading) { return ( Loading... ); } if (error) { return ( Error: {error} ); } return (
Persentase Jumlah Mahasiswa Berdasarkan Gender dan Tahun Angkatan {showDetailButton && ( )}
); }