Admin: Ubah Pie Chart Submenu IKM, Menu PPID

This commit is contained in:
2025-08-13 00:34:44 +08:00
parent a1d55e2b0a
commit a6832cad40

View File

@@ -1,10 +1,20 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
'use client' 'use client';
import React, { useEffect, useState } from 'react';
import { Box, Center, Flex, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
import colors from '@/con/colors'; import colors from '@/con/colors';
import { PieChart, Pie, Cell } from 'recharts'; import { PieChart } from '@mantine/charts'; // ✅ Ganti recharts dengan Mantine
import {
Box,
Center,
Flex,
Paper,
SimpleGrid,
Skeleton,
Stack,
Text,
Title,
} from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks'; import { useShallowEffect } from '@mantine/hooks';
import { useState } from 'react';
import { useProxy } from 'valtio/utils'; import { useProxy } from 'valtio/utils';
import indeksKepuasanState from '../../../_state/landing-page/indeks-kepuasan'; import indeksKepuasanState from '../../../_state/landing-page/indeks-kepuasan';
@@ -21,13 +31,8 @@ function Page() {
const [donutDataJenisKelamin, setDonutDataJenisKelamin] = useState<ChartDataItem[]>([]); const [donutDataJenisKelamin, setDonutDataJenisKelamin] = useState<ChartDataItem[]>([]);
const [donutDataRating, setDonutDataRating] = useState<ChartDataItem[]>([]); const [donutDataRating, setDonutDataRating] = useState<ChartDataItem[]>([]);
const [donutDataKelompokUmur, setDonutDataKelompokUmur] = useState<ChartDataItem[]>([]); const [donutDataKelompokUmur, setDonutDataKelompokUmur] = useState<ChartDataItem[]>([]);
const [mounted, setMounted] = useState(false);
useShallowEffect(() => { useShallowEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (data) { if (data) {
// Hitung total berdasarkan jenis kelamin // Hitung total berdasarkan jenis kelamin
const totalLaki = data.filter((item: any) => item.jenisKelamin?.name?.toLowerCase() === 'laki-laki').length; const totalLaki = data.filter((item: any) => item.jenisKelamin?.name?.toLowerCase() === 'laki-laki').length;
@@ -43,28 +48,29 @@ function Page() {
const totalMuda = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'muda').length; const totalMuda = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'muda').length;
const totalDewasa = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'dewasa').length; const totalDewasa = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'dewasa').length;
const totalLansia = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'lansia').length; const totalLansia = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'lansia').length;
// Update gender chart data // Update gender chart data
setDonutDataJenisKelamin([ setDonutDataJenisKelamin([
{ name: 'laki', value: totalLaki, color: colors['blue-button'], label: 'Laki-laki' }, { name: 'Laki-laki', value: totalLaki, color: colors['blue-button'] },
{ name: 'perempuan', value: totalPerempuan, color: '#10A85AFF', label: 'Perempuan' } { name: 'Perempuan', value: totalPerempuan, color: '#10A85AFF' },
]); ]);
// Update rating chart data // Update rating chart data
setDonutDataRating([ setDonutDataRating([
{ name: 'sangat_baik', value: totalSangatBaik, color: colors['blue-button'], label: 'Sangat Baik' }, { name: 'Sangat Baik', value: totalSangatBaik, color: colors['blue-button'] },
{ name: 'baik', value: totalBaik, color: '#10A85AFF', label: 'Baik' }, { name: 'Baik', value: totalBaik, color: '#10A85AFF' },
{ name: 'kurang_baik', value: totalKurangBaik, color: '#FFA500', label: 'Kurang Baik' }, { name: 'Kurang Baik', value: totalKurangBaik, color: '#FFA500' },
{ name: 'sangat_kurang_baik', value: totalSangatKurangBaik, color: '#FF4500', label: 'Sangat Kurang Baik' } { name: 'Sangat Kurang Baik', value: totalSangatKurangBaik, color: '#FF4500' },
]); ]);
// Update age group chart data // Update age group chart data
setDonutDataKelompokUmur([ setDonutDataKelompokUmur([
{ name: 'muda', value: totalMuda, color: colors['blue-button'], label: 'Muda' }, { name: 'Muda', value: totalMuda, color: colors['blue-button'] },
{ name: 'dewasa', value: totalDewasa, color: '#10A85AFF', label: 'Dewasa' }, { name: 'Dewasa', value: totalDewasa, color: '#10A85AFF' },
{ name: 'lansia', value: totalLansia, color: '#FFA500', label: 'Lansia' } { name: 'Lansia', value: totalLansia, color: '#FFA500' },
]); ]);
} }
}, [data]) }, [data]);
if (loading || !data) { if (loading || !data) {
return ( return (
@@ -77,46 +83,43 @@ function Page() {
if (data.length === 0) { if (data.length === 0) {
return ( return (
<Stack py={10}> <Stack py={10}>
<Text c='dimmed' ta="center" my="md">Belum ada data untuk ditampilkan</Text> <Text c="dimmed" ta="center" my="md">
Belum ada data untuk ditampilkan
</Text>
</Stack> </Stack>
) );
} }
return ( return (
<Stack gap="xs">
<SimpleGrid cols={{ base: 1, md: 3 }}>
{/* Chart Jenis Kelamin */}
<Paper bg={colors['white-1']} p="md" radius="md">
<Stack> <Stack>
{/* Chart */} <Title order={4}>Jenis Kelamin</Title>
<Box> {donutDataJenisKelamin.every(item => item.value === 0) ? (
<Paper bg={colors['white-1']} p={'md'} style={{ height: '100%' }}> <Text c="dimmed" ta="center" my="md">
<Stack> Belum ada data untuk ditampilkan dalam grafik
<Title pb={10} order={4} size="h4">Grafik Berdasarkan Jenis Kelamin Responden</Title> </Text>
{mounted && donutDataJenisKelamin.length === 0 ? (
<Text c='dimmed' ta="center" my="md">Belum ada data untuk ditampilkan dalam grafik</Text>
) : ( ) : (
<Box> <Box>
<Center> <Center>
<PieChart width={250} height={350}> <PieChart
<Pie withLabels
withTooltip
labelsType="percent"
size={250}
data={donutDataJenisKelamin} data={donutDataJenisKelamin}
dataKey="value" />
nameKey="name"
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={100}
label={({ percent }: { percent: number }) => `${(percent * 100).toFixed(0)}%`}
labelLine={false}
>
{donutDataJenisKelamin.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
</PieChart>
</Center> </Center>
<Stack gap="sm" mt="md"> <Stack gap="sm" mt="md">
{donutDataJenisKelamin.map((entry) => ( {donutDataJenisKelamin.map((entry) => (
<Flex key={entry.name} gap="md" align="center"> <Flex key={entry.name} gap="md" align="center">
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} /> <Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
<Text size="sm">{entry.label}: {entry.value || 0}</Text> <Text size="sm">{entry.name}: {entry.value}</Text>
</Flex> </Flex>
))} ))}
</Stack> </Stack>
@@ -124,40 +127,31 @@ function Page() {
)} )}
</Stack> </Stack>
</Paper> </Paper>
</Box>
<Box> {/* Chart Rating */}
{/* Rating Chart */} <Paper bg={colors['white-1']} p="md" radius="md">
<Paper bg={colors['white-1']} p={'md'} style={{ height: '100%' }}>
<Stack> <Stack>
<Title pb={10} order={4}>Grafik Berdasarkan Rating Responden</Title> <Title order={4}>Pilihan</Title>
{mounted && donutDataRating.length === 0 ? ( {donutDataRating.every(item => item.value === 0) ? (
<Text c='dimmed' ta="center" my="md">Belum ada data untuk ditampilkan dalam grafik</Text> <Text c="dimmed" ta="center" my="md">
Belum ada data untuk ditampilkan dalam grafik
</Text>
) : ( ) : (
<Box> <Box>
<Center> <Center>
<PieChart width={350} height={350}> <PieChart
<Pie withLabels
withTooltip
labelsType="percent"
size={250}
data={donutDataRating} data={donutDataRating}
dataKey="value" />
nameKey="name"
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={100}
label={({ percent }: { percent: number }) => `${(percent * 100).toFixed(0)}%`}
labelLine={false}
>
{donutDataRating.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
</PieChart>
</Center> </Center>
<Stack gap="sm" mt="md"> <Stack gap="sm" mt="md">
{donutDataRating.map((entry) => ( {donutDataRating.map((entry) => (
<Flex key={entry.name} gap="md" align="center"> <Flex key={entry.name} gap="md" align="center">
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} /> <Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
<Text size="sm">{entry.label}: {entry.value || 0}</Text> <Text size="sm">{entry.name}: {entry.value}</Text>
</Flex> </Flex>
))} ))}
</Stack> </Stack>
@@ -165,41 +159,31 @@ function Page() {
)} )}
</Stack> </Stack>
</Paper> </Paper>
</Box>
{/* Age Group Chart */} {/* Chart Kelompok Umur */}
<Box> <Paper bg={colors['white-1']} p="md" radius="md">
<Paper bg={colors['white-1']} p={'md'} style={{ height: '100%' }}>
<Stack> <Stack>
<Title pb={10} order={4}>Grafik Berdasarkan Kelompok Umur</Title> <Title order={4}>Umur</Title>
{mounted && donutDataKelompokUmur.length === 0 ? ( {donutDataKelompokUmur.every(item => item.value === 0) ? (
<Text c='dimmed' ta="center" my="md">Belum ada data untuk ditampilkan dalam grafik</Text> <Text c="dimmed" ta="center" my="md">
Belum ada data untuk ditampilkan dalam grafik
</Text>
) : ( ) : (
<Box> <Box>
<Center> <Center>
<PieChart width={350} height={350}> <PieChart
<Pie withLabels
withTooltip
labelsType="percent"
size={250}
data={donutDataKelompokUmur} data={donutDataKelompokUmur}
dataKey="value" />
nameKey="name"
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={100}
label={({ percent }: { percent: number }) => `${(percent * 100).toFixed(0)}%`}
labelLine={false}
>
{donutDataKelompokUmur.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
</PieChart>
</Center> </Center>
<Stack gap="sm" mt="md"> <Stack gap="sm" mt="md">
{donutDataKelompokUmur.map((entry) => ( {donutDataKelompokUmur.map((entry) => (
<Flex key={entry.name} gap="md" align="center"> <Flex key={entry.name} gap="md" align="center">
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} /> <Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
<Text size="sm">{entry.label}: {entry.value || 0}</Text> <Text size="sm">{entry.name}: {entry.value}</Text>
</Flex> </Flex>
))} ))}
</Stack> </Stack>
@@ -207,7 +191,7 @@ function Page() {
)} )}
</Stack> </Stack>
</Paper> </Paper>
</Box> </SimpleGrid>
</Stack> </Stack>
); );
} }