QC Tampilan Admin & User, Api berfungsi

This commit is contained in:
2025-09-16 16:47:12 +08:00
parent 4ceea5203f
commit 39e1e7b575
48 changed files with 3250 additions and 1916 deletions

View File

@@ -1,5 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
'use client'
'use client';
import jumlahPengangguranState from '@/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran';
import colors from '@/con/colors';
import { Box, Button, Group, Paper, Stack, Text, TextInput, Title, Select, NumberInput } from '@mantine/core';
@@ -10,19 +10,12 @@ import { toast } from 'react-toastify';
import { useProxy } from 'valtio/utils';
function EditDetailDataPengangguran() {
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran)
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran);
const router = useRouter();
const params = useParams()
const params = useParams();
const [formData, setFormData] = useState<{
month: string;
year: number;
educatedUnemployment: number;
uneducatedUnemployment: number;
totalUnemployment: number;
percentageChange: number | null;
}>({
month: "",
const [formData, setFormData] = useState({
month: '',
year: new Date().getFullYear(),
educatedUnemployment: 0,
uneducatedUnemployment: 0,
@@ -30,52 +23,41 @@ function EditDetailDataPengangguran() {
percentageChange: 0,
});
// Update form data and recalculate totals
const updateFormData = async (updates: Partial<typeof formData>) => {
const newData = { ...formData, ...updates };
const { total, percentageChange } = await calculateTotalAndChange();
setFormData({
...newData,
totalUnemployment: total,
percentageChange,
});
};
// Hitung total & perubahan otomatis
const calculateTotalAndChange = async () => {
const total = formData.educatedUnemployment + formData.uneducatedUnemployment;
// Calculate percentage change based on previous month's data
let percentageChange = 0;
const monthOrder = ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"];
const monthOrder = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'];
const currentMonthIndex = monthOrder.indexOf(formData.month);
if (currentMonthIndex !== -1) {
let prevMonthIndex = currentMonthIndex - 1;
let prevYear = formData.year;
if (prevMonthIndex < 0) {
prevMonthIndex = 11;
prevYear--;
}
const prevMonth = monthOrder[prevMonthIndex];
// Get previous month's data
const prevData = await stateDetail.findByMonthYear.load({
month: prevMonth,
year: prevYear,
});
const prevData = await stateDetail.findByMonthYear.load({ month: prevMonth, year: prevYear });
if (prevData && prevData.totalUnemployment > 0) {
const change = ((total - prevData.totalUnemployment) / prevData.totalUnemployment) * 100;
percentageChange = parseFloat(change.toFixed(1));
}
}
return { total, percentageChange };
};
const updateFormData = async (updates: Partial<typeof formData>) => {
const newData = { ...formData, ...updates };
const { total, percentageChange } = await calculateTotalAndChange();
setFormData({ ...newData, totalUnemployment: total, percentageChange });
};
useEffect(() => {
const loadDetail = async () => {
const id = params?.id as string;
@@ -124,79 +106,69 @@ function EditDetailDataPengangguran() {
const handleSubmit = async () => {
const { total, percentageChange } = await calculateTotalAndChange();
try {
stateDetail.update.form = {
...formData,
totalUnemployment: total,
percentageChange,
};
stateDetail.update.form = { ...formData, totalUnemployment: total, percentageChange };
const success = await stateDetail.update.submit();
if (success) {
toast.success("Detail data pengangguran berhasil diperbarui!");
router.push("/admin/ekonomi/jumlah-pengangguran");
toast.success('Detail data pengangguran berhasil diperbarui!');
router.push('/admin/ekonomi/jumlah-pengangguran');
}
} catch (error) {
console.error("Error updating:", error);
toast.error("Terjadi kesalahan saat memperbarui data");
console.error('Error updating:', error);
toast.error('Terjadi kesalahan saat memperbarui data');
}
}
};
return (
<Box>
<Box mb={10}>
<Button onClick={() => router.back()} variant='subtle' color={'blue'}>
<IconArrowBack color={colors['blue-button']} size={25} />
<Box px={{ base: 'sm', md: 'lg' }} py="md">
<Group mb="md">
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
<IconArrowBack color={colors['blue-button']} size={24} />
</Button>
</Box>
<Title order={4} ml="sm">
Edit Detail Data Pengangguran
</Title>
</Group>
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
<Title order={4}>Edit Detail Data Pengangguran</Title>
<Stack gap="xs">
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p="lg" radius="md" shadow="sm" style={{ border: '1px solid #e0e0e0' }}>
<Stack gap="md">
<Select
label="Bulan"
data={["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"]}
data={['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des']}
value={formData.month}
onChange={async (val) => {
await updateFormData({ month: val || "" });
}}
onChange={(val) => updateFormData({ month: val || '' })}
/>
<NumberInput
label="Tahun"
value={formData.year}
onChange={async (val) => {
await updateFormData({ year: Number(val) });
}}
onChange={(val) => updateFormData({ year: Number(val) })}
/>
<TextInput
label="Pengangguran Terdidik"
type="number"
value={formData.educatedUnemployment}
onChange={async (val) => {
const value = Number(val.currentTarget.value) || 0;
await updateFormData({ educatedUnemployment: value });
}}
onChange={(val) => updateFormData({ educatedUnemployment: Number(val.currentTarget.value) || 0 })}
/>
<TextInput
label="Pengangguran Tidak Terdidik"
type="number"
value={formData.uneducatedUnemployment}
onChange={async (val) => {
const value = Number(val.currentTarget.value) || 0;
await updateFormData({ uneducatedUnemployment: value });
}}
onChange={(val) => updateFormData({ uneducatedUnemployment: Number(val.currentTarget.value) || 0 })}
/>
<Text fz="sm" fw={500}>
Total Otomatis: {formData.totalUnemployment}
</Text>
<Text fz="sm" fw={500}>
Perubahan Otomatis:{" "}
{formData.percentageChange !== null
? `${formData.percentageChange}%`
: '-'}
</Text>
<Group>
<Button bg={colors['blue-button']} mt={10} onClick={handleSubmit}>
Submit
<Text fz="sm" fw={500}>Total Otomatis: {formData.totalUnemployment}</Text>
<Text fz="sm" fw={500}>Perubahan Otomatis: {formData.percentageChange !== null ? `${formData.percentageChange}%` : '-'}</Text>
<Group justify="right">
<Button
onClick={handleSubmit}
radius="md"
size="md"
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}
>
Simpan
</Button>
</Group>
</Stack>
@@ -206,3 +178,4 @@ function EditDetailDataPengangguran() {
}
export default EditDetailDataPengangguran;

View File

@@ -2,7 +2,7 @@
import { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus';
import jumlahPengangguranState from '@/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran';
import colors from '@/con/colors';
import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core';
import { Box, Button, Flex, Paper, Skeleton, Stack, Text, Tooltip } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react';
import { useParams, useRouter } from 'next/navigation';
@@ -11,91 +11,125 @@ import { useProxy } from 'valtio/utils';
function DetailJumlahPengangguran() {
const router = useRouter();
const params = useParams()
const [modalHapus, setModalHapus] = useState(false)
const [selectedId, setSelectedId] = useState<string | null>(null)
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran)
const params = useParams();
const [modalHapus, setModalHapus] = useState(false);
const [selectedId, setSelectedId] = useState<string | null>(null);
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran);
useShallowEffect(() => {
stateDetail.findUnique.load(params?.id as string)
}, [params?.id])
stateDetail.findUnique.load(params?.id as string);
}, [params?.id]);
const handleHapus = () => {
if (selectedId) {
stateDetail.delete.byId(selectedId)
setModalHapus(false)
setSelectedId(null)
router.push("/admin/ekonomi/jumlah-pengangguran")
stateDetail.delete.byId(selectedId);
setModalHapus(false);
setSelectedId(null);
router.push("/admin/ekonomi/jumlah-pengangguran");
}
}
};
if (!stateDetail.findUnique.data) {
return (
<Box>
<Skeleton h={500} />
</Box>
)
<Stack py={10}>
<Skeleton height={500} radius="md" />
</Stack>
);
}
const data = stateDetail.findUnique.data;
return (
<Box>
<Box mb={10}>
<Button variant="subtle" onClick={() => router.back()}>
<IconArrowBack color={colors['blue-button']} size={25} />
</Button>
</Box>
<Paper w={{ base: "100%", md: "50%" }} bg={colors['white-1']} p={'md'}>
<Stack>
<Text fz={"xl"} fw={"bold"}>Detail Data Pengangguran</Text>
<Paper bg={colors['BG-trans']} p={'md'}>
<Stack gap={"xs"}>
<Box py={10}>
{/* Tombol Kembali */}
<Button
variant="subtle"
onClick={() => router.back()}
leftSection={<IconArrowBack size={24} color={colors['blue-button']} />}
mb={15}
>
Kembali
</Button>
{/* Paper Detail */}
<Paper
withBorder
w={{ base: "100%", md: "60%" }}
bg={colors['white-1']}
p="lg"
radius="md"
shadow="sm"
>
<Stack gap="md">
<Text fz="2xl" fw="bold" c={colors['blue-button']}>
Detail Data Pengangguran
</Text>
<Paper bg="#ECEEF8" p="md" radius="md" shadow="xs">
<Stack gap="sm">
<Box>
<Text fw={"bold"}>Pengangguran Terdidik</Text>
<Text>{stateDetail.findUnique.data?.educatedUnemployment}</Text>
<Text fw="bold">Pengangguran Terdidik</Text>
<Text c="dimmed">{data.educatedUnemployment || '-'}</Text>
</Box>
<Box>
<Text fw={"bold"}>Pengangguran Tidak Terdidik</Text>
<Text>{stateDetail.findUnique.data?.uneducatedUnemployment}</Text>
<Text fw="bold">Pengangguran Tidak Terdidik</Text>
<Text c="dimmed">{data.uneducatedUnemployment || '-'}</Text>
</Box>
<Box>
<Text fw={"bold"}>Perubahan</Text>
<Text>
{stateDetail.findUnique.data?.percentageChange !== null &&
stateDetail.findUnique.data?.percentageChange !== undefined
? `${stateDetail.findUnique.data.percentageChange}%`
<Text fw="bold">Perubahan</Text>
<Text c="dimmed">
{data.percentageChange !== null && data.percentageChange !== undefined
? `${data.percentageChange}%`
: 'Tidak ada data perubahan'}
</Text>
</Box>
<Box>
<Text fw={"bold"}>Tahun</Text>
<Text>{stateDetail.findUnique.data?.year || ''}</Text>
<Text fw="bold">Tahun</Text>
<Text c="dimmed">{data.year || '-'}</Text>
</Box>
<Box>
<Text fw={"bold"}>Bulan</Text>
<Text>{stateDetail.findUnique.data?.month}</Text>
<Text fw="bold">Bulan</Text>
<Text c="dimmed">{data.month || '-'}</Text>
</Box>
<Box>
<Text fw={"bold"}>Total Pengangguran</Text>
<Text>{stateDetail.findUnique.data?.totalUnemployment}</Text>
<Text fw="bold">Total Pengangguran</Text>
<Text c="dimmed">{data.totalUnemployment || '-'}</Text>
</Box>
<Box>
<Flex gap={"xs"}>
{/* Tombol Edit & Hapus */}
<Flex gap="sm">
<Tooltip label="Hapus Data Pengangguran" withArrow position="top">
<Button
onClick={() => {
if (stateDetail.findUnique.data) {
setSelectedId(stateDetail.findUnique.data.id);
setModalHapus(true);
}
setSelectedId(data.id);
setModalHapus(true);
}}
disabled={stateDetail.delete.loading || !stateDetail.findUnique.data}
color={"red"}>
color="red"
variant="light"
radius="md"
size="md"
>
<IconX size={20} />
</Button>
<Button onClick={() => router.push(`/admin/ekonomi/jumlah-pengangguran/${stateDetail.findUnique.data?.id}/edit`)} color="green">
</Tooltip>
<Tooltip label="Edit Data Pengangguran" withArrow position="top">
<Button
onClick={() => router.push(`/admin/ekonomi/jumlah-pengangguran/${data.id}/edit`)}
color="green"
variant="light"
radius="md"
size="md"
>
<IconEdit size={20} />
</Button>
</Flex>
</Box>
</Tooltip>
</Flex>
</Stack>
</Paper>
</Stack>
@@ -106,7 +140,7 @@ function DetailJumlahPengangguran() {
opened={modalHapus}
onClose={() => setModalHapus(false)}
onConfirm={handleHapus}
text="Apakah anda yakin ingin menghapus data ini?"
text="Apakah Anda yakin ingin menghapus data ini?"
/>
</Box>
);

View File

@@ -3,14 +3,25 @@
'use client'
import jumlahPengangguranState from '@/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran';
import colors from '@/con/colors';
import { Box, Button, Group, Paper, Stack, Text, TextInput, Title, Select, NumberInput } from '@mantine/core';
import {
Box,
Button,
Group,
Paper,
Stack,
Text,
NumberInput,
Title,
Select,
Tooltip,
} from '@mantine/core';
import { IconArrowBack } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { useProxy } from 'valtio/utils';
function CreateJumlahPengangguran() {
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran)
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran);
const [chartData, setChartData] = useState<any[]>([]);
const router = useRouter();
@@ -21,14 +32,14 @@ function CreateJumlahPengangguran() {
const resetForm = () => {
stateDetail.create.form = {
month: monthOptions[new Date().getMonth()], // Default to current month
year: new Date().getFullYear(), // Default to current year
month: monthOptions[new Date().getMonth()], // default bulan sekarang
year: new Date().getFullYear(), // default tahun sekarang
totalUnemployment: 0,
educatedUnemployment: 0,
uneducatedUnemployment: 0,
percentageChange: 0,
}
}
};
};
const calculateTotalAndChange = async () => {
const total =
@@ -37,11 +48,8 @@ function CreateJumlahPengangguran() {
stateDetail.create.form.totalUnemployment = total;
// Ambil data bulan sebelumnya
const monthOrder = [
'Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun',
'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'
];
// hitung perubahan dibanding bulan sebelumnya
const monthOrder = monthOptions;
const currentIndex = monthOrder.findIndex(
(m) => m.toLowerCase() === stateDetail.create.form.month.toLowerCase()
);
@@ -78,15 +86,34 @@ function CreateJumlahPengangguran() {
};
return (
<Box>
<Box mb={10}>
<Button onClick={() => router.back()} variant='subtle' color={'blue'}>
<IconArrowBack color={colors['blue-button']} size={25} />
</Button>
</Box>
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
<Title order={4}>Tambah Data Pengangguran</Title>
<Stack gap="xs" mt="md">
<Box px={{ base: 'sm', md: 'lg' }} py="md">
{/* Header */}
<Group mb="md">
<Tooltip label="Kembali ke halaman sebelumnya" withArrow>
<Button
variant="subtle"
onClick={() => router.back()}
p="xs"
radius="md"
>
<IconArrowBack color={colors['blue-button']} size={24} />
</Button>
</Tooltip>
<Title order={4} ml="sm" c="dark">
Tambah Data Pengangguran
</Title>
</Group>
{/* Form Card */}
<Paper
w={{ base: '100%', md: '50%' }}
bg={colors['white-1']}
p="lg"
radius="md"
shadow="sm"
style={{ border: '1px solid #e0e0e0' }}
>
<Stack gap="md">
<Select
label="Bulan"
placeholder="Pilih bulan"
@@ -98,6 +125,7 @@ function CreateJumlahPengangguran() {
}}
required
/>
<NumberInput
label="Tahun"
value={stateDetail.create.form.year}
@@ -109,6 +137,7 @@ function CreateJumlahPengangguran() {
max={2100}
required
/>
<NumberInput
label="Pengangguran Terdidik"
value={stateDetail.create.form.educatedUnemployment}
@@ -119,6 +148,7 @@ function CreateJumlahPengangguran() {
min={0}
required
/>
<NumberInput
label="Pengangguran Tidak Terdidik"
value={stateDetail.create.form.uneducatedUnemployment}
@@ -129,15 +159,36 @@ function CreateJumlahPengangguran() {
min={0}
required
/>
<Text fz="sm" fw={500}>
Total Otomatis: {stateDetail.create.form.totalUnemployment.toLocaleString()}
</Text>
<Text fz="sm" fw={500}>
Perubahan Otomatis: {stateDetail.create.form.percentageChange.toFixed(1)}%
</Text>
<Group mt="md">
<Box>
<Text fz="sm" fw={500} mb={4}>
Total Otomatis:
</Text>
<Text fz="sm" c="dimmed">
{stateDetail.create.form.totalUnemployment.toLocaleString()}
</Text>
</Box>
<Box>
<Text fz="sm" fw={500} mb={4}>
Perubahan Otomatis:
</Text>
<Text fz="sm" c="dimmed">
{stateDetail.create.form.percentageChange.toFixed(1)}%
</Text>
</Box>
{/* Action Button */}
<Group justify="right" mt="md">
<Button
onClick={handleSubmit}
radius="md"
size="md"
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}
disabled={!stateDetail.create.form.month || !stateDetail.create.form.year}
>
Simpan

View File

@@ -1,150 +1,181 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client'
import colors from '@/con/colors';
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
import {
Box, Button, Center, Group, Pagination, Paper, Skeleton, Stack,
Table, TableTbody, TableTd, TableTh, TableThead, TableTr,
Text, Title, Tooltip
} from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
import { IconDeviceImac, IconPlus, IconSearch } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import { useProxy } from 'valtio/utils';
import { BarChart } from '@mantine/charts';
import HeaderSearch from '../../_com/header';
import JudulList from '../../_com/judulList';
import jumlahPengangguranState from '../../_state/ekonomi/jumlah-pengangguran';
function DetailDataPengangguran() {
const [search, setSearch] = useState("")
const [search, setSearch] = useState("");
return (
<Box>
<Stack gap={"xs"}>
<HeaderSearch
title='Detail Data Pengangguran'
placeholder='pencarian'
placeholder='Cari bulan atau tahun...'
searchIcon={<IconSearch size={20} />}
value={search}
onChange={(e) => setSearch(e.currentTarget.value)}
/>
<ListDetailDataPengangguran search={search} />
</Stack>
<ListDetailDataPengangguran search={search} />
</Box>
);
}
function ListDetailDataPengangguran({search}: {search: string}) {
type DetailDataPengangguran = {
id: string;
month: string;
year: number;
educatedUnemployment: number;
uneducatedUnemployment: number;
percentageChange: number;
totalUnemployment: number;
}
const [chartData, setChartData] = useState<DetailDataPengangguran[]>([]);
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran)
function ListDetailDataPengangguran({ search }: { search: string }) {
const [chartData, setChartData] = useState<any[]>([]);
const [mounted, setMounted] = useState(false);
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran);
const router = useRouter();
const {
data,
page,
totalPages,
loading,
load,
} = stateDetail.findMany;
useShallowEffect(() => {
setMounted(true)
stateDetail.findMany.load()
}, [])
setMounted(true);
load(page, 10, search);
}, [page, search]);
useEffect(() => {
setMounted(true);
if (stateDetail.findMany.data) {
setChartData(stateDetail.findMany.data.map((item) => ({
id: item.id,
month: item.month,
year: item.year && typeof item.year === 'object' && 'getFullYear' in item.year ? (item.year as Date).getFullYear() : Number(item.year),
educatedUnemployment: Number(item.educatedUnemployment),
uneducatedUnemployment: Number(item.uneducatedUnemployment),
percentageChange: Number(item.percentageChange),
totalUnemployment: Number(item.totalUnemployment),
})));
if (data) {
setChartData(
data.map((item) => ({
id: item.id,
month: item.month,
year: Number(item.year),
educatedUnemployment: Number(item.educatedUnemployment),
uneducatedUnemployment: Number(item.uneducatedUnemployment),
percentageChange: Number(item.percentageChange),
totalUnemployment: Number(item.totalUnemployment),
}))
);
}
}, [stateDetail.findMany.data]);
}, [data]);
const filteredData = (stateDetail.findMany.data || []).filter(item => {
const keyword = search.toLowerCase();
const filteredData = data || []
// Loading state
if (loading || !data) {
return (
item.month.toLowerCase().includes(keyword) ||
item.year.toString().toLowerCase().includes(keyword)
<Stack py="md">
<Skeleton h={500} radius="md" />
</Stack>
);
});
if (!stateDetail.findMany.data) {
return (
<Box>
<Skeleton h={500} />
</Box>
)
}
return (
<Box>
<Stack gap={"md"}>
<Paper bg={colors['white-1']} p={'md'}>
<JudulList
title='List Detail Data Pengangguran'
href='/admin/ekonomi/jumlah-pengangguran/create'
/>
<Table striped withTableBorder withRowBorders>
<Stack py="md" gap="lg">
{/* Table Section */}
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
<Group justify="space-between" mb="md">
<Title order={4}>Daftar Detail Data Pengangguran</Title>
<Tooltip label="Tambah Data Baru" withArrow>
<Button
leftSection={<IconPlus size={18} />}
color="blue"
variant="light"
onClick={() => router.push('/admin/ekonomi/jumlah-pengangguran/create')}
>
Tambah Baru
</Button>
</Tooltip>
</Group>
<Box style={{ overflowX: 'auto' }}>
<Table highlightOnHover striped withTableBorder withRowBorders>
<TableThead>
<TableTr>
<TableTh>Bulan</TableTh>
<TableTh>Terdidik</TableTh>
<TableTh>Tidak Terdidik</TableTh>
<TableTh>Detail</TableTh>
<TableTh style={{ width: '25%' }}>Bulan</TableTh>
<TableTh style={{ width: '20%' }}>Terdidik</TableTh>
<TableTh style={{ width: '20%' }}>Tidak Terdidik</TableTh>
<TableTh style={{ width: '15%' }}>Aksi</TableTh>
</TableTr>
</TableThead>
<TableTbody>
{filteredData.map((item) => (
<TableTr key={item.id}>
<TableTd>{item.month}</TableTd>
<TableTd>{item.educatedUnemployment}</TableTd>
<TableTd>{item.uneducatedUnemployment}</TableTd>
<TableTd>
<Button onClick={() => router.push(`/admin/ekonomi/jumlah-pengangguran/${item.id}`)}>
<IconDeviceImac size={20} />
</Button>
{filteredData.length > 0 ? (
filteredData.map((item) => (
<TableTr key={item.id}>
<TableTd>{item.month} {item.year}</TableTd>
<TableTd>{item.educatedUnemployment}</TableTd>
<TableTd>{item.uneducatedUnemployment}</TableTd>
<TableTd>
<Button
variant="light"
color="blue"
onClick={() => router.push(`/admin/ekonomi/jumlah-pengangguran/${item.id}`)}
>
<IconDeviceImac size={20} />
<Text ml={5}>Detail</Text>
</Button>
</TableTd>
</TableTr>
))
) : (
<TableTr>
<TableTd colSpan={4}>
<Center py={20}>
<Text c="dimmed">Tidak ada data yang cocok</Text>
</Center>
</TableTd>
</TableTr>
))}
)}
</TableTbody>
</Table>
</Paper>
</Box>
</Paper>
<Center>
<Pagination
value={page}
onChange={(newPage) => {
load(newPage, 10);
window.scrollTo({ top: 0, behavior: 'smooth' });
}}
total={totalPages}
mt="md"
mb="md"
color="blue"
radius="md"
/>
</Center>
{/* Chart */}
{!mounted && !chartData ? (
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
<Paper bg={colors['white-1']} p={'md'}>
<Title pb={10} order={3}>Data Pengangguran Terdidik dan Tidak Terdidik</Title>
<Text c='dimmed'>Belum ada data untuk ditampilkan dalam grafik</Text>
</Paper>
{/* Chart Section */}
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
<Title order={4} mb="md">
Data Pengangguran Terdidik & Tidak Terdidik
</Title>
{mounted && chartData.length > 0 ? (
<Box w={{ base: '100%', md: '70%' }}>
<BarChart
h={450}
data={chartData}
dataKey="month"
series={[
{ name: 'educatedUnemployment', color: 'red.6', label: 'Terdidik' },
{ name: 'uneducatedUnemployment', color: 'orange.6', label: 'Tidak Terdidik' },
]}
/>
</Box>
) : (
<Box style={{ width: '100%', minWidth: 300, height: 550, minHeight: 300 }}>
<Paper bg={colors['white-1']} p={'md'}>
<Title pb={10} order={4}>Data Pengangguran Terdidik dan Tidak Terdidik</Title>
{mounted && chartData.length > 0 && (
<Box w={{ base: '100%', md: '70%' }}>
<BarChart
h={450}
data={chartData}
dataKey="month"
series={[
{ name: 'educatedUnemployment', color: 'red.6', label: 'Terdidik' },
{ name: 'uneducatedUnemployment', color: 'orange.6', label: 'Tidak Terdidik' },
]}
/>
</Box>
)}
</Paper>
</Box>
<Text c="dimmed">Belum ada data untuk ditampilkan dalam grafik</Text>
)}
</Stack>
</Box>
</Paper>
</Stack>
);
}