ayo commit lagi
This commit is contained in:
@@ -26,6 +26,7 @@ export default function JenisPendaftaranPerAngkatanChart({ tahunAngkatan }: Prop
|
|||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [data, setData] = useState<JenisPendaftaranData[]>([]);
|
const [data, setData] = useState<JenisPendaftaranData[]>([]);
|
||||||
const [series, setSeries] = useState<number[]>([]);
|
const [series, setSeries] = useState<number[]>([]);
|
||||||
|
const [chartColors, setChartColors] = useState<string[]>([]);
|
||||||
const [options, setOptions] = useState<ApexOptions>({
|
const [options, setOptions] = useState<ApexOptions>({
|
||||||
chart: {
|
chart: {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
@@ -43,7 +44,7 @@ export default function JenisPendaftaranPerAngkatanChart({ tahunAngkatan }: Prop
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
labels: [],
|
labels: [],
|
||||||
colors: ['#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#06B6D4', '#F97316'],
|
colors: [],
|
||||||
legend: {
|
legend: {
|
||||||
position: 'bottom',
|
position: 'bottom',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
@@ -101,9 +102,11 @@ export default function JenisPendaftaranPerAngkatanChart({ tahunAngkatan }: Prop
|
|||||||
tooltip: {
|
tooltip: {
|
||||||
...prev.tooltip,
|
...prev.tooltip,
|
||||||
theme: theme === 'dark' ? 'dark' : 'light'
|
theme: theme === 'dark' ? 'dark' : 'light'
|
||||||
}
|
},
|
||||||
|
// Preserve computed colors across theme changes
|
||||||
|
colors: chartColors.length > 0 ? chartColors : prev.colors,
|
||||||
}));
|
}));
|
||||||
}, [theme]);
|
}, [theme, chartColors]);
|
||||||
|
|
||||||
// Update dataLabels formatter when data changes
|
// Update dataLabels formatter when data changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -141,29 +144,46 @@ export default function JenisPendaftaranPerAngkatanChart({ tahunAngkatan }: Prop
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
const response = await fetch(`/api/mahasiswa/jenis-pendaftaran?tahun_angkatan=${tahunAngkatan}`);
|
// Fetch year-filtered data and global data in parallel
|
||||||
|
const [response, allResponse] = await Promise.all([
|
||||||
|
fetch(`/api/mahasiswa/jenis-pendaftaran?tahun_angkatan=${tahunAngkatan}`),
|
||||||
|
fetch('/api/mahasiswa/jenis-pendaftaran'),
|
||||||
|
]);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Failed to fetch data: ${response.status} ${response.statusText}`);
|
throw new Error(`Failed to fetch data: ${response.status} ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
const allResult = allResponse.ok ? await allResponse.json() : result;
|
||||||
|
|
||||||
if (!Array.isArray(result)) {
|
if (!Array.isArray(result)) {
|
||||||
throw new Error('Invalid data format received from server');
|
throw new Error('Invalid data format received from server');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build global sorted jenis list (same order as bar chart) for stable color assignment
|
||||||
|
const colorPalette = ['#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#06B6D4', '#F97316'];
|
||||||
|
const allJenis: string[] = [...new Set((allResult as any[]).map(item => item.jenis_pendaftaran as string))].sort() as string[];
|
||||||
|
|
||||||
// Process data for pie chart
|
// Process data for pie chart
|
||||||
const jenisPendaftaran = [...new Set(result.map(item => item.jenis_pendaftaran))].sort();
|
const jenisPendaftaran = [...new Set(result.map(item => item.jenis_pendaftaran))].sort() as string[];
|
||||||
const jumlahData = jenisPendaftaran.map(jenis => {
|
const jumlahData = jenisPendaftaran.map((jenis: string) => {
|
||||||
const item = result.find(d => d.jenis_pendaftaran === jenis);
|
const item = result.find((d: any) => d.jenis_pendaftaran === jenis);
|
||||||
return item ? item.jumlah : 0;
|
return item ? item.jumlah : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Assign colors based on global sorted position to match bar chart colors
|
||||||
|
const computedColors = jenisPendaftaran.map((jenis: string) => {
|
||||||
|
const idx = allJenis.indexOf(jenis);
|
||||||
|
return idx >= 0 ? colorPalette[idx % colorPalette.length] : '#999999';
|
||||||
|
});
|
||||||
|
|
||||||
|
setChartColors(computedColors);
|
||||||
setSeries(jumlahData);
|
setSeries(jumlahData);
|
||||||
setOptions(prev => ({
|
setOptions(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
labels: jenisPendaftaran,
|
labels: jenisPendaftaran,
|
||||||
|
colors: computedColors,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Store processed data
|
// Store processed data
|
||||||
|
|||||||
@@ -73,15 +73,10 @@ export default function StatistikMahasiswaChart({
|
|||||||
const seriesIndex = opts.seriesIndex;
|
const seriesIndex = opts.seriesIndex;
|
||||||
const dataPointIndex = opts.dataPointIndex;
|
const dataPointIndex = opts.dataPointIndex;
|
||||||
|
|
||||||
// Jika series Total (index 2), tampilkan angka
|
// Hitung total dari Laki-laki (index 0) dan Perempuan (index 1)
|
||||||
if (seriesIndex === 2) {
|
const lakiLakiData = opts.w.config.series[0]?.data || [];
|
||||||
return val.toString();
|
const perempuanData = opts.w.config.series[1]?.data || [];
|
||||||
}
|
const totalValue = (lakiLakiData[dataPointIndex] || 0) + (perempuanData[dataPointIndex] || 0);
|
||||||
|
|
||||||
// Untuk Laki-laki (index 0) dan Perempuan (index 1), hitung persentase
|
|
||||||
// Ambil data total dari series Total (index 2)
|
|
||||||
const totalSeriesData = opts.w.config.series[2]?.data || [];
|
|
||||||
const totalValue = totalSeriesData[dataPointIndex] || 0;
|
|
||||||
|
|
||||||
if (totalValue === 0 || val === 0) return '0%';
|
if (totalValue === 0 || val === 0) return '0%';
|
||||||
|
|
||||||
@@ -97,7 +92,7 @@ export default function StatistikMahasiswaChart({
|
|||||||
stroke: {
|
stroke: {
|
||||||
show: true,
|
show: true,
|
||||||
width: 2,
|
width: 2,
|
||||||
colors: ['transparent', 'transparent', 'transparent'],
|
colors: ['transparent', 'transparent'],
|
||||||
curve: 'straight' as const
|
curve: 'straight' as const
|
||||||
},
|
},
|
||||||
xaxis: {
|
xaxis: {
|
||||||
@@ -153,7 +148,7 @@ export default function StatistikMahasiswaChart({
|
|||||||
colors: '#000'
|
colors: '#000'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors: ['#3B82F6', '#EC4899', '#10B981'],
|
colors: ['#3B82F6', '#EC4899'],
|
||||||
tooltip: {
|
tooltip: {
|
||||||
theme: 'light',
|
theme: 'light',
|
||||||
shared: true,
|
shared: true,
|
||||||
@@ -161,7 +156,7 @@ export default function StatistikMahasiswaChart({
|
|||||||
custom: function({ series, seriesIndex, dataPointIndex, w }: any) {
|
custom: function({ series, seriesIndex, dataPointIndex, w }: any) {
|
||||||
const lakiLaki = series[0][dataPointIndex];
|
const lakiLaki = series[0][dataPointIndex];
|
||||||
const perempuan = series[1][dataPointIndex];
|
const perempuan = series[1][dataPointIndex];
|
||||||
const total = series[2][dataPointIndex];
|
const total = lakiLaki + perempuan;
|
||||||
const tahun = w.globals.labels[dataPointIndex];
|
const tahun = w.globals.labels[dataPointIndex];
|
||||||
|
|
||||||
return `
|
return `
|
||||||
@@ -199,7 +194,6 @@ export default function StatistikMahasiswaChart({
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
">
|
">
|
||||||
<div style="width: 8px; height: 8px; background: #10B981; border-radius: 50%; margin-right: 8px;"></div>
|
|
||||||
<span style="font-size: 12px; font-weight: 600; color: #1f2937;">Total</span>
|
<span style="font-size: 12px; font-weight: 600; color: #1f2937;">Total</span>
|
||||||
<span style="font-size: 13px; font-weight: 700; color: #10B981; margin-left: auto;">${total}</span>
|
<span style="font-size: 13px; font-weight: 700; color: #10B981; margin-left: auto;">${total}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -248,18 +242,11 @@ export default function StatistikMahasiswaChart({
|
|||||||
dataLabels: {
|
dataLabels: {
|
||||||
...prev.dataLabels,
|
...prev.dataLabels,
|
||||||
formatter: function (val: number, opts: any) {
|
formatter: function (val: number, opts: any) {
|
||||||
const seriesIndex = opts.seriesIndex;
|
|
||||||
const dataPointIndex = opts.dataPointIndex;
|
const dataPointIndex = opts.dataPointIndex;
|
||||||
|
|
||||||
// Jika series Total (index 2), tampilkan angka
|
const lakiLakiData = opts.w.config.series[0]?.data || [];
|
||||||
if (seriesIndex === 2) {
|
const perempuanData = opts.w.config.series[1]?.data || [];
|
||||||
return val.toString();
|
const totalValue = (lakiLakiData[dataPointIndex] || 0) + (perempuanData[dataPointIndex] || 0);
|
||||||
}
|
|
||||||
|
|
||||||
// Untuk Laki-laki (index 0) dan Perempuan (index 1), hitung persentase
|
|
||||||
// Ambil data total dari series Total (index 2)
|
|
||||||
const totalSeriesData = opts.w.config.series[2]?.data || [];
|
|
||||||
const totalValue = totalSeriesData[dataPointIndex] || 0;
|
|
||||||
|
|
||||||
if (totalValue === 0 || val === 0) return '0%';
|
if (totalValue === 0 || val === 0) return '0%';
|
||||||
|
|
||||||
@@ -320,13 +307,9 @@ export default function StatistikMahasiswaChart({
|
|||||||
custom: function({ series, seriesIndex, dataPointIndex, w }: any) {
|
custom: function({ series, seriesIndex, dataPointIndex, w }: any) {
|
||||||
const lakiLaki = series[0][dataPointIndex];
|
const lakiLaki = series[0][dataPointIndex];
|
||||||
const perempuan = series[1][dataPointIndex];
|
const perempuan = series[1][dataPointIndex];
|
||||||
const total = series[2][dataPointIndex];
|
const total = lakiLaki + perempuan;
|
||||||
const tahun = w.globals.labels[dataPointIndex];
|
const tahun = w.globals.labels[dataPointIndex];
|
||||||
|
|
||||||
const bgColor = currentTheme === 'dark' ? '#1e293b' : 'white';
|
|
||||||
const textColor = currentTheme === 'dark' ? '#fff' : '#000';
|
|
||||||
const borderColor = currentTheme === 'dark' ? '#475569' : '#ccc';
|
|
||||||
|
|
||||||
const isDark = currentTheme === 'dark';
|
const isDark = currentTheme === 'dark';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
@@ -364,7 +347,6 @@ export default function StatistikMahasiswaChart({
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
">
|
">
|
||||||
<div style="width: 8px; height: 8px; background: #10B981; border-radius: 50%; margin-right: 8px;"></div>
|
|
||||||
<span style="font-size: 12px; font-weight: 600; color: ${isDark ? '#f1f5f9' : '#1f2937'};">Total</span>
|
<span style="font-size: 12px; font-weight: 600; color: ${isDark ? '#f1f5f9' : '#1f2937'};">Total</span>
|
||||||
<span style="font-size: 13px; font-weight: 700; color: #10B981; margin-left: auto;">${total}</span>
|
<span style="font-size: 13px; font-weight: 700; color: #10B981; margin-left: auto;">${total}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -404,11 +386,6 @@ export default function StatistikMahasiswaChart({
|
|||||||
name: 'Perempuan',
|
name: 'Perempuan',
|
||||||
type: 'bar' as const,
|
type: 'bar' as const,
|
||||||
data: statistikData.map(item => item.wanita)
|
data: statistikData.map(item => item.wanita)
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Total',
|
|
||||||
type: 'bar' as const,
|
|
||||||
data: statistikData.map(item => item.total_mahasiswa)
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export default function StatusMahasiswaFilterPieChart({ selectedYear, selectedSt
|
|||||||
background: theme === 'dark' ? '#0F172B' : '#fff',
|
background: theme === 'dark' ? '#0F172B' : '#fff',
|
||||||
},
|
},
|
||||||
labels: ['Laki-laki', 'Perempuan'],
|
labels: ['Laki-laki', 'Perempuan'],
|
||||||
colors: ['#3B82F6', '#EC4899'],
|
colors: ['#008FFB', '#EC4899'],
|
||||||
legend: {
|
legend: {
|
||||||
position: 'bottom',
|
position: 'bottom',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
|
|||||||
@@ -65,9 +65,18 @@ export default function StatusMahasiswaPieChartPerangkatan({ selectedYear }: Pro
|
|||||||
fetchData();
|
fetchData();
|
||||||
}, [selectedYear]);
|
}, [selectedYear]);
|
||||||
|
|
||||||
|
// Color mapping consistent with StatusMahasiswaChart bar chart
|
||||||
|
const STATUS_COLOR_MAP: { [key: string]: string } = {
|
||||||
|
'Aktif': '#008FFB',
|
||||||
|
'Lulus': '#00E396',
|
||||||
|
'Cuti': '#FEB019',
|
||||||
|
'Non Aktif': '#EF4444',
|
||||||
|
};
|
||||||
|
|
||||||
// Prepare data for pie chart
|
// Prepare data for pie chart
|
||||||
const series = data.map(item => item.jumlah);
|
const series = data.map(item => item.jumlah);
|
||||||
const labels = data.map(item => item.status_kuliah);
|
const labels = data.map(item => item.status_kuliah);
|
||||||
|
const colors = data.map(item => STATUS_COLOR_MAP[item.status_kuliah] || '#775DD0');
|
||||||
|
|
||||||
const chartOptions: ApexOptions = {
|
const chartOptions: ApexOptions = {
|
||||||
chart: {
|
chart: {
|
||||||
@@ -103,13 +112,7 @@ export default function StatusMahasiswaPieChartPerangkatan({ selectedYear }: Pro
|
|||||||
colors: theme === 'dark' ? '#fff' : '#000'
|
colors: theme === 'dark' ? '#fff' : '#000'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors: [
|
colors: colors,
|
||||||
'#00E396', // Aktif - Green
|
|
||||||
'#008FFB', // Lulus - Blue
|
|
||||||
'#FEB019', // Cuti - Orange
|
|
||||||
'#FF4560', // Non-Aktif - Red
|
|
||||||
'#775DD0', // Lainnya - Purple
|
|
||||||
],
|
|
||||||
tooltip: {
|
tooltip: {
|
||||||
theme: theme === 'dark' ? 'dark' : 'light',
|
theme: theme === 'dark' ? 'dark' : 'light',
|
||||||
y: {
|
y: {
|
||||||
|
|||||||
Reference in New Issue
Block a user