'use client'; import { useEffect, useState } from 'react'; import dynamic from 'next/dynamic'; import { ApexOptions } from 'apexcharts'; import { useTheme } from 'next-themes'; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; 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 BimbinganDosenData { id_dosen: number; nama_dosen: string; selesai: number; belum_selesai: number; total: number; } interface BimbinganDosenChartProps { height?: string; showDetailButton?: boolean; } export default function BimbinganDosenChart({ height = "h-[400px] sm:h-[450px] md:h-[500px] lg:h-[600px]", showDetailButton = true }: BimbinganDosenChartProps = {}) { const { theme } = useTheme(); const [mounted, setMounted] = useState(false); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [data, setData] = useState([]); const [series, setSeries] = useState([ { name: 'Selesai', data: [] }, { name: 'Belum Selesai', data: [] } ]); const [options, setOptions] = useState({ chart: { type: 'bar', stacked: true, toolbar: { show: true, }, }, plotOptions: { bar: { horizontal: true, columnWidth: '85%', distributed: false, barHeight: '90%', dataLabels: { position: 'center', }, }, }, dataLabels: { enabled: true, formatter: function (val: number) { return val > 0 ? val.toString() : ''; }, style: { fontSize: '12px', colors: [theme === 'dark' ? '#fff' : '#000'] }, }, stroke: { show: true, width: 1, colors: [theme === 'dark' ? '#374151' : '#E5E7EB'], }, xaxis: { categories: [], title: { text: 'Jumlah Bimbingan', style: { fontSize: '14px', fontWeight: 'bold', color: theme === 'dark' ? '#fff' : '#000' } }, labels: { style: { fontSize: '12px', colors: theme === 'dark' ? '#fff' : '#000' } } }, yaxis: { title: { text: 'Nama Dosen', style: { fontSize: '14px', fontWeight: 'bold', color: theme === 'dark' ? '#fff' : '#000' } }, labels: { style: { fontSize: '14px', colors: theme === 'dark' ? '#fff' : '#000' }, maxWidth: 200, }, }, legend: { position: 'top', fontSize: '14px', markers: { size: 12, }, itemMargin: { horizontal: 10, }, horizontalAlign: 'center', labels: { colors: theme === 'dark' ? '#fff' : '#000' } }, fill: { opacity: 1, }, colors: ['#10B981', '#F59E0B'], // Hijau untuk Selesai, Kuning untuk Belum Selesai tooltip: { theme: theme === 'dark' ? 'dark' : 'light', shared: true, intersect: false, custom: function({ series, seriesIndex, dataPointIndex, w }: any) { const dosen = w.globals.labels[dataPointIndex]; const isDark = theme === 'dark'; // Hitung total untuk dosen ini let total = 0; series.forEach((seriesData: number[]) => { total += seriesData[dataPointIndex] || 0; }); const statusNames = ['Selesai', 'Belum Selesai']; const statusColors = ['#10B981', '#F59E0B']; let tooltipContent = `
${dosen}
`; // Tambahkan setiap status series.forEach((seriesData: number[], index: number) => { const value = seriesData[dataPointIndex] || 0; tooltipContent += `
${statusNames[index]} ${value}
`; }); // Tambahkan total tooltipContent += `
Total ${total}
`; return tooltipContent; } } }); // Perbarui tema saat berubah useEffect(() => { setOptions(prev => ({ ...prev, chart: { ...prev.chart, background: theme === 'dark' ? '#0F172B' : '#fff', }, dataLabels: { ...prev.dataLabels, style: { ...prev.dataLabels?.style, colors: [theme === 'dark' ? '#fff' : '#000'] } }, xaxis: { ...prev.xaxis, title: { ...prev.xaxis?.title, style: { ...prev.xaxis?.title?.style, color: theme === 'dark' ? '#fff' : '#000' } }, labels: { ...prev.xaxis?.labels, style: { ...prev.xaxis?.labels?.style, colors: theme === 'dark' ? '#fff' : '#000' } } }, yaxis: { ...prev.yaxis, title: { ...(Array.isArray(prev.yaxis) ? prev.yaxis[0]?.title : prev.yaxis?.title), style: { ...(Array.isArray(prev.yaxis) ? prev.yaxis[0]?.title?.style : prev.yaxis?.title?.style), color: theme === 'dark' ? '#fff' : '#000' } }, labels: { ...(Array.isArray(prev.yaxis) ? prev.yaxis[0]?.labels : prev.yaxis?.labels), style: { ...(Array.isArray(prev.yaxis) ? prev.yaxis[0]?.labels?.style : prev.yaxis?.labels?.style), colors: theme === 'dark' ? '#fff' : '#000' } } }, legend: { ...prev.legend, labels: { ...prev.legend?.labels, colors: theme === 'dark' ? '#fff' : '#000' } }, tooltip: { ...prev.tooltip, theme: theme === 'dark' ? 'dark' : 'light' } })); }, [theme]); useEffect(() => { setMounted(true); }, []); useEffect(() => { const fetchData = async () => { try { setLoading(true); setError(null); const response = await fetch('/api/mahasiswa/bimbingan-dosen'); if (!response.ok) { throw new Error(`Failed to fetch data: ${response.status} ${response.statusText}`); } const result = await response.json(); if (!Array.isArray(result)) { throw new Error('Format data tidak valid diterima dari server'); } // Urutkan data berdasarkan kategori "Belum Selesai" dari terbanyak ke terkecil const sortedResult = result.sort((a, b) => b.belum_selesai - a.belum_selesai); setData(sortedResult); // Proses data untuk chart const namaDosen = sortedResult.map(item => item.nama_dosen); const selesaiData = sortedResult.map(item => item.selesai); const belumSelesaiData = sortedResult.map(item => item.belum_selesai); setSeries([ { name: 'Selesai', data: selesaiData }, { name: 'Belum Selesai', data: belumSelesaiData } ]); setOptions(prev => ({ ...prev, xaxis: { ...prev.xaxis, categories: namaDosen, }, })); } catch (err) { console.error('Error in fetchData:', err); setError(err instanceof Error ? err.message : 'Terjadi kesalahan saat mengambil data'); } finally { setLoading(false); } }; fetchData(); }, []); if (!mounted) { return null; } if (loading) { return ( Loading... ); } if (error) { return ( Error: {error} ); } if (data.length === 0) { return ( Tidak ada data bimbingan yang tersedia ); } // Hitung tinggi dinamis berdasarkan jumlah dosen const calculateHeight = () => { const minHeight = 200; const barHeight = 25; // Tinggi per bar dalam piksel const padding = 100; // Ruang ekstra untuk judul, legenda, dll const dynamicHeight = Math.max(minHeight, (data.length * barHeight) + padding); return `${dynamicHeight}px`; }; return (
Jumlah Bimbingan Dosen Berdasarkan Nama Dosen dan Status Bimbingan {showDetailButton && ( )}
); }