diff --git a/prisma/schema.prisma b/prisma/schema.prisma index dd630ab0..413728e6 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1265,43 +1265,44 @@ model DataDemografiPekerjaan { // ========================================= JUMLAH PENGANGGURAN ========================================= // model DetailDataPengangguran { - id String @id @default(uuid()) @db.Uuid - month String @db.VarChar(20) - year Int - totalUnemployment Int - educatedUnemployment Int - uneducatedUnemployment Int - percentageChange Float? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - deletedAt DateTime @default(now()) - isActive Boolean @default(true) + id String @id @default(uuid()) @db.Uuid + month String @db.VarChar(20) + year Int + totalUnemployment Int + educatedUnemployment Int + uneducatedUnemployment Int + percentageChange Float? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) @@unique([month, year]) } + model RingkasanDataPengangguran { - id String @id @default(uuid()) @db.Uuid - year Int @unique - totalUnemployment Int - educatedUnemployment Int - percentageEducatedOfTotal Float? - productiveAgePopulation Int? - percentageProductiveOfTotal Float? - percentageChangeFromPreviousYear Float? + id String @id @default(uuid()) @db.Uuid + year Int @unique + totalUnemployment Int + educatedUnemployment Int + percentageEducatedOfTotal Float? + productiveAgePopulation Int? + percentageProductiveOfTotal Float? + percentageChangeFromPreviousYear Float? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - deletedAt DateTime @default(now()) - isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) } + model SedangMencariKerja { - id String @id @default(uuid()) @db.Uuid - count Int - percentageOfTotal Float? - recordedDate DateTime @unique @db.Date - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - deletedAt DateTime @default(now()) - isActive Boolean @default(true) - + id String @id @default(uuid()) @db.Uuid + count Int + percentageOfTotal Float? + recordedDate DateTime @unique @db.Date + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) } diff --git a/src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.ts b/src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.ts index c545cde9..33174920 100644 --- a/src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.ts +++ b/src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.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"; @@ -36,6 +37,25 @@ const jumlahPengangguranForm: JumlahPengangguran = { }; const jumlahPengangguran = proxy({ + findByMonthYear: { + data: null as any, + loading: false, + load: async ({ month, year }: { month: string; year: number }) => { + jumlahPengangguran.findByMonthYear.loading = true; + try { + const res = await fetch( + `/api/ekonomi/jumlahpengangguran/detaildatapengangguran/month/${month}/year/${year}` + ); + const json = await res.json(); + jumlahPengangguran.findByMonthYear.data = json.data; + return json.data; + } catch (err) { + console.error("Gagal ambil data bulan/tahun:", err); + } finally { + jumlahPengangguran.findByMonthYear.loading = false; + } + }, + }, create: { form: jumlahPengangguranForm, loading: false, diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/_lib/layoutTabs.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/_lib/layoutTabs.tsx new file mode 100644 index 00000000..8669cb22 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/_lib/layoutTabs.tsx @@ -0,0 +1,67 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' +import colors from '@/con/colors'; +import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core'; +import { usePathname, useRouter } from 'next/navigation'; +import React, { useEffect, useState } from 'react'; + +function LayoutTabs({ children }: { children: React.ReactNode }) { + const router = useRouter() + const pathname = usePathname() + const tabs = [ + { + label: "Detail Data Pengangguran", + value: "detaildatapengangguran", + href: "/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran" + }, + { + label: "Ringkasan Data Pengangguran", + value: "ringkasandatapengangguran", + href: "/admin/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran" + }, + { + label: "Sedang Mencari Kerja", + value: "sedangmencarikerja", + href: "/admin/ekonomi/jumlah-pengangguran/sedang-mencari-kerja" + } + ]; + const curentTab = tabs.find(tab => tab.href === pathname) + const [activeTab, setActiveTab] = useState(curentTab?.value || tabs[0].value); + + 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((e, i) => ( + {e.label} + ))} + + {tabs.map((e, i) => ( + + {/* Konten dummy, bisa diganti tergantung routing */} + <> + + ))} + + {children} + + ); +} + +export default LayoutTabs; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/create/page.tsx deleted file mode 100644 index 6dff3a24..00000000 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/create/page.tsx +++ /dev/null @@ -1,45 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; -import { IconArrowBack } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; - -function CreateJumlahPengangguran() { - const router = useRouter(); - return ( - - - - - - - - Create Jumlah Pengangguran - Pengangguran Terdidik} - placeholder='Masukkan pengangguran terdidik' - /> - Usia Produktif} - placeholder='Masukkan usia produktif' - /> - Sedang Mencari Kerja} - placeholder='Masukkan sedang mencari kerja' - /> - Pengangguran Tidak Terdidik} - placeholder='Masukkan pengangguran tidak terdidik' - /> - - - - - - - ); -} - -export default CreateJumlahPengangguran; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/[id]/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/[id]/edit/page.tsx new file mode 100644 index 00000000..38e187d3 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/[id]/edit/page.tsx @@ -0,0 +1,185 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'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 } from '@mantine/core'; +import { IconArrowBack } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; + +function EditDetailDataPengangguran() { + const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran) + const router = useRouter(); + const params = useParams() + + const [formData, setFormData] = useState({ + month: stateDetail.update.form.month, + year: stateDetail.update.form.year, + totalUnemployment: stateDetail.update.form.totalUnemployment, + educatedUnemployment: stateDetail.update.form.educatedUnemployment, + uneducatedUnemployment: stateDetail.update.form.uneducatedUnemployment, + percentageChange: stateDetail.update.form.percentageChange || 0, // Ensure it's always a number + }) + + const calculateTotalAndChange = async () => { + const total = formData.educatedUnemployment + formData.uneducatedUnemployment; + + // Ambil data bulan sebelumnya + const monthOrder = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des']; + const currentIndex = monthOrder.findIndex( + (m) => m.toLowerCase() === formData.month.toLowerCase() + ); + + let percentageChange = 0; + if (currentIndex > 0) { + const prevMonth = monthOrder[currentIndex - 1]; + const prev = await stateDetail.findByMonthYear.load({ + month: prevMonth, + year: formData.year, + }); + + if (prev?.totalUnemployment) { + percentageChange = Number( + (((total - prev.totalUnemployment) / prev.totalUnemployment) * 100).toFixed(1) + ); + } + } + + setFormData({ + ...formData, + totalUnemployment: total, + percentageChange, + }); + + return { total, percentageChange }; + }; + + useEffect(() => { + const loadDetail = async () => { + const id = params?.id as string; + if (!id) return; + + try { + await stateDetail.findUnique.load(id); // ambil by ID + const data = stateDetail.findUnique.data; + + if (data) { + // Set the ID for update + stateDetail.update.id = id; + + // Isi state Valtio untuk update + stateDetail.update.form = { + ...data, + percentageChange: data.percentageChange || 0 // Ensure it's always a number + }; + + // Isi local formData supaya input bisa dikontrol + setFormData({ + month: data.month, + year: data.year, + totalUnemployment: data.totalUnemployment, + educatedUnemployment: data.educatedUnemployment, + uneducatedUnemployment: data.uneducatedUnemployment, + percentageChange: data.percentageChange || 0, // Ensure it's always a number + }); + } + } catch (error) { + console.error("Error loading detail:", error); + toast.error("Gagal memuat data detail"); + } + }; + + loadDetail(); + }, [params?.id]); + + + const handleSubmit = async () => { + const { total, percentageChange } = await calculateTotalAndChange(); + try { + 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/detail-data-pengangguran"); + } + } catch (error) { + console.error("Error updating:", error); + toast.error("Terjadi kesalahan saat memperbarui data"); + } + } + + return ( + + + + + + + Edit Detail Data Pengangguran + + (setFormData({ + ...formData, + month: val.currentTarget.value + }))} + /> + (setFormData({ + ...formData, + year: Number(val.currentTarget.value) + }))} + /> + (setFormData({ + ...formData, + educatedUnemployment: Number(val.currentTarget.value) + }))} + /> + (setFormData({ + ...formData, + uneducatedUnemployment: Number(val.currentTarget.value) + }))} + /> + + Total Otomatis: {formData.totalUnemployment} + + + Perubahan Otomatis:{" "} + {formData.percentageChange !== null + ? `${formData.percentageChange}%` + : '-'} + + + + + + + + ); +} + +export default EditDetailDataPengangguran; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/[id]/page.tsx new file mode 100644 index 00000000..e4e9cbac --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/[id]/page.tsx @@ -0,0 +1,111 @@ +'use client' +import { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus'; +import jumlahPengangguranState from '@/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran'; +import colors from '@/con/colors'; +import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useProxy } from 'valtio/utils'; + +function DetailJumlahPengangguran() { + const router = useRouter(); + const params = useParams() + const [modalHapus, setModalHapus] = useState(false) + const [selectedId, setSelectedId] = useState(null) + const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran) + + useShallowEffect(() => { + stateDetail.findUnique.load(params?.id as string) + }, [params?.id]) + + const handleHapus = () => { + if (selectedId) { + stateDetail.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + router.push("/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran") + } + } + + if (!stateDetail.findUnique.data) { + return ( + + + + ) + } + + return ( + + + + + + + Detail Data Pengangguran + + + + Pengangguran Terdidik + {stateDetail.findUnique.data?.educatedUnemployment} + + + Pengangguran Tidak Terdidik + {stateDetail.findUnique.data?.uneducatedUnemployment} + + + Perubahan + {stateDetail.findUnique.data?.percentageChange} + + + Tahun + {stateDetail.findUnique.data?.year} + + + Bulan + {stateDetail.findUnique.data?.month} + + + Total Pengangguran + {stateDetail.findUnique.data?.totalUnemployment} + + + + + + + + + + + + + {/* Modal Hapus */} + setModalHapus(false)} + onConfirm={handleHapus} + text="Apakah anda yakin ingin menghapus data ini?" + /> + + ); +} + +export default DetailJumlahPengangguran; + diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create/page.tsx new file mode 100644 index 00000000..8107817e --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create/page.tsx @@ -0,0 +1,139 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +'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 } from '@mantine/core'; +import { IconArrowBack } from '@tabler/icons-react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useProxy } from 'valtio/utils'; + +function CreateJumlahPengangguran() { + const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran) + const [chartData, setChartData] = useState([]); + const router = useRouter(); + + const resetForm = () => { + stateDetail.create.form = { + month: "", + year: 0, + totalUnemployment: 0, + educatedUnemployment: 0, + uneducatedUnemployment: 0, + percentageChange: 0, + } + } + + const calculateTotalAndChange = async () => { + const total = + stateDetail.create.form.educatedUnemployment + + stateDetail.create.form.uneducatedUnemployment; + + stateDetail.create.form.totalUnemployment = total; + + // Ambil data bulan sebelumnya + const monthOrder = [ + 'Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', + 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des' + ]; + const currentIndex = monthOrder.findIndex( + (m) => m.toLowerCase() === stateDetail.create.form.month.toLowerCase() + ); + + if (currentIndex > 0) { + const prevMonth = monthOrder[currentIndex - 1]; + const prev = await stateDetail.findByMonthYear.load({ + month: prevMonth, + year: stateDetail.create.form.year, + }); + + if (prev?.totalUnemployment) { + const change = ((total - prev.totalUnemployment) / prev.totalUnemployment) * 100; + stateDetail.create.form.percentageChange = Number(change.toFixed(1)); + } else { + stateDetail.create.form.percentageChange = 0; + } + } else { + stateDetail.create.form.percentageChange = 0; + } + }; + + const handleSubmit = async () => { + await calculateTotalAndChange(); + const id = await stateDetail.create.create(); + if (id) { + await stateDetail.findUnique.load(String(id)); + if (stateDetail.findUnique.data) { + setChartData([stateDetail.findUnique.data]); + } + resetForm(); + router.push('/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran'); + } + }; + + return ( + + + + + + Tambah Detail Data Pengangguran + + (stateDetail.create.form.month = e.currentTarget.value)} + /> + + (stateDetail.create.form.year = Number(e.currentTarget.value)) + } + /> + { + stateDetail.create.form.educatedUnemployment = Number( + e.currentTarget.value, + ); + }} + /> + { + stateDetail.create.form.uneducatedUnemployment = Number( + e.currentTarget.value, + ); + }} + /> + + Total Otomatis: {stateDetail.create.form.totalUnemployment} + + + Perubahan Otomatis:{" "} + {stateDetail.create.form.percentageChange !== null + ? `${stateDetail.create.form.percentageChange}%` + : '-'} + + + + + + + + ); +} + +export default CreateJumlahPengangguran; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/page.tsx new file mode 100644 index 00000000..a8648830 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail-data-pengangguran/page.tsx @@ -0,0 +1,87 @@ +'use client' +import colors from '@/con/colors'; +import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Title } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { IconDeviceImac, IconSearch } from '@tabler/icons-react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useProxy } from 'valtio/utils'; +import JudulListTab from '../../../_com/jusulListTab'; +import jumlahPengangguranState from '../../../_state/ekonomi/jumlah-pengangguran'; + +function DetailDataPengangguran() { + return ( + + + Detail Data Pengangguran + + + + ); +} + +function ListDetailDataPengangguran() { + const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran) + const router = useRouter(); + const [search, setSearch] = useState("") + + useShallowEffect(() => { + stateDetail.findMany.load() + }, []) + + const filteredData = (stateDetail.findMany.data || []).filter(item => { + const keyword = search.toLowerCase(); + return ( + item.month.toLowerCase().includes(keyword) || + item.year.toString().toLowerCase().includes(keyword) + ); + }); + + if (!stateDetail.findMany.data) { + return ( + + + + ) + } + return ( + + + setSearch(e.currentTarget.value)} + placeholder='pencarian' + searchIcon={} + /> + + + + Bulan + Terdidik + Tidak Terdidik + Detail + + + + {filteredData.map((item) => ( + + {item.month} + {item.educatedUnemployment} + {item.uneducatedUnemployment} + + + + + ))} + +
+
+
+ ); +} + +export default DetailDataPengangguran; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail/page.tsx deleted file mode 100644 index d829de7a..00000000 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail/page.tsx +++ /dev/null @@ -1,66 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Button, Flex, Paper, Stack, Text } from '@mantine/core'; -import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; -// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; - -function DetailJumlahPengangguran() { - const router = useRouter(); - return ( - - - - - - - Detail Jumlah Pengangguran - - - - - Pengangguran Terdidik - 100 - - - Usia Produktif - 200 - - - Sedang Mencari Kerja - 300 - - - Pengangguran Tidak Terdidik - 30 - - - - - - - - - - - - - {/* Modal Hapus - setModalHapus(false)} - onConfirm={handleHapus} - text="Apakah anda yakin ingin menghapus potensi ini?" - /> */} - - ); -} - -export default DetailJumlahPengangguran; - diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/edit/page.tsx deleted file mode 100644 index 16917566..00000000 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/edit/page.tsx +++ /dev/null @@ -1,45 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; -import { IconArrowBack } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; - -function EditJumlahPengangguran() { - const router = useRouter(); - return ( - - - - - - - - Edit Jumlah Pengangguran - Pengangguran Terdidik} - placeholder='Masukkan pengangguran terdidik' - /> - Usia Produktif} - placeholder='Masukkan usia produktif' - /> - Sedang Mencari Kerja} - placeholder='Masukkan sedang mencari kerja' - /> - Pengangguran Tidak Terdidik} - placeholder='Masukkan pengangguran tidak terdidik' - /> - - - - - - - ); -} - -export default EditJumlahPengangguran; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/layout.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/layout.tsx new file mode 100644 index 00000000..072b9266 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/layout.tsx @@ -0,0 +1,9 @@ +import LayoutTabs from "./_lib/layoutTabs"; + +export default function Layout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/page.tsx deleted file mode 100644 index d02d535a..00000000 --- a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/page.tsx +++ /dev/null @@ -1,58 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Button, Paper, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } 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'; - -function JumlahPengangguran() { - return ( - - } - /> - - - ); -} - -function ListJumlahPengangguran() { - const router = useRouter(); - return ( - - - - - - - Pengangguran Terdidik - Usia Produktif - Sedang Mencari Kerja - Detail - - - - - 100 - 200 - 300 - - - - - -
-
-
- ); -} - -export default JumlahPengangguran; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/[id]/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/[id]/edit/page.tsx new file mode 100644 index 00000000..69da2f21 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/[id]/edit/page.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function Page() { + return ( +
+ Page +
+ ); +} + +export default Page; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/[id]/page.tsx new file mode 100644 index 00000000..69da2f21 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/[id]/page.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function Page() { + return ( +
+ Page +
+ ); +} + +export default Page; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/create/page.tsx new file mode 100644 index 00000000..69da2f21 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/create/page.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function Page() { + return ( +
+ Page +
+ ); +} + +export default Page; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/page.tsx new file mode 100644 index 00000000..69da2f21 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/page.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function Page() { + return ( +
+ Page +
+ ); +} + +export default Page; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/[id]/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/[id]/edit/page.tsx new file mode 100644 index 00000000..69da2f21 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/[id]/edit/page.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function Page() { + return ( +
+ Page +
+ ); +} + +export default Page; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/[id]/page.tsx new file mode 100644 index 00000000..69da2f21 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/[id]/page.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function Page() { + return ( +
+ Page +
+ ); +} + +export default Page; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/create/page.tsx new file mode 100644 index 00000000..69da2f21 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/create/page.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function Page() { + return ( +
+ Page +
+ ); +} + +export default Page; diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/page.tsx new file mode 100644 index 00000000..69da2f21 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/page.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function Page() { + return ( +
+ Page +
+ ); +} + +export default Page; diff --git a/src/app/admin/_com/list_PageAdmin.tsx b/src/app/admin/_com/list_PageAdmin.tsx index 45bd5ee7..543e7453 100644 --- a/src/app/admin/_com/list_PageAdmin.tsx +++ b/src/app/admin/_com/list_PageAdmin.tsx @@ -235,7 +235,7 @@ export const navBar = [ { id: "Ekonomi_5", name: "Jumlah Pengangguran", - path: "/admin/ekonomi/jumlah-pengangguran" + path: "/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran" }, { id: "Ekonomi_6", diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create.ts index d33c4ee3..20728bac 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create.ts @@ -1,3 +1,64 @@ +// import prisma from "@/lib/prisma"; +// import { Prisma } from "@prisma/client"; +// import { Context } from "elysia"; + +// type FormCreate = Prisma.DetailDataPengangguranGetPayload<{ +// select: { +// month: true; +// year: true; +// totalUnemployment: true; +// educatedUnemployment: true; +// uneducatedUnemployment: true; +// percentageChange: true; +// }; +// }>; + +// export default async function detailDataPengangguranCreate(context: Context) { +// const body = context.body as FormCreate; + +// // Cek apakah data untuk bulan & tahun tersebut sudah ada +// const existing = await prisma.detailDataPengangguran.findFirst({ +// where: { +// month: body.month, +// year: body.year, +// }, +// }); + +// if (existing) { +// return { +// success: false, +// message: `Data bulan ${body.month} ${body.year} sudah ada.`, +// data: null, +// }; +// } + +// const created = await prisma.detailDataPengangguran.create({ +// data: { +// month: body.month, +// year: body.year, +// totalUnemployment: body.totalUnemployment, +// educatedUnemployment: body.educatedUnemployment, +// uneducatedUnemployment: body.uneducatedUnemployment, +// percentageChange: body.percentageChange ?? null, +// }, +// select: { +// id: true, +// month: true, +// year: true, +// totalUnemployment: true, +// educatedUnemployment: true, +// uneducatedUnemployment: true, +// percentageChange: true, +// }, +// }); + +// return { +// success: true, +// message: "Berhasil menambahkan data pengangguran bulanan", +// data: created, +// }; +// } + import prisma from "@/lib/prisma"; import { Prisma } from "@prisma/client"; import { Context } from "elysia"; @@ -9,14 +70,14 @@ type FormCreate = Prisma.DetailDataPengangguranGetPayload<{ totalUnemployment: true; educatedUnemployment: true; uneducatedUnemployment: true; - percentageChange: true; }; }>; +const monthOrder = ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"]; + export default async function detailDataPengangguranCreate(context: Context) { const body = context.body as FormCreate; - // Cek apakah data untuk bulan & tahun tersebut sudah ada const existing = await prisma.detailDataPengangguran.findFirst({ where: { month: body.month, @@ -32,6 +93,24 @@ export default async function detailDataPengangguranCreate(context: Context) { }; } + // Cari bulan sebelumnya + const currentMonthIndex = monthOrder.indexOf(body.month); + const prevMonth = currentMonthIndex > 0 ? monthOrder[currentMonthIndex - 1] : "Des"; + const prevYear = currentMonthIndex > 0 ? body.year : body.year - 1; + + const prevData = await prisma.detailDataPengangguran.findFirst({ + where: { + month: prevMonth, + year: prevYear, + }, + }); + + let percentageChange: number | null = null; + if (prevData) { + const change = ((body.totalUnemployment - prevData.totalUnemployment) / prevData.totalUnemployment) * 100; + percentageChange = parseFloat(change.toFixed(1)); + } + const created = await prisma.detailDataPengangguran.create({ data: { month: body.month, @@ -39,7 +118,7 @@ export default async function detailDataPengangguranCreate(context: Context) { totalUnemployment: body.totalUnemployment, educatedUnemployment: body.educatedUnemployment, uneducatedUnemployment: body.uneducatedUnemployment, - percentageChange: body.percentageChange ?? null, + percentageChange, }, select: { id: true, diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findByMonthYear.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findByMonthYear.ts new file mode 100644 index 00000000..af787cd4 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findByMonthYear.ts @@ -0,0 +1,35 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function findByMonthYear(context: Context) { + const { month, year } = context.params as { month: string; year: string }; + + if (!month || !year) { + return { + success: false, + message: "Bulan dan tahun wajib diisi", + data: null, + }; + } + + const data = await prisma.detailDataPengangguran.findFirst({ + where: { + month, + year: Number(year), + }, + }); + + if (!data) { + return { + success: false, + message: `Data untuk bulan ${month} tahun ${year} tidak ditemukan`, + data: null, + }; + } + + return { + success: true, + message: "Data ditemukan", + data, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/index.ts index 0c732dac..ae727b29 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/index.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/index.ts @@ -4,6 +4,7 @@ import detailDataPengangguranCreate from "./create"; import detailDataPengangguranUpdate from "./updt"; import detailDataPengangguranFindUnique from "./findUnique"; import detailDataPengangguranDelete from "./del"; +import findByMonthYear from "./findByMonthYear"; const DetailDataPengangguran = new Elysia({ prefix: "/detaildatapengangguran", @@ -43,6 +44,12 @@ const DetailDataPengangguran = new Elysia({ params: t.Object({ id: t.String(), }), + }) + .get("/month/:month/year/:year", findByMonthYear, { + params: t.Object({ + month: t.String(), + year: t.String(), + }), }); export default DetailDataPengangguran; diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/updt.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/updt.ts index 502b7a7f..648a792a 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/updt.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/updt.ts @@ -1,68 +1,145 @@ +// import prisma from "@/lib/prisma"; +// import { Context } from "elysia"; + +// export default async function detailDataPengangguranUpdate(context: Context) { +// const id = context.params?.id; + +// if (!id) { +// return { +// success: false, +// message: "ID tidak ditemukan", +// } +// } + +// const { month, year, totalUnemployment, educatedUnemployment, uneducatedUnemployment, percentageChange } = context.body as { +// month: string; +// year: number; +// totalUnemployment: number; +// educatedUnemployment: number; +// uneducatedUnemployment: number; +// percentageChange: number; +// } + +// const duplicate = await prisma.detailDataPengangguran.findFirst({ +// where: { +// month, +// year, +// NOT: { id }, +// }, +// }); + +// if (duplicate) { +// return { +// success: false, +// message: `Data bulan ${month} ${year} sudah ada.`, +// }; +// } + +// const existing = await prisma.detailDataPengangguran.findUnique({ +// where: { +// id: id, +// }, +// }) + +// if (!existing) { +// return { +// success: false, +// message: "Data tidak ditemukan", +// } +// } + +// const updated = await prisma.detailDataPengangguran.update({ +// where: { id }, +// data: { +// month, +// year, +// totalUnemployment, +// educatedUnemployment, +// uneducatedUnemployment, +// percentageChange, +// }, +// }) + +// return { +// success: true, +// message: "Data berhasil diupdate", +// data: updated, +// } +// } + + import prisma from "@/lib/prisma"; import { Context } from "elysia"; + +const monthOrder = ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"]; + export default async function detailDataPengangguranUpdate(context: Context) { const id = context.params?.id; - + if (!id) { - return { - success: false, - message: "ID tidak ditemukan", - } + return { success: false, message: "ID tidak ditemukan" }; } - - const { month, year, totalUnemployment, educatedUnemployment, uneducatedUnemployment, percentageChange } = context.body as { - month: string; - year: number; - totalUnemployment: number; - educatedUnemployment: number; - uneducatedUnemployment: number; - percentageChange: number; - } - + + const { month, year, totalUnemployment, educatedUnemployment, uneducatedUnemployment } = context.body as { + month: string; + year: number; + totalUnemployment: number; + educatedUnemployment: number; + uneducatedUnemployment: number; + }; + const duplicate = await prisma.detailDataPengangguran.findFirst({ - where: { - month, - year, - NOT: { id }, - }, + where: { + month, + year, + NOT: { id }, + }, }); - + if (duplicate) { - return { - success: false, - message: `Data bulan ${month} ${year} sudah ada.`, - }; - } - - const existing = await prisma.detailDataPengangguran.findUnique({ - where: { - id: id, - }, - }) - - if (!existing) { - return { - success: false, - message: "Data tidak ditemukan", - } + return { success: false, message: `Data bulan ${month} ${year} sudah ada.` }; } - + + const current = await prisma.detailDataPengangguran.findUnique({ where: { id } }); + + if (!current) { + return { success: false, message: "Data tidak ditemukan" }; + } + + const currentMonthIndex = monthOrder.indexOf(month); + const prevMonth = currentMonthIndex > 0 ? monthOrder[currentMonthIndex - 1] : "Des"; + const prevYear = currentMonthIndex > 0 ? year : year - 1; + + const prevData = await prisma.detailDataPengangguran.findFirst({ + where: { + month: prevMonth, + year: prevYear, + }, + }); + + let percentageChange: number | null = null; + if (prevData) { + const change = ((totalUnemployment - prevData.totalUnemployment) / prevData.totalUnemployment) * 100; + percentageChange = parseFloat(change.toFixed(1)); + } + const updated = await prisma.detailDataPengangguran.update({ - where: { id }, - data: { - month, - year, - totalUnemployment, - educatedUnemployment, - uneducatedUnemployment, - percentageChange, - }, - }) - + where: { id }, + data: { + month, + year, + totalUnemployment, + educatedUnemployment, + uneducatedUnemployment, + percentageChange, + }, + }); + return { - success: true, - message: "Data berhasil diupdate", - data: updated, - } -} \ No newline at end of file + success: true, + message: "Data berhasil diupdate", + data: updated, + }; + } + \ No newline at end of file