diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0c3168ef..97b3cc2a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1487,7 +1487,7 @@ model ProgramKemiskinan { id String @id @default(uuid()) nama String deskripsi String - ikonUrl String? + icon String isActive Boolean @default(true) statistikId String? @unique statistik StatistikKemiskinan? @relation(fields: [statistikId], references: [id]) diff --git a/src/app/admin/(dashboard)/_com/iconMap.tsx b/src/app/admin/(dashboard)/_com/iconMap.tsx new file mode 100644 index 00000000..329410ba --- /dev/null +++ b/src/app/admin/(dashboard)/_com/iconMap.tsx @@ -0,0 +1,83 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +'use client' + +import React from 'react' +import { + IconLeaf, + IconTrophy, + IconTent, + IconChartLine, + IconRecycle, + IconTruck, + IconScale, + IconClipboard, + IconTrash, + IconHomeEco, + IconChristmasTreeFilled, + IconTrendingUp, + IconShieldFilled, + IconHome, + IconTree, + IconDroplet, + IconCash, + IconSchool, + IconShoppingCart, + IconHospital, +} from '@tabler/icons-react' + +export type IconKey = + | 'ekowisata' + | 'kompetisi' + | 'wisata' + | 'ekonomi' + | 'sampah' + | 'truck' + | 'scale' + | 'clipboard' + | 'trash' + | 'lingkunganSehat' + | 'sumberOksigen' + | 'ekonomiBerkelanjutan' + | 'mencegahBencana' + | 'rumah' + | 'pohon' + | 'air' + | 'bantuan' + | 'pelatihan' + | 'subsidi' + | 'layananKesehatan' + +const iconMap: Record> = { + ekowisata: IconLeaf, + kompetisi: IconTrophy, + wisata: IconTent, + ekonomi: IconChartLine, + sampah: IconRecycle, + truck: IconTruck, + scale: IconScale, + clipboard: IconClipboard, + trash: IconTrash, + lingkunganSehat: IconHomeEco, + sumberOksigen: IconChristmasTreeFilled, + ekonomiBerkelanjutan: IconTrendingUp, + mencegahBencana: IconShieldFilled, + rumah: IconHome, + pohon: IconTree, + air: IconDroplet, + bantuan: IconCash, + pelatihan: IconSchool, + subsidi: IconShoppingCart, + layananKesehatan: IconHospital, +} + +type Props = { + name: IconKey + size?: number + color?: string +} + +export const IconMapper: React.FC = ({ name, size = 24, color }) => { + const IconComponent = iconMap[name] + if (!IconComponent) return null + return +} diff --git a/src/app/admin/(dashboard)/_com/selectIcon.tsx b/src/app/admin/(dashboard)/_com/selectIcon.tsx index 78b449f7..5713f7f8 100644 --- a/src/app/admin/(dashboard)/_com/selectIcon.tsx +++ b/src/app/admin/(dashboard)/_com/selectIcon.tsx @@ -3,16 +3,20 @@ import { Box, rem, Select } from '@mantine/core'; import { + IconCash, IconChartLine, IconChristmasTreeFilled, IconClipboardTextFilled, IconDroplet, IconHome, IconHomeEco, + IconHospital, IconLeaf, IconRecycle, IconScale, + IconSchool, IconShieldFilled, + IconShoppingCart, IconTent, IconTrashFilled, IconTree, @@ -32,13 +36,17 @@ const iconMap = { scale: { label: 'Scale', icon: IconScale }, clipboard: { label: 'Clipboard', icon: IconClipboardTextFilled }, trash: { label: 'Trash', icon: IconTrashFilled }, - lingkunganSehat: {label: 'Lingkungan Sehat', icon: IconHomeEco}, - sumberOksigen: {label: 'Sumber Oksigen', icon: IconChristmasTreeFilled}, - ekonomiBerkelanjutan: {label: 'Ekonomi Berkelanjutan', icon: IconTrendingUp}, - mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled}, - rumah: {label: 'Rumah', icon: IconHome}, - pohon: {label: 'Pohon', icon: IconTree}, - air: {label: 'Air', icon: IconDroplet} + lingkunganSehat: { label: 'Lingkungan Sehat', icon: IconHomeEco }, + sumberOksigen: { label: 'Sumber Oksigen', icon: IconChristmasTreeFilled }, + ekonomiBerkelanjutan: { label: 'Ekonomi Berkelanjutan', icon: IconTrendingUp }, + mencegahBencana: { label: 'Mencegah Bencana', icon: IconShieldFilled }, + rumah: { label: 'Rumah', icon: IconHome }, + pohon: { label: 'Pohon', icon: IconTree }, + air: { label: 'Air', icon: IconDroplet }, + bantuan: { label: 'Bantuan', icon: IconCash }, + pelatihan: { label: 'Pelatihan', icon: IconSchool }, + subsidi: { label: 'Subsidi', icon: IconShoppingCart }, + layananKesehatan: { label: 'Layanan Kesehatan', icon: IconHospital }, }; diff --git a/src/app/admin/(dashboard)/_com/selectIconEdit.tsx b/src/app/admin/(dashboard)/_com/selectIconEdit.tsx index 44344b6a..368d1088 100644 --- a/src/app/admin/(dashboard)/_com/selectIconEdit.tsx +++ b/src/app/admin/(dashboard)/_com/selectIconEdit.tsx @@ -2,16 +2,20 @@ import { Box, rem, Select } from '@mantine/core'; import { + IconCash, IconChartLine, IconChristmasTreeFilled, IconClipboardTextFilled, IconDroplet, IconHome, IconHomeEco, + IconHospital, IconLeaf, IconRecycle, IconScale, + IconSchool, IconShieldFilled, + IconShoppingCart, IconTent, IconTrashFilled, IconTree, @@ -36,7 +40,11 @@ const iconMap = { mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled}, rumah: {label: 'Rumah', icon: IconHome}, pohon: {label: 'Pohon', icon: IconTree}, - air: {label: 'Air', icon: IconDroplet} + air: {label: 'Air', icon: IconDroplet}, + bantuan: {label: 'Bantuan', icon: IconCash}, + pelatihan: {label: 'Pelatihan', icon: IconSchool}, + subsidi: {label: 'Subsidi', icon: IconShoppingCart}, + layananKesehatan: {label: 'Layanan Kesehatan', icon: IconHospital}, }; type IconKey = keyof typeof iconMap; diff --git a/src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts b/src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts index 8814fe8d..bf29247b 100644 --- a/src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts +++ b/src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import ApiFetch from "@/lib/api-fetch"; import { Prisma } from "@prisma/client"; import { toast } from "react-toastify"; @@ -71,12 +72,37 @@ const demografiPekerjaan = proxy({ omit: { isActive: true }; }>[] | null, - async load() { - const res = await ApiFetch.api.ekonomi.demografipekerjaan[ - "find-many" - ].get(); - if (res.status === 200) { - demografiPekerjaan.findMany.data = res.data?.data ?? []; + page: 1, + totalPages: 1, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + demografiPekerjaan.findMany.loading = true; // ✅ Akses langsung via nama path + demografiPekerjaan.findMany.page = page; + demografiPekerjaan.findMany.search = search; + + try { + const query: any = { page, limit }; + if (search) query.search = search; + + const res = await ApiFetch.api.ekonomi.demografipekerjaan[ + "find-many" + ].get({ query }); + + if (res.status === 200 && res.data?.success) { + demografiPekerjaan.findMany.data = res.data.data ?? []; + demografiPekerjaan.findMany.totalPages = + res.data.totalPages ?? 1; + } else { + demografiPekerjaan.findMany.data = []; + demografiPekerjaan.findMany.totalPages = 1; + } + } catch (err) { + console.error("Gagal fetch demografi pekerjaan paginated:", err); + demografiPekerjaan.findMany.data = []; + demografiPekerjaan.findMany.totalPages = 1; + } finally { + demografiPekerjaan.findMany.loading = false; } }, }, @@ -194,4 +220,4 @@ const demografiPekerjaan = proxy({ }, }, }); -export default demografiPekerjaan +export default demografiPekerjaan; diff --git a/src/app/admin/(dashboard)/_state/ekonomi/jumlah-penduduk-miskin.ts b/src/app/admin/(dashboard)/_state/ekonomi/jumlah-penduduk-miskin.ts index bbb1dfa8..2eb11a03 100644 --- a/src/app/admin/(dashboard)/_state/ekonomi/jumlah-penduduk-miskin.ts +++ b/src/app/admin/(dashboard)/_state/ekonomi/jumlah-penduduk-miskin.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import ApiFetch from "@/lib/api-fetch"; import { Prisma } from "@prisma/client"; import { toast } from "react-toastify"; @@ -69,16 +70,37 @@ const jumlahPendudukMiskin = proxy({ select: { id: true; year: true; totalPoorPopulation: true }; }>[] | null, - loading: false, - async load() { - const res = await ApiFetch.api.ekonomi.jumlahpendudukmiskin[ - "find-many" - ].get(); - if (res.status === 200) { - jumlahPendudukMiskin.findMany.data = res.data?.data ?? []; - } + page: 1, + totalPages: 1, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + jumlahPendudukMiskin.findMany.loading = true; // ✅ Akses langsung via nama path + jumlahPendudukMiskin.findMany.page = page; + jumlahPendudukMiskin.findMany.search = search; + + try { + const query: any = { page, limit }; + if (search) query.search = search; + + const res = await ApiFetch.api.ekonomi.jumlahpendudukmiskin["find-many"].get({ query }); + + if (res.status === 200 && res.data?.success) { + jumlahPendudukMiskin.findMany.data = res.data.data ?? []; + jumlahPendudukMiskin.findMany.totalPages = res.data.totalPages ?? 1; + } else { + jumlahPendudukMiskin.findMany.data = []; + jumlahPendudukMiskin.findMany.totalPages = 1; + } + } catch (err) { + console.error("Gagal fetch jumlah penduduk miskin paginated:", err); + jumlahPendudukMiskin.findMany.data = []; + jumlahPendudukMiskin.findMany.totalPages = 1; + } finally { + jumlahPendudukMiskin.findMany.loading = false; + } + }, }, - }, findUnique: { data: null as Prisma.GrafikJumlahPendudukMiskinGetPayload<{ select: { id: true; year: true; totalPoorPopulation: true }; diff --git a/src/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan.ts b/src/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan.ts index 0da2a711..1332bbea 100644 --- a/src/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan.ts +++ b/src/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan.ts @@ -8,7 +8,7 @@ import { z } from "zod"; const templateForm = z.object({ nama: z.string().min(1, "Nama minimal 1 karakter"), deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"), - ikonUrl: z.string().optional(), + icon: z.string().min(1, "Icon minimal 1 karakter"), statistik: z.object({ tahun: z.string().min(1, "Tahun minimal 1 karakter"), jumlah: z.string().min(1, "Jumlah minimal 1 karakter"), @@ -18,7 +18,7 @@ const templateForm = z.object({ const defaultForm = { nama: "", deskripsi: "", - ikonUrl: "", + icon: "", statistik: { tahun: "", jumlah: "", @@ -148,7 +148,7 @@ const programKemiskinanState = proxy({ this.form = { nama: data.nama, deskripsi: data.deskripsi, - ikonUrl: data.ikonUrl || "", + icon: data.icon, statistik: { tahun: data.statistik.tahun, jumlah: data.statistik.jumlah, @@ -189,7 +189,7 @@ const programKemiskinanState = proxy({ body: JSON.stringify({ nama: this.form.nama, deskripsi: this.form.deskripsi, - ikonUrl: this.form.ikonUrl, + icon: this.form.icon, statistik: { tahun: this.form.statistik.tahun, jumlah: this.form.statistik.jumlah, diff --git a/src/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa.ts b/src/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa.ts index b198f66f..341398f0 100644 --- a/src/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa.ts +++ b/src/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import ApiFetch from "@/lib/api-fetch"; import { Prisma } from "@prisma/client"; import { toast } from "react-toastify"; @@ -76,13 +77,37 @@ const grafikSektorUnggulan = proxy({ }; }>[] | null, + page: 1, + totalPages: 1, loading: false, - async load() { - const res = await ApiFetch.api.ekonomi.sektourunggulandesa[ - "find-many" - ].get(); - if (res.status === 200) { - grafikSektorUnggulan.findMany.data = res.data?.data ?? []; + search: "", + load: async (page = 1, limit = 10, search = "") => { + grafikSektorUnggulan.findMany.loading = true; // ✅ Akses langsung via nama path + grafikSektorUnggulan.findMany.page = page; + grafikSektorUnggulan.findMany.search = search; + + try { + const query: any = { page, limit }; + if (search) query.search = search; + + const res = await ApiFetch.api.ekonomi.sektourunggulandesa[ + "find-many" + ].get({ query }); + + if (res.status === 200 && res.data?.success) { + grafikSektorUnggulan.findMany.data = res.data.data ?? []; + grafikSektorUnggulan.findMany.totalPages = + res.data.totalPages ?? 1; + } else { + grafikSektorUnggulan.findMany.data = []; + grafikSektorUnggulan.findMany.totalPages = 1; + } + } catch (err) { + console.error("Gagal fetch sektor unggulan desa paginated:", err); + grafikSektorUnggulan.findMany.data = []; + grafikSektorUnggulan.findMany.totalPages = 1; + } finally { + grafikSektorUnggulan.findMany.loading = false; } }, }, diff --git a/src/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur.ts b/src/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur.ts index 37e87cf4..52cd2f92 100644 --- a/src/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur.ts +++ b/src/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import ApiFetch from "@/lib/api-fetch"; import { Prisma } from "@prisma/client"; import { toast } from "react-toastify"; @@ -75,16 +76,37 @@ const grafikBerdasarkanUsiaKerjaNganggur = proxy({ omit: { isActive: true }; }>[] | null, - loading: false, - async load() { - const res = await ApiFetch.api.ekonomi.grafikusiakerjayangmenganggur[ - "find-many" - ].get(); - if (res.status === 200) { - grafikBerdasarkanUsiaKerjaNganggur.findMany.data = res.data?.data ?? []; - } + page: 1, + totalPages: 1, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + grafikBerdasarkanUsiaKerjaNganggur.findMany.loading = true; // ✅ Akses langsung via nama path + grafikBerdasarkanUsiaKerjaNganggur.findMany.page = page; + grafikBerdasarkanUsiaKerjaNganggur.findMany.search = search; + + try { + const query: any = { page, limit }; + if (search) query.search = search; + + const res = await ApiFetch.api.ekonomi.grafikusiakerjayangmenganggur["find-many"].get({ query }); + + if (res.status === 200 && res.data?.success) { + grafikBerdasarkanUsiaKerjaNganggur.findMany.data = res.data.data ?? []; + grafikBerdasarkanUsiaKerjaNganggur.findMany.totalPages = res.data.totalPages ?? 1; + } else { + grafikBerdasarkanUsiaKerjaNganggur.findMany.data = []; + grafikBerdasarkanUsiaKerjaNganggur.findMany.totalPages = 1; + } + } catch (err) { + console.error("Gagal fetch grafik berdasarkan usia kerja yang menganggur paginated:", err); + grafikBerdasarkanUsiaKerjaNganggur.findMany.data = []; + grafikBerdasarkanUsiaKerjaNganggur.findMany.totalPages = 1; + } finally { + grafikBerdasarkanUsiaKerjaNganggur.findMany.loading = false; + } + }, }, - }, findUnique: { data: null as Prisma.GrafikMenganggurBerdasarkanUsiaGetPayload<{ omit: { isActive: true }; @@ -259,15 +281,36 @@ const grafikBerdasarkanPendidikan = proxy({ omit: { isActive: true }; }>[] | null, - loading: false, - async load() { - const res = await ApiFetch.api.ekonomi.grafikmenganggurberdasarkanpendidikan[ - "find-many" - ].get(); - if (res.status === 200) { - grafikBerdasarkanPendidikan.findMany.data = res.data?.data ?? []; - } - }, + page: 1, + totalPages: 1, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + grafikBerdasarkanPendidikan.findMany.loading = true; // ✅ Akses langsung via nama path + grafikBerdasarkanPendidikan.findMany.page = page; + grafikBerdasarkanPendidikan.findMany.search = search; + + try { + const query: any = { page, limit }; + if (search) query.search = search; + + const res = await ApiFetch.api.ekonomi.grafikmenganggurberdasarkanpendidikan["find-many"].get({ query }); + + if (res.status === 200 && res.data?.success) { + grafikBerdasarkanPendidikan.findMany.data = res.data.data ?? []; + grafikBerdasarkanPendidikan.findMany.totalPages = res.data.totalPages ?? 1; + } else { + grafikBerdasarkanPendidikan.findMany.data = []; + grafikBerdasarkanPendidikan.findMany.totalPages = 1; + } + } catch (err) { + console.error("Gagal fetch grafik berdasarkan pendidikan paginated:", err); + grafikBerdasarkanPendidikan.findMany.data = []; + grafikBerdasarkanPendidikan.findMany.totalPages = 1; + } finally { + grafikBerdasarkanPendidikan.findMany.loading = false; + } + }, }, findUnique: { data: null as Prisma.GrafikMenganggurBerdasarkanPendidikanGetPayload<{ diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/[id]/page.tsx index fbe60162..20e7e339 100644 --- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/[id]/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/[id]/page.tsx @@ -1,8 +1,17 @@ /* eslint-disable react-hooks/exhaustive-deps */ -'use client' +'use client'; import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + TextInput, + Title, + Tooltip +} from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useEffect } from 'react'; @@ -11,33 +20,33 @@ import { useProxy } from 'valtio/utils'; import demografiPekerjaan from '../../../_state/ekonomi/demografi-pekerjaan'; function EditDemografiPekerjaan() { - const router = useRouter() - const params = useParams() as { id: string } - const stateDemografi = useProxy(demografiPekerjaan) + const router = useRouter(); + const params = useParams() as { id: string }; + const stateDemografi = useProxy(demografiPekerjaan); - const id = params.id + const id = params.id; useEffect(() => { if (!id) return; stateDemografi.update.id = id; - stateDemografi.findUnique.load(id) + stateDemografi.findUnique + .load(id) .then(() => { const data = stateDemografi.findUnique.data; if (data) { stateDemografi.update.form = { pekerjaan: String(data.pekerjaan || ''), lakiLaki: Number(data.lakiLaki || 0), - perempuan: Number(data.perempuan || 0) + perempuan: Number(data.perempuan || 0), }; } }) - .catch(error => { + .catch((error) => { console.error('Error loading data:', error); toast.error('Gagal memuat data'); }); }, [id]); - // Di handleSubmit, ubah menjadi: const handleSubmit = async () => { try { stateDemografi.update.id = id; @@ -51,52 +60,88 @@ function EditDemografiPekerjaan() { }; return ( - - - - - - - Edit Demografi Pekerjaan + + {/* Header */} + + + + + + Edit Demografi Pekerjaan + + + + {/* Form Card */} + + { - stateDemografi.update.form.pekerjaan = val.currentTarget.value; - }} + onChange={(e) => + (stateDemografi.update.form.pekerjaan = e.currentTarget.value) + } + required /> + { - stateDemografi.update.form.lakiLaki = Number(val.currentTarget.value); - }} + onChange={(e) => + (stateDemografi.update.form.lakiLaki = Number( + e.currentTarget.value + )) + } + required /> + { - stateDemografi.update.form.perempuan = Number(val.currentTarget.value); - }} + onChange={(e) => + (stateDemografi.update.form.perempuan = Number( + e.currentTarget.value + )) + } + required /> - + + + + - ) + ); } export default EditDemografiPekerjaan; diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/create/page.tsx index 83532936..f7ef972e 100644 --- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/create/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/create/page.tsx @@ -1,8 +1,18 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ -'use client' +'use client'; + import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + TextInput, + Title, + Tooltip, +} from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; @@ -12,15 +22,15 @@ import demografiPekerjaan from '../../../_state/ekonomi/demografi-pekerjaan'; function CreateDemografiPekerjaan() { const stateDemografi = useProxy(demografiPekerjaan); const [chartData, setChartData] = useState([]); - const router = useRouter() + const router = useRouter(); const resetForm = () => { stateDemografi.create.form = { - pekerjaan: "", + pekerjaan: '', lakiLaki: 0, perempuan: 0, - } - } + }; + }; const handleSubmit = async () => { const id = await stateDemografi.create.create(); @@ -32,58 +42,85 @@ function CreateDemografiPekerjaan() { } } resetForm(); - router.push("/admin/ekonomi/demografi-pekerjaan"); - } + router.push('/admin/ekonomi/demografi-pekerjaan'); + }; + return ( - - - - - - - Tambah Demografi Pekerjaan - - { - stateDemografi.create.form.pekerjaan = val.currentTarget.value; + + {/* Header */} + + + + + + Tambah Demografi Pekerjaan + + + + {/* Form */} + + + { + stateDemografi.create.form.pekerjaan = val.currentTarget.value; + }} + required + /> + { + stateDemografi.create.form.lakiLaki = Number(val.currentTarget.value); + }} + required + /> + { + stateDemografi.create.form.perempuan = Number(val.currentTarget.value); + }} + required + /> + + + - - - - + > + Simpan + + + + ); } diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx index 1db38044..cc679025 100644 --- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx @@ -1,14 +1,32 @@ 'use client' import colors from '@/con/colors'; import { BarChart } from '@mantine/charts'; -import { Box, Button, Paper, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; +import { + Box, + Button, + Center, + Group, + Paper, + Skeleton, + Stack, + Table, + TableTbody, + TableTd, + TableTh, + TableThead, + TableTr, + Text, + Title, + Tooltip, + Pagination, + Flex, +} from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react'; +import { IconEdit, IconPlus, IconSearch, IconTrash } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '../../_com/header'; -import JudulList from '../../_com/judulList'; import { ModalKonfirmasiHapus } from '../../_com/modalKonfirmasiHapus'; import demografiPekerjaan from '../../_state/ekonomi/demografi-pekerjaan'; @@ -18,7 +36,7 @@ function DemografiPekerjaan() { } value={search} onChange={(e) => setSearch(e.currentTarget.value)} @@ -34,131 +52,193 @@ function ListDemografiPekerjaan({ search }: { search: string }) { pekerjaan: string; lakiLaki: number; perempuan: number; - } + }; const router = useRouter(); - const stateDemografi = useProxy(demografiPekerjaan) + const stateDemografi = useProxy(demografiPekerjaan); const [chartData, setChartData] = useState([]); - const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready - const [modalHapus, setModalHapus] = useState(false) - const [selectedId, setSelectedId] = useState(null) + const [mounted, setMounted] = useState(false); + const [modalHapus, setModalHapus] = useState(false); + const [selectedId, setSelectedId] = useState(null); + + const { + data, + page, + totalPages, + loading, + load, + } = stateDemografi.findMany; const handleDelete = () => { if (selectedId) { - stateDemografi.delete.byId(selectedId) - setModalHapus(false) - setSelectedId(null) - - stateDemografi.findMany.load() + stateDemografi.delete.byId(selectedId); + setModalHapus(false); + setSelectedId(null); } - } + }; useShallowEffect(() => { - setMounted(true) - stateDemografi.findMany.load() - }, []) + setMounted(true); + load(page, 10, search); + }, [page, search]); useEffect(() => { - setMounted(true); - if (stateDemografi.findMany.data) { - setChartData(stateDemografi.findMany.data.map((item) => ({ - id: item.id, - pekerjaan: item.pekerjaan, - lakiLaki: Number(item.lakiLaki), - perempuan: Number(item.perempuan), - }))); + if (data) { + setChartData( + data.map((item) => ({ + id: item.id, + pekerjaan: item.pekerjaan, + lakiLaki: Number(item.lakiLaki), + perempuan: Number(item.perempuan), + })) + ); } - }, [stateDemografi.findMany.data]); + }, [data]); - const filteredData = (stateDemografi.findMany.data || []).filter(item => { - const keyword = search.toLowerCase(); + const filteredData = data || []; + + if (loading || !data) { return ( - item.pekerjaan.toLowerCase().includes(keyword) || - item.lakiLaki.toString().toLowerCase().includes(keyword) || - item.perempuan.toString().toLowerCase().includes(keyword) + + + ); - }); + } + return ( - - - - - - Pekerjaan - Jumlah Pekerja Laki - Laki - Jumlah Pekerja Perempuan - Edit - Delete - - - - {filteredData.map((item) => ( - - {item.pekerjaan} - {item.lakiLaki} - {item.perempuan} - - - - - - + + + List Demografi Pekerjaan + + + + + + +
+ + + Pekerjaan + Laki - Laki + Perempuan + Edit + Hapus - ))} - -
+ + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( + + {item.pekerjaan} + {item.lakiLaki} + {item.perempuan} + + + + + + + + )) + ) : ( + + +
+ Tidak ada data demografi pekerjaan yang cocok +
+
+
+ )} +
+ +
+ {/* Pagination */} +
+ { + load(newPage, 10, search); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + mt="md" + mb="md" + color="blue" + radius="md" + /> +
+ {/* Chart */} - {!mounted && !chartData ? ( - - - Data Kelahiran & Kematian - Belum ada data untuk ditampilkan dalam grafik - - - ) : ( - - - Data Kelahiran & Kematian - {mounted && chartData.length > 0 && ( - - - + + + + + Grafik Demografi Pekerjaan + + {mounted && chartData.length > 0 ? ( + + ) : ( + Belum ada data untuk ditampilkan dalam grafik )} - - - )} + + + + + Laki - Laki + + + + Perempuan + + + + + + {/* Modal Konfirmasi Hapus */} setModalHapus(false)} onConfirm={handleDelete} - text='Apakah anda yakin ingin menghapus demografi pekerjaan ini?' + text="Apakah anda yakin ingin menghapus demografi pekerjaan ini?" />
); diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/[id]/page.tsx index 4b2f0705..cdcbc699 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/[id]/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/[id]/page.tsx @@ -3,78 +3,116 @@ import jumlahPendudukMiskin from '@/app/admin/(dashboard)/_state/ekonomi/jumlah-penduduk-miskin'; import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, TextInput, Title } from '@mantine/core'; +import { Box, Button, Paper, Stack, TextInput, Title, Group, Tooltip } from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useEffect } from 'react'; import { useProxy } from 'valtio/utils'; +import { toast } from 'react-toastify'; function EditJumlahPendudukMiskin() { - const router = useRouter() - const params = useParams() as { id: string } - const stateJPM = useProxy(jumlahPendudukMiskin) + const router = useRouter(); + const params = useParams() as { id: string }; + const stateJPM = useProxy(jumlahPendudukMiskin); - const id = params.id + const id = params.id; - // Load data saat komponen mount useEffect(() => { - if (id) { - stateJPM.findUnique.load(id).then(() => { - const data = stateJPM.findUnique.data + if (!id) return; + + const loadData = async () => { + try { + await stateJPM.findUnique.load(id); + const data = stateJPM.findUnique.data; if (data) { stateJPM.update.form = { year: data.year || 0, totalPoorPopulation: data.totalPoorPopulation || 0, - } + }; } - }) - } - }, [id]) + } catch (error) { + console.error('Gagal memuat data:', error); + toast.error('Gagal memuat data jumlah penduduk miskin'); + } + }; + + loadData(); + }, [id]); const handleSubmit = async () => { - // Set the ID before submitting - stateJPM.update.id = id; - await stateJPM.update.submit(); - router.push('/admin/ekonomi/jumlah-penduduk-miskin') - } -return ( - - - - - - - Edit Jumlah Penduduk Miskin + try { + stateJPM.update.id = id; + await stateJPM.update.submit(); + toast.success('Data jumlah penduduk miskin berhasil diperbarui!'); + router.push('/admin/ekonomi/jumlah-penduduk-miskin'); + } catch (error) { + console.error('Gagal menyimpan data:', error); + toast.error('Terjadi kesalahan saat menyimpan data'); + } + }; + + return ( + + + + + + + Edit Jumlah Penduduk Miskin + + + + + { stateJPM.update.form.year = Number(val.currentTarget.value); }} /> + { stateJPM.update.form.totalPoorPopulation = Number(val.currentTarget.value); }} /> - + + + + - ) + ); } export default EditJumlahPendudukMiskin; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/create/page.tsx index 7845d646..d045d1d6 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/create/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/create/page.tsx @@ -1,26 +1,25 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ -'use client' -import grafikkepuasan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/grafikKepuasan'; -import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, TextInput, Title } from '@mantine/core'; +'use client'; +import { Box, Button, Group, Paper, Stack, TextInput, Title, Tooltip } from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { useProxy } from 'valtio/utils'; +import colors from '@/con/colors'; import jumlahPendudukMiskin from '../../../_state/ekonomi/jumlah-penduduk-miskin'; -function CreateJumlahPendudukMiskin() { +export default function CreateJumlahPendudukMiskin() { const stateJPM = useProxy(jumlahPendudukMiskin); const [chartData, setChartData] = useState([]); - const router = useRouter() + const router = useRouter(); const resetForm = () => { stateJPM.create.form = { - year: new Date().getFullYear(), // Default to current year + year: new Date().getFullYear(), totalPoorPopulation: 0, - } - } + }; + }; const handleSubmit = async () => { const id = await stateJPM.create.create(); @@ -32,52 +31,72 @@ function CreateJumlahPendudukMiskin() { } } resetForm(); - router.push("/admin/ekonomi/jumlah-penduduk-miskin"); - } + router.push('/admin/ekonomi/jumlah-penduduk-miskin'); + }; + return ( - - - - - - - Tambah Grafik Hasil Kepuasan Masyarakat - - { - const value = val.currentTarget.value; - stateJPM.create.form.year = value ? Number(value) : 0; + + {/* Header */} + + + + + + Tambah Jumlah Penduduk Miskin + + + + {/* Form Paper */} + + + { + const value = e.currentTarget.value; + stateJPM.create.form.year = value ? Number(value) : 0; + }} + required + /> + + { + stateJPM.create.form.totalPoorPopulation = Number(e.currentTarget.value); + }} + required + /> + + + - - - - + > + Simpan + + + + ); } - -export default CreateJumlahPendudukMiskin; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/page.tsx index a0d22e7c..498a8ce4 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/page.tsx @@ -1,15 +1,14 @@ '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 { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react'; import HeaderSearch from '../../_com/header'; -import JudulList from '../../_com/judulList'; import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; -import { useMediaQuery, useShallowEffect } from '@mantine/hooks'; +import { useShallowEffect, useMediaQuery } from '@mantine/hooks'; import { useProxy } from 'valtio/utils'; import jumlahPendudukMiskin from '../../_state/ekonomi/jumlah-penduduk-miskin'; -import { Bar, BarChart, Legend, XAxis, YAxis, Tooltip } from 'recharts'; +import { Bar, BarChart, Legend, XAxis, YAxis, Tooltip as RechartsTooltip } from 'recharts'; import { ModalKonfirmasiHapus } from '../../_com/modalKonfirmasiHapus'; function JumlahPendudukMiskin() { @@ -18,7 +17,7 @@ function JumlahPendudukMiskin() { } value={search} onChange={(e) => setSearch(e.currentTarget.value)} @@ -29,138 +28,158 @@ function JumlahPendudukMiskin() { } function ListJumlahPendudukMiskin({ search }: { search: string }) { - type JPMGrafik = { - id: string; - year: number; - totalPoorPopulation: number; - } + type JPMGrafik = { id: string; year: number; totalPoorPopulation: number } const stateJPM = useProxy(jumlahPendudukMiskin); const [chartData, setChartData] = useState([]); - const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready - const isTablet = useMediaQuery('(max-width: 1024px)') - const isMobile = useMediaQuery('(max-width: 768px)') - const [modalHapus, setModalHapus] = useState(false) - const [selectedId, setSelectedId] = useState(null) + const [mounted, setMounted] = useState(false); + const [modalHapus, setModalHapus] = useState(false); + const [selectedId, setSelectedId] = useState(null); const router = useRouter(); - const handleDelete = () => { - if (selectedId) { - stateJPM.delete.byId(selectedId) - setModalHapus(false) - setSelectedId(null) - - stateJPM.findMany.load() - } - } + const isTablet = useMediaQuery('(max-width:1024px)'); + const isMobile = useMediaQuery('(max-width:768px)'); + const { + data, + page, + loading, + load, + totalPages, + } = stateJPM.findMany; + // Load data useShallowEffect(() => { - setMounted(true) - stateJPM.findMany.load() - }, []) + setMounted(true); + load(page, 10, search); + }, [page, search]); useEffect(() => { - setMounted(true); if (stateJPM.findMany.data) { - setChartData(stateJPM.findMany.data.map((item) => ({ + setChartData(stateJPM.findMany.data.map(item => ({ id: item.id, year: Number(item.year), - totalPoorPopulation: Number(item.totalPoorPopulation), + totalPoorPopulation: Number(item.totalPoorPopulation) }))); } }, [stateJPM.findMany.data]); - const filteredData = (stateJPM.findMany.data || []).filter(item => { - const keyword = search.toLowerCase(); - return ( - item.year.toString().toLowerCase().includes(keyword) || - item.totalPoorPopulation.toString().toLowerCase().includes(keyword) - ); - }); + const filteredData = data || [] - if (!stateJPM.findMany.data) { + const handleDelete = () => { + if (selectedId) { + stateJPM.delete.byId(selectedId); + setModalHapus(false); + setSelectedId(null); + stateJPM.findMany.load(); + } + } + + if (loading || !data) { return ( - - + + - ) + ); } return ( - - - - + + + Daftar Jumlah Penduduk Miskin + + + + + + +
- Tahun - Jumlah Penduduk Miskin - Edit - Delete + Tahun + Jumlah Penduduk Miskin + Edit + Delete - {filteredData.map((item) => ( + {filteredData.length > 0 ? filteredData.map(item => ( {item.year} {item.totalPoorPopulation} - - - ))} + )) : ( + + +
+ Tidak ada data yang cocok +
+
+
+ )}
-
+
+
- {/* Chart */} - {!mounted && !chartData ? ( - - - Grafik Jumlah Penduduk Miskin - Belum ada data untuk ditampilkan dalam grafik - - - ) : ( - - - Grafik Jumlah Penduduk Miskin - {mounted && chartData.length > 0 && ( - - - - - - - - )} - - - )} - +
+ { + load(newPage, 10); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + mt="md" + mb="md" + color="blue" + radius="md" + /> +
- {/* Modal Konfirmasi Hapus */} + {/* Chart */} + + + + Grafik Jumlah Penduduk Miskin + {mounted && chartData.length > 0 ? ( + + + + + + + + ) : ( + Belum ada data untuk ditampilkan dalam grafik + )} + + + + + + {/* Modal Hapus */} setModalHapus(false)} onConfirm={handleDelete} - text='Apakah anda yakin ingin menghapus grafik jumlah penduduk miskin ini?' + text='Apakah anda yakin ingin menghapus data ini?' />
); diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/_lib/layoutTabs.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/_lib/layoutTabs.tsx index 82508a8e..8b884c50 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/_lib/layoutTabs.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/_lib/layoutTabs.tsx @@ -1,62 +1,124 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core'; +import { + Stack, + Tabs, + TabsList, + TabsPanel, + TabsTab, + Title, + Tooltip, + ScrollArea, +} from '@mantine/core'; import { usePathname, useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; +import { IconUsers, IconSchool } from '@tabler/icons-react'; function LayoutTabs({ children }: { children: React.ReactNode }) { - const router = useRouter() - const pathname = usePathname() - const tabs = [ - { - label: "Pengangguran Berdasarkan Usia", - value: "pengangguranberdasarkanusia", - href: "/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia" - }, - { - label: "Pengangguran Berdasarkan Pendidikan", - value: "pengangguranberdasarkanpendidikan", - href: "/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan" - }, - ]; - const curentTab = tabs.find(tab => tab.href === pathname) - const [activeTab, setActiveTab] = useState(curentTab?.value || tabs[0].value); + const router = useRouter(); + const pathname = usePathname(); - const handleTabChange = (value: string | null) => { - const tab = tabs.find(t => t.value === value) - if (tab) { - router.push(tab.href) - } - setActiveTab(value) - } + const tabs = [ + { + label: "Pengangguran Berdasarkan Usia", + value: "pengangguranberdasarkanusia", + href: "/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia", + icon: , + tooltip: "Data pengangguran menurut kelompok usia", + }, + { + label: "Pengangguran Berdasarkan Pendidikan", + value: "pengangguranberdasarkanpendidikan", + href: "/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan", + icon: , + tooltip: "Data pengangguran menurut tingkat pendidikan", + }, + ]; - useEffect(() => { - const match = tabs.find(tab => tab.href === pathname) - if (match) { - setActiveTab(match.value) - } - }, [pathname]) + const currentTab = tabs.find(tab => tab.href === pathname); + const [activeTab, setActiveTab] = useState(currentTab?.value || tabs[0].value); - return ( - - Jumlah Penduduk Usia Kerja yang Menganggur - - - {tabs.map((e, i) => ( - {e.label} - ))} - - {tabs.map((e, i) => ( - - {/* Konten dummy, bisa diganti tergantung routing */} - <> - - ))} - + const handleTabChange = (value: string | null) => { + const tab = tabs.find(t => t.value === value); + if (tab) router.push(tab.href); + setActiveTab(value); + }; + + useEffect(() => { + const match = tabs.find(tab => tab.href === pathname); + if (match) setActiveTab(match.value); + }, [pathname]); + + return ( + + + Jumlah Penduduk Usia Kerja yang Menganggur + + + + + + {tabs.map((tab, i) => ( + + + {tab.label} + + + ))} + + + + {tabs.map((tab, i) => ( + {children} - - ); + + ))} + + + ); } -export default LayoutTabs; \ No newline at end of file +export default LayoutTabs; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/[id]/page.tsx index d6233ad5..5d58837e 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/[id]/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/[id]/page.tsx @@ -1,108 +1,117 @@ -'use client' +'use client'; import grafikNganggur from '@/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur'; /* eslint-disable react-hooks/exhaustive-deps */ - import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, TextInput, Title } from '@mantine/core'; +import { Box, Button, Group, Paper, Stack, TextInput, Title, Tooltip } from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useEffect } from 'react'; import { useProxy } from 'valtio/utils'; function EditGrafikBerdasarkanPendidikan() { - const router = useRouter() - const params = useParams() as { id: string } - const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan) - const id = params.id + const router = useRouter(); + const params = useParams() as { id: string }; + const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan); + const id = params.id; useEffect(() => { - if(id){ + if (id) { stategrafik.findUnique.load(id).then(() => { - const data = stategrafik.findUnique.data - if(data){ + const data = stategrafik.findUnique.data; + if (data) { stategrafik.update.form = { SD: data.SD || '', SMP: data.SMP || '', SMA: data.SMA || '', D3: data.D3 || '', S1: data.S1 || '', - } + }; } - }) + }); } - }, [id]) + }, [id]); const handleSubmit = async () => { stategrafik.update.id = id; await stategrafik.update.submit(); - router.push('/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan') - } + router.push('/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan'); + }; return ( - - - + + + + + + + Edit Grafik Pengangguran Berdasarkan Pendidikan + + + + + + (stategrafik.update.form.SD = val.currentTarget.value)} + /> + (stategrafik.update.form.SMP = val.currentTarget.value)} + /> + (stategrafik.update.form.SMA = val.currentTarget.value)} + /> + (stategrafik.update.form.D3 = val.currentTarget.value)} + /> + (stategrafik.update.form.S1 = val.currentTarget.value)} + /> + + + + + + - - - Edit Grafik Pengangguran Berdasarkan Pendidikan - { - stategrafik.update.form.SD = val.currentTarget.value; - }} - /> - { - stategrafik.update.form.SMP = val.currentTarget.value; - }} - /> - { - stategrafik.update.form.SMA = val.currentTarget.value; - }} - /> - { - stategrafik.update.form.D3 = val.currentTarget.value; - }} - /> - { - stategrafik.update.form.S1 = val.currentTarget.value; - }} - /> - - - - ); } diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/create/page.tsx index 2bbf63e9..d62b2de1 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/create/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/create/page.tsx @@ -1,32 +1,30 @@ -'use client' +'use client'; /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ import React from 'react'; import { useRouter } from 'next/navigation'; -import grafikBerdasarkanJenisKelamin from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin'; +import grafikNganggur from '@/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur'; import { useProxy } from 'valtio/utils'; import { useState } from 'react'; import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Title, TextInput } from '@mantine/core'; +import { Box, Button, Paper, Stack, Title, TextInput, Group, Tooltip } from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; -import grafikNganggur from '@/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur'; - function CreateGrafikBerdasarkanPendidikan() { const router = useRouter(); - const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan) + const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan); const [donutData, setDonutData] = useState([]); const resetForm = () => { stategrafik.create.form = { ...stategrafik.create.form, - SD: "", - SMP: "", - SMA: "", - D3: "", - S1: "", - } - } + SD: '', + SMP: '', + SMA: '', + D3: '', + S1: '', + }; + }; const handleSubmit = async () => { const id = await stategrafik.create.create(); @@ -38,73 +36,91 @@ function CreateGrafikBerdasarkanPendidikan() { } } resetForm(); - router.push("/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan") - } + router.push( + '/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan' + ); + }; + return ( - - - - - - - Create Grafik Pengangguran Berdasarkan Pendidikan - { - stategrafik.create.form.SD = val.currentTarget.value; - }} - /> - { - stategrafik.create.form.SMP = val.currentTarget.value; - }} - /> - { - stategrafik.create.form.SMA = val.currentTarget.value; - }} - /> - { - stategrafik.create.form.D3 = val.currentTarget.value; - }} - /> - { - stategrafik.create.form.S1 = val.currentTarget.value; - }} - /> - - - - + + + + + + + Tambah Data Pengangguran Berdasarkan Pendidikan + + + + + + (stategrafik.create.form.SD = val.currentTarget.value)} + required + /> + (stategrafik.create.form.SMP = val.currentTarget.value)} + required + /> + (stategrafik.create.form.SMA = val.currentTarget.value)} + required + /> + (stategrafik.create.form.D3 = val.currentTarget.value)} + required + /> + (stategrafik.create.form.S1 = val.currentTarget.value)} + required + /> + + + + + + + ); } diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/page.tsx index fc50e09c..328a19da 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/page.tsx @@ -1,59 +1,62 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Flex, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; +import { Box, Button, Center, Flex, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title, Tooltip } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react'; +import { IconEdit, IconPlus, IconSearch, IconTrash } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { Cell, Pie, PieChart } from 'recharts'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '../../../_com/header'; -import JudulList from '../../../_com/judulList'; import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; import grafikNganggur from '../../../_state/ekonomi/usia-kerja-nganggur'; function GrafikBerdasarkanPendidikan() { - const [search, setSearch] = useState("") + const [search, setSearch] = useState(""); return ( - } value={search} onChange={(e) => setSearch(e.currentTarget.value)} /> - - + ); } -function ListGrafikBerdasarkanPendidikan({search}: {search: string}) { - const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan) +function ListGrafikBerdasarkanPendidikan({ search }: { search: string }) { + const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan); const [donutData, setDonutData] = useState([]); const [mounted, setMounted] = useState(false); - const [modalHapus, setModalHapus] = useState(false) - const [selectedId, setSelectedId] = useState(null) + const [modalHapus, setModalHapus] = useState(false); + const [selectedId, setSelectedId] = useState(null); const router = useRouter(); - const handleDelete = async () => { if (selectedId) { - await stategrafik.delete.byId(selectedId) - setModalHapus(false) - setSelectedId(null) - - stategrafik.findMany.load() + await stategrafik.delete.byId(selectedId); + setModalHapus(false); + setSelectedId(null); + stategrafik.findMany.load(); } - } + }; + + const { + data, + page, + totalPages, + loading, + load, + } = stategrafik.findMany; useShallowEffect(() => { setMounted(true); - stategrafik.findMany.load() - }, []); + load(page, 10, search); + }, [page, search]); useEffect(() => { if (stategrafik.findMany.data) { @@ -70,36 +73,37 @@ function ListGrafikBerdasarkanPendidikan({search}: {search: string}) { { name: 'S1', value: S1, color: '#1018A8FF', key: 'S1' }, ]); } - }, [stategrafik.findMany.data]) + }, [stategrafik.findMany.data]); - const filteredData = (stategrafik.findMany.data || []).filter(item => { - const keyword = search.toLowerCase(); + const filteredData = data || [] + + if (loading || !data) { return ( - item.SD.toString().toLowerCase().includes(keyword) || - item.SMP.toString().toLowerCase().includes(keyword) || - item.SMA.toString().toLowerCase().includes(keyword) || - item.D3.toString().toLowerCase().includes(keyword) || - item.S1.toString().toLowerCase().includes(keyword) + + + ); - }); - - if (!stategrafik.findMany.data) { - return ( - - - - ) } return ( - - - - - + + + {/* Header */} + + List Pengangguran Berdasarkan Usia Kerja + + + + + +
SD @@ -114,8 +118,10 @@ function ListGrafikBerdasarkanPendidikan({search}: {search: string}) { {filteredData.length === 0 ? ( - - Belum ada data grafik responden + +
+ Belum ada data grafik responden +
) : ( @@ -127,82 +133,87 @@ function ListGrafikBerdasarkanPendidikan({search}: {search: string}) { {item.D3} {item.S1} - + + + - + + +
)) )} -
-
+
+ - {/* Chart */} - - - - Grafik Pengangguran Berdasarkan Pendidikan - {mounted && donutData.length > 0 ? ( - +
+ { + load(newPage, 10); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + mt="md" + mb="md" + color="blue" + radius="md" + /> +
+ + {/* Chart */} + + + + Grafik Pengangguran Berdasarkan Pendidikan + {mounted && donutData.length > 0 ? ( + + {donutData.map((entry, index) => ( ))} - - - SD : {donutData.find((entry) => entry.name === 'SD')?.value} - - - - SMP : {donutData.find((entry) => entry.name === 'SMP')?.value} - - - - SMA : {donutData.find((entry) => entry.name === 'SMA')?.value} - - - - D3 : {donutData.find((entry) => entry.name === 'D3')?.value} - - - - S1 : {donutData.find((entry) => entry.name === 'S1')?.value} - + + {donutData.map((entry) => ( + + + {entry.name} : {entry.value} + + ))} + - ) : ( - Belum ada data untuk ditampilkan dalam grafik - )} - - - -
+ ) : ( + Belum ada data untuk ditampilkan dalam grafik + )} + +
+
{/* Modal Konfirmasi Hapus */} { - if(id){ + if (id) { stategrafik.findUnique.load(id).then(() => { - const data = stategrafik.findUnique.data - if(data){ + const data = stategrafik.findUnique.data; + if (data) { stategrafik.update.form = { usia18_25: data.usia18_25 || '', usia26_35: data.usia26_35 || '', usia36_45: data.usia36_45 || '', usia46_keatas: data.usia46_keatas || '', - } + }; } - }) + }); } - }, [id]) + }, [id]); const handleSubmit = async () => { - stategrafik.update.id = id; - await stategrafik.update.submit(); - router.push('/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia') - } + try { + stategrafik.update.id = id; + await stategrafik.update.submit(); + toast.success('Data grafik berhasil diperbarui!'); + router.push( + '/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia' + ); + } catch (error) { + console.error(error); + toast.error('Terjadi kesalahan saat memperbarui data grafik'); + } + }; return ( - - - + + + + + + + Edit Grafik Pengangguran Berdasarkan Usia Kerja + + + + + + { + stategrafik.update.form.usia18_25 = val.currentTarget.value; + }} + required + /> + { + stategrafik.update.form.usia26_35 = val.currentTarget.value; + }} + required + /> + { + stategrafik.update.form.usia36_45 = val.currentTarget.value; + }} + required + /> + { + stategrafik.update.form.usia46_keatas = val.currentTarget.value; + }} + required + /> + + + + + + - - - Edit Grafik Pengangguran Berdasarkan Usia Kerja - { - stategrafik.update.form.usia18_25 = val.currentTarget.value; - }} - /> - { - stategrafik.update.form.usia26_35 = val.currentTarget.value; - }} - /> - { - stategrafik.update.form.usia36_45 = val.currentTarget.value; - }} - /> - { - stategrafik.update.form.usia46_keatas = val.currentTarget.value; - }} - /> - - - - ); } diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/create/page.tsx index 79ffd790..673256f5 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/create/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/create/page.tsx @@ -1,31 +1,29 @@ -'use client' /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import React from 'react'; -import { useRouter } from 'next/navigation'; -import grafikBerdasarkanJenisKelamin from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin'; -import { useProxy } from 'valtio/utils'; -import { useState } from 'react'; -import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Title, TextInput } from '@mantine/core'; -import { IconArrowBack } from '@tabler/icons-react'; -import grafikNganggur from '@/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur'; +'use client'; +import React, { useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { useProxy } from 'valtio/utils'; +import grafikNganggur from '@/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur'; +import colors from '@/con/colors'; +import { Box, Button, Paper, Stack, Title, TextInput, Group, Tooltip } from '@mantine/core'; +import { IconArrowBack } from '@tabler/icons-react'; function CreateGrafikBerdasarkanUsiaKerjaYangMenganggur() { const router = useRouter(); - const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanUsiaKerjaNganggur) + const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanUsiaKerjaNganggur); const [donutData, setDonutData] = useState([]); const resetForm = () => { stategrafik.create.form = { ...stategrafik.create.form, - usia18_25: "", - usia26_35: "", - usia36_45: "", - usia46_keatas: "", - } - } + usia18_25: '', + usia26_35: '', + usia36_45: '', + usia46_keatas: '', + }; + }; const handleSubmit = async () => { const id = await stategrafik.create.create(); @@ -37,64 +35,84 @@ function CreateGrafikBerdasarkanUsiaKerjaYangMenganggur() { } } resetForm(); - router.push("/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia") - } + router.push('/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia'); + }; + return ( - - - - - - - Create Grafik Pengangguran Berdasarkan Usia Kerja - { - stategrafik.create.form.usia18_25 = val.currentTarget.value; - }} - /> - { - stategrafik.create.form.usia26_35 = val.currentTarget.value; - }} - /> - { - stategrafik.create.form.usia36_45 = val.currentTarget.value; - }} - /> - { - stategrafik.create.form.usia46_keatas = val.currentTarget.value; - }} - /> - - - - + + {/* Header */} + + + + + + Tambah Data Pengangguran Berdasarkan Usia + + + + {/* Form Paper */} + + + (stategrafik.create.form.usia18_25 = val.currentTarget.value)} + required + /> + (stategrafik.create.form.usia26_35 = val.currentTarget.value)} + required + /> + (stategrafik.create.form.usia36_45 = val.currentTarget.value)} + required + /> + (stategrafik.create.form.usia46_keatas = val.currentTarget.value)} + required + /> + + {/* Submit Button */} + + + + + + ); } diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/page.tsx index f51e77d9..0c8b70d2 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/page.tsx @@ -1,60 +1,62 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Flex, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; +import { Box, Button, Center, Flex, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title, Tooltip } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react'; +import { IconEdit, IconPlus, IconSearch, IconTrash } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { Cell, Pie, PieChart } from 'recharts'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '../../../_com/header'; -import JudulList from '../../../_com/judulList'; import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; import grafikNganggur from '../../../_state/ekonomi/usia-kerja-nganggur'; - function GrafikBerdasarkanUsiaKerjaYangMenganggur() { - const [search, setSearch] = useState("") + const [search, setSearch] = useState(''); return ( - } value={search} onChange={(e) => setSearch(e.currentTarget.value)} /> - - + ); } -function ListGrafikBerdasarkanUsiaKerjaYangMenganggur({search}: {search: string}) { - const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanUsiaKerjaNganggur) +function ListGrafikBerdasarkanUsiaKerjaYangMenganggur({ search }: { search: string }) { + const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanUsiaKerjaNganggur); const [donutData, setDonutData] = useState([]); const [mounted, setMounted] = useState(false); - const [modalHapus, setModalHapus] = useState(false) - const [selectedId, setSelectedId] = useState(null) + const [modalHapus, setModalHapus] = useState(false); + const [selectedId, setSelectedId] = useState(null); const router = useRouter(); - const handleDelete = async () => { if (selectedId) { - await stategrafik.delete.byId(selectedId) - setModalHapus(false) - setSelectedId(null) - - stategrafik.findMany.load() + await stategrafik.delete.byId(selectedId); + setModalHapus(false); + setSelectedId(null); + stategrafik.findMany.load(); } - } + }; + + const { + data, + page, + totalPages, + loading, + load, + } = stategrafik.findMany; useShallowEffect(() => { setMounted(true); - stategrafik.findMany.load() - }, []); + load(page, 10, search) + }, [page, search]); useEffect(() => { if (stategrafik.findMany.data) { @@ -69,139 +71,149 @@ function ListGrafikBerdasarkanUsiaKerjaYangMenganggur({search}: {search: string} { name: 'usia46_keatas', value: totalUsia46_keatas, color: '#1094A8FF', key: 'usia46_keatas' }, ]); } - }, [stategrafik.findMany.data]) + }, [stategrafik.findMany.data]); - const filteredData = (stategrafik.findMany.data || []).filter(item => { - const keyword = search.toLowerCase(); + const filteredData = data || [] + + if (loading || !data) { return ( - item.usia18_25.toString().toLowerCase().includes(keyword) || - item.usia26_35.toString().toLowerCase().includes(keyword) || - item.usia36_45.toString().toLowerCase().includes(keyword) || - item.usia46_keatas.toString().toLowerCase().includes(keyword) + + + ); - }); - - if (!stategrafik.findMany.data) { - return ( - - - - ) } return ( - - - - - - - - Usia 18-25 - Usia 26-35 - Usia 36-45 - Usia 46 + - Edit - Delete - - - - {filteredData.length === 0 ? ( + + + + {/* Header */} + + List Pengangguran Berdasarkan Usia Kerja + + + + + + {/* Table */} + +
+ - - Belum ada data grafik responden - + Usia 18-25 + Usia 26-35 + Usia 36-45 + Usia 46 + + Edit + Delete - ) : ( - filteredData.map((item) => ( - - {item.usia18_25} - {item.usia26_35} - {item.usia36_45} - {item.usia46_keatas} - - - - - + + + {filteredData.length > 0 ? ( + filteredData.map(item => ( + + {item.usia18_25} + {item.usia26_35} + {item.usia36_45} + {item.usia46_keatas} + + + + + + + + )) + ) : ( + + +
+ Belum ada data grafik responden +
- )) - )} -
+ )} + +
+
- - + + - {/* Chart */} - - - - Grafik Pengangguran Berdasarkan Usia Kerja - {mounted && donutData.length > 0 ? ( - - - {donutData.map((entry, index) => ( - - ))} - - +
+ { + load(newPage, 10); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + mt="md" + mb="md" + color="blue" + radius="md" + /> +
+ + {/* Chart */} + + + Grafik Pengangguran Berdasarkan Usia Kerja + {mounted && donutData.length > 0 ? ( + + + + {donutData.map((entry, index) => ( + + ))} + + + Usia 18-25 : {donutData.find((entry) => entry.name === 'usia18_25')?.value} - Usia 26-35 : {donutData.find((entry) => entry.name === 'usia26_35')?.value} + Usia 26-35 : {donutData.find((entry) => entry.name === 'usia26_35')?.value} + - Usia 36-45 : {donutData.find((entry) => entry.name === 'usia36_45')?.value} + Usia 36-45 : {donutData.find((entry) => entry.name === 'usia36_45')?.value} + - Usia 46 + : {donutData.find((entry) => entry.name === 'usia46_keatas')?.value} + Usia 46 + : {donutData.find((entry) => entry.name === 'usia46_keatas')?.value} + - - ) : ( - Belum ada data untuk ditampilkan dalam grafik - )} - - -
-
+ +
+ ) : ( + Belum ada data untuk ditampilkan dalam grafik + )} + + + {/* Modal Konfirmasi Hapus */} setModalHapus(false)} onConfirm={handleDelete} - text='Apakah anda yakin ingin menghapus grafik pengangguran berdasarkan usia kerja ini?' + text="Apakah anda yakin ingin menghapus grafik pengangguran berdasarkan usia kerja ini?" />
); diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/[id]/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/[id]/edit/page.tsx index f65818be..6e0bae06 100644 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/[id]/edit/page.tsx @@ -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) => { - 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) => { + 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 ( - - - - + + Edit Detail Data Pengangguran + + - - Edit Detail Data Pengangguran - + + + + + - - Total Otomatis: {stateDetail.create.form.totalUnemployment.toLocaleString()} - - - Perubahan Otomatis: {stateDetail.create.form.percentageChange.toFixed(1)}% - - + + + + Total Otomatis: + + + {stateDetail.create.form.totalUnemployment.toLocaleString()} + + + + + + Perubahan Otomatis: + + + {stateDetail.create.form.percentageChange.toFixed(1)}% + + + + {/* Action Button */} + - - - - - Edit Program Kemiskinan + + {/* Header dengan tombol kembali */} + + + + + + Edit Program Kemiskinan + + + + { stateProgram.update.form.nama = e.target.value; }} - label={Judul Program} + label={Judul Program} placeholder="Masukkan judul program" + required /> - Deskripsi + + Deskripsi + { @@ -81,40 +113,58 @@ function EditProgramKemiskinan() { /> - { - stateProgram.update.form.ikonUrl = e.target.value; - }} - label={Ikon URL} - placeholder="Masukkan ikon url" - /> + + + Ikon Program Kreatif Desa + + { + stateProgram.update.form.icon = value; + }} + /> + - Statistik Jumlah Masyarakat Miskin + + + Statistik Jumlah Masyarakat Miskin + + { + stateProgram.update.form.statistik.jumlah = e.target.value; + }} + label="Jumlah Masyarakat Miskin" + placeholder="Masukkan jumlah masyarakat miskin" + required + /> - { - stateProgram.update.form.statistik.jumlah = e.target.value; - }} - label={Jumlah Masyarakat Miskin} - placeholder="Masukkan jumlah masyarakat miskin" - /> + { + stateProgram.update.form.statistik.tahun = e.target.value; + }} + label="Tahun" + placeholder="Masukkan tahun" + required + mt="sm" + /> + - { - stateProgram.update.form.statistik.tahun = e.target.value; - }} - label={Tahun} - placeholder="Masukkan tahun" - /> - - - diff --git a/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/[id]/page.tsx index 4ebcd736..2d87c9bc 100644 --- a/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/[id]/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/[id]/page.tsx @@ -1,115 +1,169 @@ 'use client' + import colors from '@/con/colors'; -import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Skeleton, + Stack, + Text, + Tooltip, +} from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react'; +import { IconArrowBack, IconEdit, IconTrash } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useState } from 'react'; import { useProxy } from 'valtio/utils'; import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; import programKemiskinanState from '../../../_state/ekonomi/program-kemiskinan'; - +import { IconKey, IconMapper } from '../../../_com/iconMap'; function DetailProgramKemiskinan() { - const programState = useProxy(programKemiskinanState) - const [modalHapus, setModalHapus] = useState(false) - const [selectedId, setSelectedId] = useState(null) + const programState = useProxy(programKemiskinanState); + const [modalHapus, setModalHapus] = useState(false); + const [selectedId, setSelectedId] = useState(null); const router = useRouter(); - const params = useParams() + const params = useParams(); useShallowEffect(() => { - programState.findUnique.load(params?.id as string) - }, []) + programState.findUnique.load(params?.id as string); + }, []); const handleHapus = () => { if (selectedId) { - programState.delete.delete(selectedId) - setModalHapus(false) - setSelectedId(null) - router.push("/admin/ekonomi/program-kemiskinan") + programState.delete.delete(selectedId); + setModalHapus(false); + setSelectedId(null); + router.push("/admin/ekonomi/program-kemiskinan"); } - } + }; if (!programState.findUnique.data) { return ( - + - ) + ); } + + const data = programState.findUnique.data; + return ( - - - - - - - Detail Program Kemiskinan - - + + {/* Tombol Kembali */} + + + {/* Card utama */} + + + + Detail Program Kemiskinan + + + {/* Detail Content */} + + - Judul Program - {programState.findUnique.data?.nama} + Judul Program + {data.nama || '-'} + - Deskripsi Singkat - + Deskripsi Singkat + + - Ikon URL - {programState.findUnique.data?.ikonUrl} + Ikon Program + {data.icon ? ( + + ) : ( + Tidak ada ikon + )} - Statistik Jumlah Masyarakat Miskin + - Jumlah Masyarakat Miskin - {programState.findUnique.data?.statistik?.jumlah} + Statistik Jumlah Masyarakat Miskin + + + Jumlah + {data.statistik?.jumlah || '-'} + + + Tahun + {data.statistik?.tahun || '-'} + + - - Tahun - {programState.findUnique.data?.statistik?.tahun} - - - - - + }} + variant="light" + radius="md" + size="md" + disabled={programState.delete.loading} + > + + + + + + + + - {/* Modal Hapus */} + {/* Modal Konfirmasi Hapus */} setModalHapus(false)} onConfirm={handleHapus} - text="Apakah anda yakin ingin menghapus program kemiskinan ini?" + text="Apakah Anda yakin ingin menghapus program kemiskinan ini?" /> ); } export default DetailProgramKemiskinan; - diff --git a/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/create/page.tsx index d67af82a..37d93d55 100644 --- a/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/create/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/create/page.tsx @@ -1,34 +1,50 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ -'use client' +'use client'; + import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + Text, + TextInput, + Title, + Tooltip, +} from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useProxy } from 'valtio/utils'; import programKemiskinanState from '../../../_state/ekonomi/program-kemiskinan'; import CreateEditor from '../../../_com/createEditor'; +import SelectIconProgram from '../../../_com/selectIcon'; import { useState } from 'react'; - +import { toast } from 'react-toastify'; function CreateProgramKemiskinan() { - const programState = useProxy(programKemiskinanState) + const programState = useProxy(programKemiskinanState); const router = useRouter(); const [lineChart, setLineChart] = useState([]); const resetForm = () => { programState.create.form = { - nama: "", - deskripsi: "", - ikonUrl: "", + nama: '', + deskripsi: '', + icon: '', statistik: { - tahun: "", - jumlah: "", - } - } - } + tahun: '', + jumlah: '', + }, + }; + }; const handleSubmit = async () => { + if (!programState.create.form.nama || !programState.create.form.deskripsi) { + return toast.warn('Judul dan deskripsi wajib diisi'); + } + const id = await programState.create.create(); if (id) { const idStr = String(id); @@ -36,68 +52,116 @@ function CreateProgramKemiskinan() { if (programState.findUnique.data) { setLineChart([programState.findUnique.data]); } + toast.success('Program berhasil ditambahkan'); + } else { + toast.error('Gagal menambahkan program, coba lagi'); } - resetForm() - router.push("/admin/ekonomi/program-kemiskinan") - } + + resetForm(); + router.push('/admin/ekonomi/program-kemiskinan'); + }; return ( - - - - + + {/* Header dengan tombol back */} + + + + + + Tambah Program Kemiskinan + + - - - Create Program Kemiskinan + + + {/* Judul Program */} { - programState.create.form.nama = val.target.value; - }} - label={Judul Program} - placeholder='Masukkan judul program' + onChange={(val) => (programState.create.form.nama = val.target.value)} + required /> - - Deskripsi - { - programState.create.form.deskripsi = val; - }} - /> - - { - programState.create.form.ikonUrl = val.target.value; - }} - label={Ikon URL} - placeholder='Masukkan ikon url' - /> - Statistik Jumlah Masyarakat Miskin - { - programState.create.form.statistik.jumlah = val.target.value; - }} - label={Jumlah Masyarakat Miskin} - placeholder='Masukkan jumlah masyarakat miskin' - /> - { - programState.create.form.statistik.tahun = val.target.value; - }} - label={Tahun} - placeholder='Masukkan tahun' - /> - - + + {/* Ikon Program */} + + + Ikon Program Kreatif Desa + + (programState.create.form.icon = value)} + /> + + + {/* Deskripsi */} + + + Deskripsi + + { + programState.create.form.deskripsi = val; + }} + /> + + + {/* Statistik */} + + Statistik Jumlah Masyarakat Miskin + + + + (programState.create.form.statistik.jumlah = val.target.value) + } + label="Jumlah" + placeholder="Masukkan jumlah masyarakat miskin" + required + /> + + (programState.create.form.statistik.tahun = val.target.value) + } + label="Tahun" + placeholder="Masukkan tahun" + required + /> + + + {/* Tombol Submit */} + + diff --git a/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/page.tsx b/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/page.tsx index 3dfa48d2..def7ec5e 100644 --- a/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/program-kemiskinan/page.tsx @@ -1,16 +1,15 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' +/* eslint-disable @typescript-eslint/no-explicit-any */ import colors from '@/con/colors'; -import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; -import { IconDeviceImac, IconSearch } from '@tabler/icons-react'; -import HeaderSearch from '../../_com/header'; -import JudulList from '../../_com/judulList'; -import { useRouter } from 'next/navigation'; -import { useProxy } from 'valtio/utils'; -import programKemiskinanState from '../../_state/ekonomi/program-kemiskinan'; +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, IconPlus, IconSearch } from '@tabler/icons-react'; +import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; -import { CartesianGrid, Legend, Line, LineChart, Tooltip, XAxis, YAxis } from 'recharts'; +import { CartesianGrid, Legend, Line, LineChart, Tooltip as RechartTooltip, XAxis, YAxis } from 'recharts'; +import { useProxy } from 'valtio/utils'; +import HeaderSearch from '../../_com/header'; +import programKemiskinanState from '../../_state/ekonomi/program-kemiskinan'; function ProgramKemiskinan() { const [search, setSearch] = useState(""); @@ -18,7 +17,7 @@ function ProgramKemiskinan() { } value={search} onChange={(e) => setSearch(e.currentTarget.value)} @@ -29,23 +28,17 @@ function ProgramKemiskinan() { } function ListProgramKemiskinan({ search }: { search: string }) { - const programState = useProxy(programKemiskinanState) + const programState = useProxy(programKemiskinanState); const router = useRouter(); const [lineChart, setLineChart] = useState([]); const [mounted, setMounted] = useState(false); - const { - data, - page, - totalPages, - loading, - load, - } = programState.findMany; + const { data, page, totalPages, loading, load } = programState.findMany; useShallowEffect(() => { - setMounted(true) - load(page, 10, search) - }, []) + setMounted(true); + load(page, 10, search); + }, [page, search]); useEffect(() => { if (data) { @@ -55,103 +48,118 @@ function ListProgramKemiskinan({ search }: { search: string }) { tahun: item.statistik?.tahun, jumlah: Number(item.statistik?.jumlah) })) - .sort((a, b) => (a.tahun || 0) - (b.tahun || 0)); // opsional, urutkan tahun + .sort((a, b) => (a.tahun || 0) - (b.tahun || 0)); setLineChart(chartData); - } - }, [data]) + }, [data]); - const filteredData = data || [] + const filteredData = data || []; if (loading || !data) { return ( - + - ) + ); } + return ( - - - - - - Judul Program - Deskripsi Singkat - Jumlah Masyarakat Miskin - Detail - - - - {filteredData.map((item) => ( - - {item.nama} - - - - {item.statistik?.jumlah} - - - + + + Daftar Program Kemiskinan + + + + + +
+ + + Judul Program + Deskripsi Singkat + Jumlah Masyarakat Miskin + Aksi - ))} - -
+ + + {filteredData.length > 0 ? ( + filteredData.map(item => ( + + + {item.nama} + + + + + {item.statistik?.jumlah || '-'} + + + + + )) + ) : ( + + +
+ Tidak ada data program kemiskinan yang cocok +
+
+
+ )} +
+ +
+ {/* Pagination */} +
+ { + load(newPage, 10); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + mt="md" + mb="md" + color="blue" + radius="md" + /> +
+ {/* Chart */} - - - - - Grafik Berdasarkan Responden - {mounted && lineChart.length > 0 ? ( - - - - - - [`${value} orang`, name]} - labelFormatter={(label: any) => `Tahun: ${label}`} - /> - - - - - - - - ) : ( - Belum ada data untuk ditampilkan dalam grafik - )} + + + Grafik Berdasarkan Responden + {mounted && lineChart.length > 0 ? ( + + + + + + [`${value} orang`, name]} + labelFormatter={(label: any) => `Tahun: ${label}`} + /> + + + - + ) : ( + Belum ada data untuk ditampilkan dalam grafik + )} -
- load(newPage)} - total={totalPages} - my={"md"} - /> -
); diff --git a/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/[id]/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/[id]/edit/page.tsx index ac01fd22..603c194e 100644 --- a/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/[id]/edit/page.tsx @@ -3,87 +3,138 @@ import grafikSektorUnggulan from '@/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa'; import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + Text, + TextInput, + Title, + Tooltip, +} from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useEffect } from 'react'; import { useProxy } from 'valtio/utils'; +import { toast } from 'react-toastify'; +import EditEditor from '@/app/admin/(dashboard)/_com/editEditor'; function EditSektorUnggulanDesa() { - const router = useRouter() - const params = useParams() as { id: string } - const stateGrafik = useProxy(grafikSektorUnggulan) + const router = useRouter(); + const params = useParams() as { id: string }; + const stateGrafik = useProxy(grafikSektorUnggulan); - const id = params.id + const id = params.id; // Load data saat komponen mount useEffect(() => { if (id) { stateGrafik.findUnique.load(id).then(() => { - const data = stateGrafik.findUnique.data + const data = stateGrafik.findUnique.data; if (data) { stateGrafik.update.form = { name: data.name || '', description: data.description || '', value: data.value || 0, - } + }; } - }) + }).catch((err) => { + console.error('Error load sektor unggulan:', err); + toast.error('Gagal mengambil data sektor unggulan'); + }); } - }, [id]) + }, [id]); const handleSubmit = async () => { - // Set the ID before submitting - stateGrafik.update.id = id; - await stateGrafik.update.submit(); - router.push('/admin/ekonomi/sektor-unggulan-desa') - } -return ( - - - - - - - Edit Sektor Unggulan Desa + try { + stateGrafik.update.id = id; + await stateGrafik.update.submit(); + toast.success('Sektor unggulan berhasil diperbarui!'); + router.push('/admin/ekonomi/sektor-unggulan-desa'); + } catch (error) { + console.error('Error update sektor unggulan:', error); + toast.error('Terjadi kesalahan saat memperbarui sektor unggulan'); + } + }; + + return ( + + + + + + + Edit Sektor Unggulan Desa + + + + + { stateGrafik.update.form.name = val.currentTarget.value; }} + required /> - { - stateGrafik.update.form.description = val.currentTarget.value; - }} - /> + + + Konten + + { + stateGrafik.update.form.description = htmlContent; + }} + /> + { stateGrafik.update.form.value = Number(val.currentTarget.value); }} + required /> - + + + + - ) + ); } export default EditSektorUnggulanDesa; diff --git a/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/[id]/page.tsx index d4d5f727..f89351a9 100644 --- a/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/[id]/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/[id]/page.tsx @@ -1,97 +1,134 @@ 'use client' import { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus'; import colors from '@/con/colors'; -import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Skeleton, + Stack, + Text, + Tooltip, +} from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react'; +import { IconArrowBack, IconEdit, IconTrash } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useState } from 'react'; import { useProxy } from 'valtio/utils'; import grafikSektorUnggulan from '../../../_state/ekonomi/sektor-unggulan-desa'; function DetailSektorUnggulanDesa() { - const stateGrafik = useProxy(grafikSektorUnggulan) - const [modalHapus, setModalHapus] = useState(false) - const [selectedId, setSelectedId] = useState(null) - const params = useParams() + const stateGrafik = useProxy(grafikSektorUnggulan); + const [modalHapus, setModalHapus] = useState(false); + const [selectedId, setSelectedId] = useState(null); + const params = useParams(); const router = useRouter(); useShallowEffect(() => { - stateGrafik.findUnique.load(params?.id as string) - }, []) + stateGrafik.findUnique.load(params?.id as string); + }, []); const handleHapus = () => { if (selectedId) { - stateGrafik.delete.byId(selectedId) - setModalHapus(false) - setSelectedId(null) - router.push("/admin/ekonomi/sektor-unggulan-desa") + stateGrafik.delete.byId(selectedId); + setModalHapus(false); + setSelectedId(null); + router.push('/admin/ekonomi/sektor-unggulan-desa'); } - } + }; if (!stateGrafik.findUnique.data) { return ( - + - ) + ); } + const data = stateGrafik.findUnique.data; + return ( - - - - - - - Detail Sektor Unggulan Desa - - + + {/* Tombol kembali */} + + + + + + Detail Sektor Unggulan Desa + + + + - Nama Sektor Unggulan - {stateGrafik.findUnique.data?.name} + Nama Sektor Unggulan + {data.name || '-'} + - Deskripsi Sektor Unggulan - {stateGrafik.findUnique.data?.description} + Deskripsi + + - Jumlah Sektor Unggulan - {stateGrafik.findUnique.data?.value} + Jumlah + {data.value ?? '-'} - - + + {/* Tombol Aksi */} + + + + + - - + + - {/* Modal Hapus */} + {/* Modal Konfirmasi Hapus */} setModalHapus(false)} diff --git a/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/create/page.tsx index 1e403069..507cb066 100644 --- a/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/create/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/create/page.tsx @@ -1,8 +1,18 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ -'use client' +'use client'; import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + Text, + TextInput, + Title, + Tooltip, +} from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; @@ -13,15 +23,15 @@ import CreateEditor from '../../../_com/createEditor'; function CreateSektorUnggulanDesa() { const stateGrafik = useProxy(grafikSektorUnggulan); const [chartData, setChartData] = useState([]); - const router = useRouter() + const router = useRouter(); const resetForm = () => { stateGrafik.create.form = { - name: "", - description: "", + name: '', + description: '', value: 0, - } - } + }; + }; const handleSubmit = async () => { const id = await stateGrafik.create.create(); @@ -33,58 +43,87 @@ function CreateSektorUnggulanDesa() { } } resetForm(); - router.push("/admin/ekonomi/sektor-unggulan-desa"); - } + router.push('/admin/ekonomi/sektor-unggulan-desa'); + }; + return ( - - - - - - - Tambah Grafik Hasil Kepuasan Masyarakat - - + {/* Header dengan back button */} + + + + + + Tambah Sektor Unggulan Desa + + + + {/* Form */} + + + { + stateGrafik.create.form.name = e.currentTarget.value; + }} + required + /> + + + + Deskripsi Sektor Unggulan + + { - stateGrafik.create.form.name = val.currentTarget.value; + stateGrafik.create.form.description = val; }} /> - - Deskripsi Sektor Ungggulan - { - stateGrafik.create.form.description = val; - }} - /> - - { - stateGrafik.create.form.value = Number(val.currentTarget.value); + + + { + stateGrafik.create.form.value = Number(e.currentTarget.value); + }} + required + /> + + + - - - - + > + Simpan + + + + ); } diff --git a/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/page.tsx b/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/page.tsx index 58c4f1c8..3a7cc1e8 100644 --- a/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/sektor-unggulan-desa/page.tsx @@ -1,23 +1,40 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; -import { IconDeviceImac, IconSearch } from '@tabler/icons-react'; -import HeaderSearch from '../../_com/header'; -import JudulList from '../../_com/judulList'; +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, IconPlus, IconSearch } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; -import grafikSektorUnggulan from '../../_state/ekonomi/sektor-unggulan-desa'; +import { Bar, BarChart, Legend, ResponsiveContainer, Tooltip as ReTooltip, XAxis, YAxis } from 'recharts'; import { useProxy } from 'valtio/utils'; -import { useMediaQuery, useShallowEffect } from '@mantine/hooks'; -import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts'; +import HeaderSearch from '../../_com/header'; +import grafikSektorUnggulan from '../../_state/ekonomi/sektor-unggulan-desa'; function SektorUnggulanDesa() { const [search, setSearch] = useState(''); return ( } value={search} onChange={(e) => setSearch(e.currentTarget.value)} @@ -30,96 +47,155 @@ function SektorUnggulanDesa() { function ListSektorUnggulanDesa({ search }: { search: string }) { const router = useRouter(); const state = useProxy(grafikSektorUnggulan); - const [chartData, setChartData] = useState<{ id: string; name: string; description: string | null; value: number | null }[]>([]); - const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready - const isTablet = useMediaQuery('(max-width: 1024px)') - const isMobile = useMediaQuery('(max-width: 768px)') + const [chartData, setChartData] = useState< + { id: string; name: string; description: string | null; value: number | null }[] + >([]); - const filteredData = (state.findMany.data || []).filter(item => { - const keyword = search.toLowerCase(); - return ( - item.name.toLowerCase().includes(keyword) || - (item.value?.toString() || '').toLowerCase().includes(keyword) - ); - }); - - useShallowEffect(() => { - setMounted(true) - state.findMany.load() - }, []) + const { + data, + page, + totalPages, + loading, + load, + } = state.findMany; useEffect(() => { - setMounted(true); if (state.findMany.data) { - setChartData(state.findMany.data.map((item) => ({ - id: item.id, - name: item.name, - description: item.description, - value: Number(item.value), - }))); + setChartData( + state.findMany.data.map((item) => ({ + id: item.id, + name: item.name, + description: item.description, + value: Number(item.value), + })) + ); } }, [state.findMany.data]); - return ( - - - - - - - - Nama Sektor Unggulan - Deskripsi Sektor Unggulan - Detail - - - - {filteredData.map((item) => ( - - {item.name} - - - - - - - - ))} - -
-
+ useShallowEffect(() => { + load(page, 10, search) + }, [page, search]) - {/* Chart */} - {!mounted && !chartData ? ( - - - Grafik Hasil Kepuasan Masyarakat - Belum ada data untuk ditampilkan dalam grafik - - + const filteredData = data || [] + + if (loading || !data) { + return ( + + + + ); + } + + return ( + + {/* List Table */} + + + List Sektor Unggulan Desa + + + + + {loading ? ( + ) : ( - - - Grafik Sektor Unggulan Desa - {mounted && chartData.length > 0 && ( - - - - - - - - )} - + + + + + Nama Sektor + Deskripsi + Detail + + + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( + + + + + {item.name} + + + + + + + + + + + + + + + )) + ) : ( + + +
+ Tidak ada data sektor unggulan yang cocok +
+
+
+ )} +
+
)} -
-
+
+ +
+ { + load(newPage, 10); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + mt="md" + mb="md" + color="blue" + radius="md" + /> +
+ + {/* Chart */} + + + Grafik Sektor Unggulan Desa + + {loading ? ( + + ) : chartData.length > 0 ? ( + + + + + + + + + + + + ) : ( +
+ Belum ada data untuk ditampilkan dalam grafik +
+ )} +
+
); } diff --git a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/[id]/edit/page.tsx b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/[id]/edit/page.tsx index cd1fc06e..878b1b40 100644 --- a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/[id]/edit/page.tsx @@ -10,6 +10,7 @@ import { useEffect, useState } from 'react'; import { toast } from 'react-toastify'; import { useProxy } from 'valtio/utils'; import SelectIconProgramEdit from '../../../../_com/selectIconEdit'; +import { IconKey } from '@/app/admin/(dashboard)/_com/iconMap'; interface FormProgramKreatif { name: string; @@ -18,8 +19,6 @@ interface FormProgramKreatif { icon: string; } -type IconKey = 'ekowisata' | 'kompetisi' | 'wisata' | 'ekonomi' | 'sampah'; - function EditProgramKreatifDesa() { const stateProgramKreatif = useProxy(programKreatifState) diff --git a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/[id]/page.tsx b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/[id]/page.tsx index 91a89f73..b0d58c6e 100644 --- a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/[id]/page.tsx +++ b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/[id]/page.tsx @@ -1,14 +1,14 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' import colors from '@/con/colors'; import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconArrowBack, IconChartLine, IconChristmasTreeFilled, IconClipboard, IconEdit, IconHomeEco, IconLeaf, IconRecycle, IconScale, IconShieldFilled, IconTent, IconTrash, IconTrendingUp, IconTrophy, IconTruck, IconX } from '@tabler/icons-react'; +import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; -import React, { useState } from 'react'; +import { useState } from 'react'; import { useProxy } from 'valtio/utils'; -import programKreatifState from '../../../_state/inovasi/program-kreatif'; +import { IconKey, IconMapper } from '../../../_com/iconMap'; import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; +import programKreatifState from '../../../_state/inovasi/program-kreatif'; // import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; @@ -19,22 +19,6 @@ function DetailProgramKreatifDesa() { const params = useParams() const [selectedId, setSelectedId] = useState(null) - const iconMap: Record> = { - ekowisata: IconLeaf, - kompetisi: IconTrophy, - wisata: IconTent, - ekonomi: IconChartLine, - sampah: IconRecycle, - truck: IconTruck, - scale: IconScale, - clipboard: IconClipboard, - trash: IconTrash, - lingkunganSehat: IconHomeEco, - sumberOksigen: IconChristmasTreeFilled, - ekonomiBerkelanjutan: IconTrendingUp, - mencegahBencana: IconShieldFilled, - }; - useShallowEffect(() => { stateProgramKreatif.findUnique.load(params?.id as string) }, [params?.id]) @@ -75,10 +59,12 @@ function DetailProgramKreatifDesa() {
Ikon Program Kreatif Desa - {iconMap[stateProgramKreatif.findUnique.data?.icon] && ( - - {React.createElement(iconMap[stateProgramKreatif.findUnique.data?.icon], { size: 24 })} - + {stateProgramKreatif.findUnique.data?.icon && ( + )} @@ -127,7 +113,7 @@ function DetailProgramKreatifDesa() { onClose={() => setModalHapus(false)} onConfirm={handleHapus} text="Apakah anda yakin ingin menghapus program kreatif desa ini?" - /> + /> ); } diff --git a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/page.tsx b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/page.tsx index 5b5bfb2c..605fa01e 100644 --- a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/page.tsx +++ b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/page.tsx @@ -4,7 +4,7 @@ import React from 'react'; import colors from '@/con/colors'; import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; -import { IconDeviceImac, IconSearch } from '@tabler/icons-react'; +import { IconCash, IconChristmasTreeFilled, IconClipboard, IconDeviceImac, IconDroplet, IconHome, IconHomeEco, IconHospital, IconScale, IconSchool, IconSearch, IconShieldFilled, IconShoppingCart, IconTrash, IconTree, IconTrendingUp, IconTruck } from '@tabler/icons-react'; import HeaderSearch from '../../_com/header'; import JudulList from '../../_com/judulList'; import { useRouter } from 'next/navigation'; @@ -60,6 +60,21 @@ function ListProgramKreatifDesa({ search }: { search: string }) { wisata: IconTent, ekonomi: IconChartLine, sampah: IconRecycle, + truck: IconTruck, + scale: IconScale, + clipboard: IconClipboard, + trash: IconTrash, + lingkunganSehat: IconHomeEco, + sumberOksigen: IconChristmasTreeFilled, + ekonomiBerkelanjutan: IconTrendingUp, + mencegahBencana: IconShieldFilled, + rumah: IconHome, + pohon: IconTree, + air: IconDroplet, + bantuan: IconCash, + pelatihan: IconSchool, + subsidi: IconShoppingCart, + layananKesehatan: IconHospital }; if (loading || !data) { diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findMany.ts index 009069ed..9f659331 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findMany.ts @@ -1,8 +1,49 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function demografiPekerjaanFindMany(context: Context) { + const page = Number(context.query.page) || 1; + const limit = Number(context.query.limit) || 10; + const search = (context.query.search as string) || ''; + const skip = (page - 1) * limit; + + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [ + { pekerjaan: { contains: search, mode: "insensitive" } }, + ]; + } + + try { + const [data, total] = await Promise.all([ + prisma.dataDemografiPekerjaan.findMany({ + where, + skip, + take: limit, + orderBy: { createdAt: "desc" }, + }), + prisma.dataDemografiPekerjaan.count({ + where, + }), + ]); -export default async function demografiPekerjaanFindMany() { - const res = await prisma.dataDemografiPekerjaan.findMany(); return { - data: res - } -} \ No newline at end of file + success: true, + message: "Success fetch demografi pekerjaan with pagination", + data, + page, + totalPages: Math.ceil(total / limit), + total, + }; + } catch (e) { + console.error(e); + return { + success: false, + message: "Failed to fetch demografi pekerjaan with pagination", + data: null, + }; + } +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-penduduk-miskin/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-penduduk-miskin/findMany.ts index e6ad0010..4cc14207 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-penduduk-miskin/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-penduduk-miskin/findMany.ts @@ -1,8 +1,54 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function grafikJumlahPendudukMiskinFindMany( + context: Context +) { + const page = Number(context.query.page) || 1; + const limit = Number(context.query.limit) || 10; + const search = (context.query.search as string) || ""; + const skip = (page - 1) * limit; + + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + const yearSearch = Number(search); + + where.OR = [ + // kalau search bisa diparse jadi number → cocokin year + ...(isNaN(yearSearch) ? [] : [{ year: yearSearch }]), + ]; + } + + try { + const [data, total] = await Promise.all([ + prisma.grafikJumlahPendudukMiskin.findMany({ + where, + skip, + take: limit, + orderBy: { createdAt: "desc" }, + }), + prisma.grafikJumlahPendudukMiskin.count({ + where, + }), + ]); -export default async function grafikJumlahPendudukMiskinFindMany() { - const res = await prisma.grafikJumlahPendudukMiskin.findMany(); return { - data: res, + success: true, + message: "Success fetch grafik jumlah penduduk miskin with pagination", + data, + page, + totalPages: Math.ceil(total / limit), + total, }; -} \ No newline at end of file + } catch (e) { + console.error(e); + return { + success: false, + message: "Failed to fetch grafik jumlah penduduk miskin with pagination", + data: null, + }; + } +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findMany.ts index e03fa3a6..52092a43 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findMany.ts @@ -12,27 +12,33 @@ export default async function detailDataPengangguranFindMany(context: Context) { // Tambahkan pencarian (jika ada) if (search) { + const yearSearch = Number(search); + where.OR = [ - { year: { contains: search, mode: "insensitive" } }, + // kalau search bisa diparse jadi number → cocokin year + ...(isNaN(yearSearch) ? [] : [{ year: yearSearch }]), + // selalu cocokin month pakai contains { month: { contains: search, mode: "insensitive" } }, ]; } try { + const monthOrder = ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agu","Sep","Okt","Nov","Des"]; const [data, total] = await Promise.all([ prisma.detailDataPengangguran.findMany({ where, skip, take: limit, - orderBy: [{ year: "desc" }, { month: "asc" }], + orderBy: { year: "asc" }, // urut tahun dulu }), prisma.detailDataPengangguran.count({ where, }), ]); - + data.sort((a, b) => monthOrder.indexOf(a.month) - monthOrder.indexOf(b.month)); + return { success: true, - message: "Success fetch apb desa with pagination", + message: "Success fetch detail data pengangguran with pagination", data, page, totalPages: Math.ceil(total / limit), diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/create.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/create.ts index a34684eb..8f852cbd 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/create.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/create.ts @@ -4,7 +4,7 @@ import { Context } from "elysia"; type FormCreate = { nama: string; deskripsi: string; - ikonUrl?: string; // optional karena boleh null + icon: string; statistik?: { tahun: number; jumlah: number; @@ -18,7 +18,7 @@ export default async function programKemiskinanCreate(context: Context) { data: { nama: body.nama, deskripsi: body.deskripsi, - ikonUrl: body.ikonUrl, + icon: body.icon, statistik: body.statistik ? { create: { diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/index.ts index a9967668..4502a3ce 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/index.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/index.ts @@ -12,7 +12,7 @@ const ProgramKemiskinan = new Elysia({ body: t.Object({ nama: t.String(), deskripsi: t.String(), - ikonUrl: t.String(), + icon: t.String(), statistik: t.Object({ tahun: t.String(), jumlah: t.String(), @@ -32,7 +32,7 @@ const ProgramKemiskinan = new Elysia({ body: t.Object({ nama: t.String(), deskripsi: t.String(), - ikonUrl: t.String(), + icon: t.String(), statistik: t.Object({ tahun: t.String(), jumlah: t.String(), diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/updt.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/updt.ts index 924d1dcc..aeddea34 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/updt.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/program-kemiskinan/updt.ts @@ -5,6 +5,7 @@ type FormUpdate = { nama: string; deskripsi: string; ikonUrl?: string; + icon: string; statistik?: { tahun: number; jumlah: number; @@ -51,7 +52,7 @@ export default async function programKemiskinanUpdate(context: Context) { data: { nama: body.nama, deskripsi: body.deskripsi, - ikonUrl: body.ikonUrl, + icon: body.icon, statistik: { connect: { id: statistikUpdate.id }, // konek ke statistik baru atau yang diperbarui }, diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/sektor-unggulan-desa/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/sektor-unggulan-desa/findMany.ts index 1da65785..38987324 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/sektor-unggulan-desa/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/sektor-unggulan-desa/findMany.ts @@ -1,8 +1,50 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function sektorUnggulanDesaFindMany(context: Context) { + const page = Number(context.query.page) || 1; + const limit = Number(context.query.limit) || 10; + const search = (context.query.search as string) || ''; + const skip = (page - 1) * limit; + + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [ + { name: { contains: search, mode: "insensitive" } }, + { description: { contains: search, mode: "insensitive" } }, + ]; + } + + try { + const [data, total] = await Promise.all([ + prisma.sektorUnggulanDesa.findMany({ + where, + skip, + take: limit, + orderBy: { createdAt: "desc" }, + }), + prisma.sektorUnggulanDesa.count({ + where, + }), + ]); -export default async function sektorUnggulanDesaFindMany() { - const res = await prisma.sektorUnggulanDesa.findMany(); return { - data: res, + success: true, + message: "Success fetch sektor unggulan desa with pagination", + data, + page, + totalPages: Math.ceil(total / limit), + total, }; -} \ No newline at end of file + } catch (e) { + console.error(e); + return { + success: false, + message: "Failed to fetch sektor unggulan desa with pagination", + data: null, + }; + } +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/usia-kerja-yang-menganggur/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/usia-kerja-yang-menganggur/findMany.ts index 3365fc1b..04a7e4e4 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/usia-kerja-yang-menganggur/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/usia-kerja-yang-menganggur/findMany.ts @@ -1,8 +1,56 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function grafikMenganggurBerdasarkanUsiaFindMany( + context: Context +) { + const page = Number(context.query.page) || 1; + const limit = Number(context.query.limit) || 10; + const search = (context.query.search as string) || ""; + const skip = (page - 1) * limit; + + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [ + { usia18_25: { contains: search, mode: "insensitive" } }, + { usia26_35: { contains: search, mode: "insensitive" } }, + { usia36_45: { contains: search, mode: "insensitive" } }, + { usia46_keatas: { contains: search, mode: "insensitive" } }, + ]; + } + + try { + const [data, total] = await Promise.all([ + prisma.grafikMenganggurBerdasarkanUsia.findMany({ + where, + skip, + take: limit, + orderBy: { createdAt: "desc" }, + }), + prisma.grafikMenganggurBerdasarkanUsia.count({ + where, + }), + ]); -export default async function grafikMenganggurBerdasarkanUsiaFindMany() { - const res = await prisma.grafikMenganggurBerdasarkanUsia.findMany(); return { - data: res - } -} \ No newline at end of file + success: true, + message: + "Success fetch grafik menganggur berdasarkan usia with pagination", + data, + page, + totalPages: Math.ceil(total / limit), + total, + }; + } catch (e) { + console.error(e); + return { + success: false, + message: + "Failed to fetch grafik menganggur berdasarkan usia with pagination", + data: null, + }; + } +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/usia-kerja-yang-menganggur/pengangguran-berdasrkan-pendidikan/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/usia-kerja-yang-menganggur/pengangguran-berdasrkan-pendidikan/findMany.ts index 558a9011..186c8b9a 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/usia-kerja-yang-menganggur/pengangguran-berdasrkan-pendidikan/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/usia-kerja-yang-menganggur/pengangguran-berdasrkan-pendidikan/findMany.ts @@ -1,8 +1,53 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function grafikPengangguranBerdasarkanPendidikanFindMany(context: Context) { + const page = Number(context.query.page) || 1; + const limit = Number(context.query.limit) || 10; + const search = (context.query.search as string) || ''; + const skip = (page - 1) * limit; + + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [ + { SD: { contains: search, mode: "insensitive" } }, + { SMP: { contains: search, mode: "insensitive" } }, + { SMA: { contains: search, mode: "insensitive" } }, + { D3: { contains: search, mode: "insensitive" } }, + { S1: { contains: search, mode: "insensitive" } }, + ]; + } + + try { + const [data, total] = await Promise.all([ + prisma.grafikMenganggurBerdasarkanPendidikan.findMany({ + where, + skip, + take: limit, + orderBy: { createdAt: "asc" }, + }), + prisma.grafikMenganggurBerdasarkanPendidikan.count({ + where, + }), + ]); -export default async function grafikMenganggurBerdasarkanPendidikanFindMany() { - const res = await prisma.grafikMenganggurBerdasarkanPendidikan.findMany(); return { - data: res - } -} \ No newline at end of file + success: true, + message: "Success fetch grafik menganggur berdasarkan pendidikan with pagination", + data, + page, + totalPages: Math.ceil(total / limit), + total, + }; + } catch (e) { + console.error(e); + return { + success: false, + message: "Failed to fetch grafik menganggur berdasarkan pendidikan with pagination", + data: null, + }; + } +} diff --git a/src/app/darmasaba/(pages)/ekonomi/demografi-pekerjaan/page.tsx b/src/app/darmasaba/(pages)/ekonomi/demografi-pekerjaan/page.tsx index 3b3e9327..18d9dcca 100644 --- a/src/app/darmasaba/(pages)/ekonomi/demografi-pekerjaan/page.tsx +++ b/src/app/darmasaba/(pages)/ekonomi/demografi-pekerjaan/page.tsx @@ -41,37 +41,39 @@ function Page() { - Statistik Demografi Pekerjaan Di Desa Darmasaba - ({ - id: item.id, - Pekerjaan: item.pekerjaan, - laki: item.lakiLaki, - perempuan: item.perempuan, - }))} - dataKey="Pekerjaan" - series={[ - { name: 'laki', color: '#5082EE' }, - { name: 'perempuan', color: '#6EDF9C' }, - ]} - tickLine="y" - xAxisProps={{ - angle: -45, // Rotate labels by -45 degrees - textAnchor: 'end', // Anchor text to the end for better alignment - height: 100, // Increase height for rotated labels - interval: 0, // Show all labels - style: { - fontSize: '12px', // Adjust font size if needed - overflow: 'visible', - whiteSpace: 'nowrap' - } - }} - /> + + Statistik Demografi Pekerjaan Di Desa Darmasaba + ({ + id: item.id, + Pekerjaan: item.pekerjaan, + laki: item.lakiLaki, + perempuan: item.perempuan, + }))} + dataKey="Pekerjaan" + series={[ + { name: 'laki', color: '#5082EE' }, + { name: 'perempuan', color: '#6EDF9C' }, + ]} + tickLine="y" + xAxisProps={{ + angle: -45, // Rotate labels by -45 degrees + textAnchor: 'end', // Anchor text to the end for better alignment + height: 100, // Increase height for rotated labels + interval: 0, // Show all labels + style: { + fontSize: '12px', // Adjust font size if needed + overflow: 'visible', + whiteSpace: 'nowrap' + } + }} + /> + diff --git a/src/app/darmasaba/(pages)/ekonomi/program-kemiskinan/page.tsx b/src/app/darmasaba/(pages)/ekonomi/program-kemiskinan/page.tsx index fb015f6a..5522d54e 100644 --- a/src/app/darmasaba/(pages)/ekonomi/program-kemiskinan/page.tsx +++ b/src/app/darmasaba/(pages)/ekonomi/program-kemiskinan/page.tsx @@ -1,18 +1,19 @@ 'use client' -import colors from '@/con/colors'; -import { Stack, Box, Text, SimpleGrid, Paper, Skeleton, Center, Pagination, Grid, GridCol, TextInput } from '@mantine/core'; -import React, { useState } from 'react'; -import BackButton from '../../desa/layanan/_com/BackButto'; -import { CartesianGrid, Legend, Line, LineChart as RechartsLineChart, Tooltip, XAxis, YAxis } from 'recharts'; -import { useProxy } from 'valtio/utils'; import programKemiskinanState from '@/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan'; +import colors from '@/con/colors'; +import { Box, Center, Grid, GridCol, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core'; import { useDebouncedValue, useShallowEffect } from '@mantine/hooks'; import { IconSearch } from '@tabler/icons-react'; +import { useState } from 'react'; +import { CartesianGrid, Line, LineChart as RechartsLineChart, Tooltip, XAxis, YAxis } from 'recharts'; +import { useProxy } from 'valtio/utils'; +import BackButton from '../../desa/layanan/_com/BackButto'; interface StatistikData { id: string; tahun: number; jumlah: number; + icon: string; createdAt: Date; updatedAt: Date; } @@ -21,7 +22,7 @@ interface ProgramKemiskinanData { id: string; nama: string; deskripsi: string; - ikonUrl: string | null; + icon: string; statistik: StatistikData | null; isActive: boolean; statistikId: string | null; @@ -34,6 +35,20 @@ function Page() { const [debouncedSearch] = useDebouncedValue(search, 500); // 500ms delay const state = useProxy(programKemiskinanState) + // 🔧 Get valid statistics data with proper type checking + const statistikData = state.findMany.data + .filter((item): item is ProgramKemiskinanData & { statistik: StatistikData } => { + return !!item?.statistik && + item.statistik.tahun !== undefined && + item.statistik.jumlah !== undefined; + }) + .map(item => ({ + tahun: Number(item.statistik.tahun) || 0, // Ensure tahun is a number + jumlah: Number(item.statistik.jumlah) || 0, // Ensure jumlah is a number + })) + .sort((a, b) => a.tahun - b.tahun) + .filter(item => !isNaN(item.tahun) && !isNaN(item.jumlah)); // Remove any invalid entries + const { data, page, @@ -88,9 +103,9 @@ function Page() { md: 2 }} > - {state.findMany.data.map((v, k) => { + {state.findMany.data.map(v => { return ( - + {v.nama} @@ -100,7 +115,10 @@ function Page() {
load(newPage)} + onChange={(newPage) => { + load(newPage) + window.scrollTo({ top: 0, behavior: 'smooth' }) + }} total={totalPages} my={"md"} /> @@ -108,44 +126,48 @@ function Page() { Statistik Kemiskinan Masyarakat - {data.length > 0 && data[0]?.statistik ? ( + {statistikData.length > 0 ? (
- - item.statistik !== null - ) - .map(item => ({ - tahun: item.statistik.tahun, - jumlah: item.statistik.jumlah - })) - .sort((a, b) => a.tahun - b.tahun) - } + - - - [`${value} orang`, name]} - labelFormatter={(label: number) => `Tahun: ${label}`} + - - + [`${value} orang`, 'Jumlah']} + labelFormatter={(label) => `Tahun ${label}`} + /> +
) : ( - Belum ada data statistik yang tersedia + + + {state.findMany.loading + ? 'Memuat data statistik...' + : 'Belum ada data statistik yang tersedia atau data tidak valid'} + + )}