diff --git a/prisma/data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json b/prisma/data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json new file mode 100644 index 00000000..f55abd7f --- /dev/null +++ b/prisma/data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json @@ -0,0 +1,51 @@ +[ + { + "month": "Jan", + "year": 2025, + "totalUnemployment": 160, + "educatedUnemployment": 95, + "uneducatedUnemployment": 65, + "percentageChange": null + }, + { + "month": "Feb", + "year": 2025, + "totalUnemployment": 155, + "educatedUnemployment": 90, + "uneducatedUnemployment": 65, + "percentageChange": -3.1 + }, + { + "month": "Mar", + "year": 2025, + "totalUnemployment": 150, + "educatedUnemployment": 88, + "uneducatedUnemployment": 62, + "percentageChange": -3.2 + }, + { + "month": "Apr", + "year": 2025, + "totalUnemployment": 148, + "educatedUnemployment": 85, + "uneducatedUnemployment": 63, + "percentageChange": -1.3 + }, + { + "month": "Mei", + "year": 2025, + "totalUnemployment": 145, + "educatedUnemployment": 82, + "uneducatedUnemployment": 63, + "percentageChange": -2.0 + }, + { + "month": "Jun", + "year": 2025, + "totalUnemployment": 140, + "educatedUnemployment": 80, + "uneducatedUnemployment": 60, + "percentageChange": -3.4 + } + ] + \ No newline at end of file diff --git a/prisma/data/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran.json b/prisma/data/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran.json new file mode 100644 index 00000000..233dc473 --- /dev/null +++ b/prisma/data/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran.json @@ -0,0 +1,12 @@ +[ + { + "year": 2025, + "totalUnemployment": 140, + "educatedUnemployment": 80, + "percentageEducatedOfTotal": 57.1, + "productiveAgePopulation": 125, + "percentageProductiveOfTotal": 89.3, + "percentageChangeFromPreviousYear": -12.5 + } + ] + \ No newline at end of file diff --git a/prisma/data/ekonomi/jumlah-pengangguran/sedang-mencari-kerja.json b/prisma/data/ekonomi/jumlah-pengangguran/sedang-mencari-kerja.json new file mode 100644 index 00000000..39fe4f8b --- /dev/null +++ b/prisma/data/ekonomi/jumlah-pengangguran/sedang-mencari-kerja.json @@ -0,0 +1,8 @@ +[ + { + "recordedDate": "2025-06-30", + "count": 95, + "percentageOfTotal": 67.9 + } + ] + \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 25a9fe1e..dd630ab0 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1262,3 +1262,46 @@ model DataDemografiPekerjaan { deletedAt DateTime @default(now()) isActive Boolean @default(true) } + +// ========================================= 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) + + @@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? + + 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) + +} diff --git a/prisma/seed.ts b/prisma/seed.ts index 7cd8a6a3..df363dd4 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -21,6 +21,9 @@ import kategoriProduk from "./data/ekonomi/pasar-desa/kategori-produk.json"; import hubunganOrganisasi from "./data/ekonomi/struktur-organisasi/hubungan-organisasi.json"; import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json"; import pegawai from "./data/ekonomi/struktur-organisasi/pegawai.json"; +import detailDataPengangguran from './data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json'; +import ringkasanDataPengangguran from './data/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran.json'; +import sedangMencariKerja from './data/ekonomi/jumlah-pengangguran/sedang-mencari-kerja.json'; (async () => { for (const l of layanan) { @@ -431,6 +434,75 @@ import pegawai from "./data/ekonomi/struktur-organisasi/pegawai.json"; }); } console.log("hubungan organisasi success ..."); + + for (const d of detailDataPengangguran) { + await prisma.detailDataPengangguran.upsert({ + where: { + month_year: { month: d.month, year: d.year }, + }, + update: { + totalUnemployment: d.totalUnemployment, + educatedUnemployment: d.educatedUnemployment, + uneducatedUnemployment: d.uneducatedUnemployment, + percentageChange: d.percentageChange, + }, + create: { + month: d.month, + year: d.year, + totalUnemployment: d.totalUnemployment, + educatedUnemployment: d.educatedUnemployment, + uneducatedUnemployment: d.uneducatedUnemployment, + percentageChange: d.percentageChange, + }, + }); + } + console.log("📊 detailDataPengangguran success ..."); + + // RingkasanDataPengangguran + for (const r of ringkasanDataPengangguran) { + await prisma.ringkasanDataPengangguran.upsert({ + where: { + year: r.year, + }, + update: { + totalUnemployment: r.totalUnemployment, + educatedUnemployment: r.educatedUnemployment, + percentageEducatedOfTotal: r.percentageEducatedOfTotal, + productiveAgePopulation: r.productiveAgePopulation, + percentageProductiveOfTotal: r.percentageProductiveOfTotal, + percentageChangeFromPreviousYear: r.percentageChangeFromPreviousYear, + }, + create: { + year: r.year, + totalUnemployment: r.totalUnemployment, + educatedUnemployment: r.educatedUnemployment, + percentageEducatedOfTotal: r.percentageEducatedOfTotal, + productiveAgePopulation: r.productiveAgePopulation, + percentageProductiveOfTotal: r.percentageProductiveOfTotal, + percentageChangeFromPreviousYear: r.percentageChangeFromPreviousYear, + }, + }); + } + console.log("📈 ringkasanDataPengangguran success ..."); + + // SedangMencariKerja + for (const s of sedangMencariKerja) { + await prisma.sedangMencariKerja.upsert({ + where: { + recordedDate: new Date(s.recordedDate), + }, + update: { + count: s.count, + percentageOfTotal: s.percentageOfTotal, + }, + create: { + recordedDate: new Date(s.recordedDate), + count: s.count, + percentageOfTotal: s.percentageOfTotal, + }, + }); + } + console.log("💼 sedangMencariKerja success ..."); })() .then(() => prisma.$disconnect()) .catch((e) => { diff --git a/src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.ts b/src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.ts new file mode 100644 index 00000000..c545cde9 --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.ts @@ -0,0 +1,638 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateJumlahPengngguran = z.object({ + month: z.string().min(1, "Bulan harus diisi"), + year: z.number().min(1, "Tahun harus diisi"), + totalUnemployment: z.number().min(1, "Total pengangguran harus diisi"), + educatedUnemployment: z + .number() + .min(1, "Pengangguran pendidikan harus diisi"), + uneducatedUnemployment: z + .number() + .min(1, "Pengangguran tidak pendidikan harus diisi"), + percentageChange: z.number().min(0, "Persentase perubahan harus diisi"), +}); + +type JumlahPengangguran = { + month: string; + year: number; + totalUnemployment: number; + educatedUnemployment: number; + uneducatedUnemployment: number; + percentageChange: number; +}; + +const jumlahPengangguranForm: JumlahPengangguran = { + month: "", + year: 0, + totalUnemployment: 0, + educatedUnemployment: 0, + uneducatedUnemployment: 0, + percentageChange: 0, +}; + +const jumlahPengangguran = proxy({ + create: { + form: jumlahPengangguranForm, + loading: false, + async create() { + const cek = templateJumlahPengngguran.safeParse( + jumlahPengangguran.create.form + ); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + try { + jumlahPengangguran.create.loading = true; + const res = + await ApiFetch.api.ekonomi.jumlahpengangguran.detaildatapengangguran[ + "create" + ].post(jumlahPengangguran.create.form); + + if (res.status === 200) { + const id = res.data?.data?.id; + if (id) { + toast.success("Success create"); + jumlahPengangguran.create.form = { ...jumlahPengangguranForm }; + jumlahPengangguran.findMany.load(); + return id; + } + } + toast.error("failed create"); + return null; + } catch (error) { + console.log((error as Error).message); + return null; + } finally { + jumlahPengangguran.create.loading = false; + } + }, + }, + + findMany: { + data: null as + | Prisma.DetailDataPengangguranGetPayload<{ + omit: { isActive: true }; + }>[] + | null, + async load() { + const res = + await ApiFetch.api.ekonomi.jumlahpengangguran.detaildatapengangguran[ + "find-many" + ].get(); + if (res.status === 200) { + jumlahPengangguran.findMany.data = res.data?.data ?? []; + } + }, + }, + + findUnique: { + data: null as Prisma.DetailDataPengangguranGetPayload<{ + omit: { isActive: true }; + }> | null, + async load(id: string) { + try { + const res = await fetch( + `/api/ekonomi/jumlahpengangguran/detaildatapengangguran/${id}` + ); + if (res.ok) { + const data = await res.json(); + jumlahPengangguran.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch jumlahPengangguran:", res.statusText); + jumlahPengangguran.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching jumlahPengangguran:", error); + jumlahPengangguran.findUnique.data = null; + } + }, + }, + + update: { + id: "", + form: { ...jumlahPengangguranForm }, + loading: false, + async submit() { + const id = this.id; + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + const formData = { + month: this.form.month, + year: this.form.year, + totalUnemployment: this.form.totalUnemployment, + educatedUnemployment: this.form.educatedUnemployment, + uneducatedUnemployment: this.form.uneducatedUnemployment, + percentageChange: this.form.percentageChange, + }; + + const cek = templateJumlahPengngguran.safeParse(formData); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + + try { + this.loading = true; + const res = await fetch( + `/api/ekonomi/jumlahpengangguran/detaildatapengangguran/${id}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + } + ); + + const result = await res.json(); + + if (!res.ok || !result?.success) { + throw new Error(result?.message || "Gagal update data"); + } + + toast.success("Berhasil update data!"); + await jumlahPengangguran.findMany.load(); + return result.data; + } catch (error) { + console.error("Update error:", error); + toast.error("Gagal update data jumlah pengangguran"); + throw error; + } finally { + this.loading = false; + } + }, + }, + + delete: { + loading: false, + async byId(id: string) { + if (!id) return toast.warn("ID tidak valid"); + + try { + jumlahPengangguran.delete.loading = true; + + const response = await fetch( + `/api/ekonomi/jumlahpengangguran/detaildatapengangguran/del/${id}`, + { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + } + ); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success( + result.message || "Jumlah pengangguran berhasil dihapus" + ); + await jumlahPengangguran.findMany.load(); + } else { + toast.error(result?.message || "Gagal menghapus jumlah pengangguran"); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus jumlah pengangguran"); + } finally { + jumlahPengangguran.delete.loading = false; + } + }, + }, +}); + +const templateRingkasanData = z.object({ + year: z.number().min(1, "Tahun harus diisi"), + totalUnemployment: z.number().min(1, "Total pengangguran harus diisi"), + educatedUnemployment: z + .number() + .min(1, "Pengangguran pendidikan harus diisi"), + percentageEducatedOfTotal: z + .number() + .min(1, "Persentase pendidikan harus diisi"), + productiveAgePopulation: z.number().min(1, "Populasi produktif harus diisi"), + percentageProductiveOfTotal: z + .number() + .min(1, "Persentase produktif harus diisi"), + percentageChangeFromPreviousYear: z + .number() + .min(1, "Persentase perubahan harus diisi"), +}); + +type RingkasanData = { + year: number; + totalUnemployment: number; + educatedUnemployment: number; + percentageEducatedOfTotal: number; + productiveAgePopulation: number; + percentageProductiveOfTotal: number; + percentageChangeFromPreviousYear: number; +}; + +const ringkasanDataForm: RingkasanData = { + year: 0, + totalUnemployment: 0, + educatedUnemployment: 0, + percentageEducatedOfTotal: 0, + productiveAgePopulation: 0, + percentageProductiveOfTotal: 0, + percentageChangeFromPreviousYear: 0, +}; + +const ringkasanData = proxy({ + create: { + form: ringkasanDataForm, + loading: false, + async create() { + const cek = templateRingkasanData.safeParse(ringkasanData.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + try { + ringkasanData.create.loading = true; + const res = + await ApiFetch.api.ekonomi.jumlahpengangguran.ringkasandatapengangguran[ + "create" + ].post(ringkasanData.create.form); + + if (res.status === 200) { + const id = res.data?.data?.id; + if (id) { + toast.success("Success create"); + ringkasanData.create.form = { ...ringkasanDataForm }; + ringkasanData.findMany.load(); + return id; + } + } + toast.error("failed create"); + return null; + } catch (error) { + console.log((error as Error).message); + return null; + } finally { + ringkasanData.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.RingkasanDataPengangguranGetPayload<{ + omit: { isActive: true }; + }>[] + | null, + async load() { + const res = + await ApiFetch.api.ekonomi.jumlahpengangguran.ringkasandatapengangguran[ + "find-many" + ].get(); + if (res.status === 200) { + ringkasanData.findMany.data = res.data?.data ?? []; + } + }, + }, + findUnique: { + data: null as Prisma.RingkasanDataPengangguranGetPayload<{ + omit: { isActive: true }; + }> | null, + async load(id: string) { + try { + const res = await fetch( + `/api/ekonomi/jumlahpengangguran/ringkasandatapengangguran/${id}` + ); + if (res.ok) { + const data = await res.json(); + ringkasanData.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch ringkasanData:", res.statusText); + ringkasanData.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching ringkasanData:", error); + ringkasanData.findUnique.data = null; + } + }, + }, + update: { + id: "", + form: { ...ringkasanDataForm }, + loading: false, + async submit() { + const id = this.id; + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + const formData = { + year: this.form.year, + totalUnemployment: this.form.totalUnemployment, + educatedUnemployment: this.form.educatedUnemployment, + percentageEducatedOfTotal: this.form.percentageEducatedOfTotal, + productiveAgePopulation: this.form.productiveAgePopulation, + percentageProductiveOfTotal: this.form.percentageProductiveOfTotal, + percentageChangeFromPreviousYear: + this.form.percentageChangeFromPreviousYear, + }; + + const cek = templateJumlahPengngguran.safeParse(formData); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + + try { + this.loading = true; + const res = await fetch( + `/api/ekonomi/jumlahpengangguran/ringkasandatapengangguran/${id}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + } + ); + + const result = await res.json(); + + if (!res.ok || !result?.success) { + throw new Error(result?.message || "Gagal update data"); + } + + toast.success("Berhasil update data!"); + await ringkasanData.findMany.load(); + return result.data; + } catch (error) { + console.error("Update error:", error); + toast.error("Gagal update data ringkasan data pengangguran"); + throw error; + } finally { + this.loading = false; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + if (!id) return toast.warn("ID tidak valid"); + + try { + ringkasanData.delete.loading = true; + + const response = await fetch( + `/api/ekonomi/jumlahpengangguran/ringkasandatapengangguran/del/${id}`, + { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + } + ); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success( + result.message || "Ringkasan data pengangguran berhasil dihapus" + ); + await ringkasanData.findMany.load(); + } else { + toast.error( + result?.message || "Gagal menghapus ringkasan data pengangguran" + ); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error( + "Terjadi kesalahan saat menghapus ringkasan data pengangguran" + ); + } finally { + ringkasanData.delete.loading = false; + } + }, + }, +}); + +const templateSedangMencariKerja = z.object({ + count: z.number().min(1, "Jumlah harus diisi"), + percentageOfTotal: z.number().min(1, "Persentase harus diisi"), + recordedDate: z.string().min(1, "Tanggal harus diisi"), +}); + +type SedangMencariKerja = { + count: number; + percentageOfTotal: number; + recordedDate: string; +}; + +const sedangMencariKerjaForm: SedangMencariKerja = { + count: 0, + percentageOfTotal: 0, + recordedDate: "", +}; + +const sedangMencariKerja = proxy({ + create: { + form: sedangMencariKerjaForm, + loading: false, + async create() { + const cek = templateSedangMencariKerja.safeParse( + sedangMencariKerja.create.form + ); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + try { + sedangMencariKerja.create.loading = true; + const res = + await ApiFetch.api.ekonomi.jumlahpengangguran.sedangmencarikerja[ + "create" + ].post(sedangMencariKerja.create.form); + + if (res.status === 200) { + const id = res.data?.data?.id; + if (id) { + toast.success("Success create"); + sedangMencariKerja.create.form = { ...sedangMencariKerjaForm }; + sedangMencariKerja.findMany.load(); + return id; + } + } + toast.error("failed create"); + return null; + } catch (error) { + console.log((error as Error).message); + return null; + } finally { + sedangMencariKerja.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.SedangMencariKerjaGetPayload<{ + omit: { isActive: true }; + }>[] + | null, + async load() { + const res = + await ApiFetch.api.ekonomi.jumlahpengangguran.sedangmencarikerja[ + "find-many" + ].get(); + if (res.status === 200) { + sedangMencariKerja.findMany.data = res.data?.data ?? []; + } + }, + }, + findUnique: { + data: null as Prisma.SedangMencariKerjaGetPayload<{ + omit: { isActive: true }; + }> | null, + async load(id: string) { + try { + const res = await fetch( + `/api/ekonomi/jumlahpengangguran/sedangmencarikerja/${id}` + ); + if (res.ok) { + const data = await res.json(); + sedangMencariKerja.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch sedangMencariKerja:", res.statusText); + sedangMencariKerja.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching sedangMencariKerja:", error); + sedangMencariKerja.findUnique.data = null; + } + }, + }, + update: { + id: "", + form: { ...sedangMencariKerjaForm }, + loading: false, + async submit() { + const id = this.id; + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + const formData = { + count: this.form.count, + percentageOfTotal: this.form.percentageOfTotal, + recordedDate: this.form.recordedDate, + }; + + const cek = templateSedangMencariKerja.safeParse(formData); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + + try { + this.loading = true; + const res = await fetch( + `/api/ekonomi/jumlahpengangguran/sedangmencarikerja/${id}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + } + ); + + const result = await res.json(); + + if (!res.ok || !result?.success) { + throw new Error(result?.message || "Gagal update data"); + } + + toast.success("Berhasil update data!"); + await sedangMencariKerja.findMany.load(); + return result.data; + } catch (error) { + console.error("Update error:", error); + toast.error("Gagal update data sedang mencari kerja"); + throw error; + } finally { + this.loading = false; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + if (!id) return toast.warn("ID tidak valid"); + + try { + sedangMencariKerja.delete.loading = true; + + const response = await fetch( + `/api/ekonomi/jumlahpengangguran/sedangmencarikerja/del/${id}`, + { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + } + ); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success( + result.message || "Sedang mencari kerja berhasil dihapus" + ); + await sedangMencariKerja.findMany.load(); + } else { + toast.error( + result?.message || "Gagal menghapus sedang mencari kerja" + ); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus sedang mencari kerja"); + } finally { + sedangMencariKerja.delete.loading = false; + } + }, + }, +}); + +const jumlahPengangguranState = proxy({ + jumlahPengangguran, + ringkasanData, + sedangMencariKerja, +}); + +export default jumlahPengangguranState; diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx index fb9bb8c7..3f54a24e 100644 --- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx @@ -1,11 +1,11 @@ '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 { useMediaQuery, useShallowEffect } from '@mantine/hooks'; +import { useShallowEffect } from '@mantine/hooks'; import { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; -import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '../../_com/header'; import JudulList from '../../_com/judulList'; @@ -40,8 +40,6 @@ function ListDemografiPekerjaan({ search }: { search: string }) { const stateDemografi = useProxy(demografiPekerjaan) 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) @@ -54,7 +52,7 @@ function ListDemografiPekerjaan({ search }: { search: string }) { stateDemografi.findMany.load() } } - + useShallowEffect(() => { setMounted(true) stateDemografi.findMany.load() @@ -104,7 +102,7 @@ function ListDemografiPekerjaan({ search }: { search: string }) { {item.lakiLaki} {item.perempuan} - @@ -138,14 +136,18 @@ function ListDemografiPekerjaan({ search }: { search: string }) { Data Kelahiran & Kematian {mounted && chartData.length > 0 && ( - - - - - - - - + + + )} diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin-2024-2025/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/[id]/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin-2024-2025/[id]/page.tsx rename to src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/[id]/page.tsx diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin-2024-2025/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/create/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin-2024-2025/create/page.tsx rename to src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/create/page.tsx diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin-2024-2025/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin-2024-2025/page.tsx rename to src/app/admin/(dashboard)/ekonomi/jumlah-penduduk-miskin/page.tsx diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran-2024-2025/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/create/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran-2024-2025/create/page.tsx rename to src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/create/page.tsx diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran-2024-2025/detail/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran-2024-2025/detail/page.tsx rename to src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/detail/page.tsx diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran-2024-2025/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/edit/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran-2024-2025/edit/page.tsx rename to src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/edit/page.tsx diff --git a/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran-2024-2025/page.tsx b/src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran-2024-2025/page.tsx rename to src/app/admin/(dashboard)/ekonomi/jumlah-pengangguran/page.tsx diff --git a/src/app/admin/_com/list_PageAdmin.tsx b/src/app/admin/_com/list_PageAdmin.tsx index 820548fe..45bd5ee7 100644 --- a/src/app/admin/_com/list_PageAdmin.tsx +++ b/src/app/admin/_com/list_PageAdmin.tsx @@ -234,8 +234,8 @@ export const navBar = [ }, { id: "Ekonomi_5", - name: "Jumlah Pengangguran 2024-2025", - path: "/admin/ekonomi/jumlah-pengangguran-2024-2025" + name: "Jumlah Pengangguran", + path: "/admin/ekonomi/jumlah-pengangguran" }, { id: "Ekonomi_6", @@ -244,8 +244,8 @@ export const navBar = [ }, { id: "Ekonomi_7", - name: "Jumlah Penduduk Miskin 2024-2025", - path: "/admin/ekonomi/jumlah-penduduk-miskin-2024-2025" + name: "Jumlah Penduduk Miskin", + path: "/admin/ekonomi/jumlah-penduduk-miskin" }, { id: "Ekonomi_8", diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/index.ts index d5b1a8cf..af2bbf1e 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/index.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/index.ts @@ -9,6 +9,7 @@ import GrafikMenganggurBerdasarkanPendidikan from "./usia-kerja-yang-menganggur/ import JumlahPendudukMiskin from "./jumlah-penduduk-miskin"; import SektorUnggulanDesa from "./sektor-unggulan-desa"; import DemografiPekerjaan from "./demografi-pekerjaan"; +import JumlahPengangguran from "./jumlah-pengangguran"; const Ekonomi = new Elysia({ prefix: "/api/ekonomi", @@ -24,5 +25,6 @@ const Ekonomi = new Elysia({ .use(JumlahPendudukMiskin) .use(SektorUnggulanDesa) .use(DemografiPekerjaan) +.use(JumlahPengangguran) export default Ekonomi \ No newline at end of file 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 new file mode 100644 index 00000000..d33c4ee3 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create.ts @@ -0,0 +1,60 @@ +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, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/del.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/del.ts new file mode 100644 index 00000000..f6a99265 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/del.ts @@ -0,0 +1,36 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function detailDataPengangguranDelete(context: Context) { + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID tidak ditemukan", + } + } + + const existing = await prisma.detailDataPengangguran.findUnique({ + where: { + id: id, + }, + }) + + if (!existing) { + return { + success: false, + message: "Data tidak ditemukan", + } + } + + const deleted = await prisma.detailDataPengangguran.delete({ + where: { id }, + }) + + return { + success: true, + message: "Data berhasil dihapus", + data: deleted, + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..822fc96a --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findMany.ts @@ -0,0 +1,10 @@ +import prisma from "@/lib/prisma"; + +export default async function detailDataPengangguranFindMany() { + const res = await prisma.detailDataPengangguran.findMany({ + orderBy: [{ year: "desc" }, { month: "asc" }], + }); + return { + data: res, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findUnique.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findUnique.ts new file mode 100644 index 00000000..4e7772c4 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/findUnique.ts @@ -0,0 +1,46 @@ +import prisma from "@/lib/prisma"; + +export default async function detailDataPengangguranFindUnique(request: Request) { + const url = new URL(request.url); + const pathSegments = url.pathname.split('/'); + const id = pathSegments[pathSegments.length - 1]; + + if (!id) { + return Response.json({ + success: false, + message: "ID tidak boleh kosong", + }, { status: 400 }); + } + + try { + if (typeof id !== 'string') { + return Response.json({ + success: false, + message: "ID tidak valid", + }, { status: 400 }); + } + + const data = await prisma.detailDataPengangguran.findUnique({ + where: { id }, + }); + + if (!data) { + return Response.json({ + success: false, + message: "Data tidak ditemukan", + }, { status: 404 }); + } + + return Response.json({ + success: true, + message: "Data ditemukan", + data: data, + }, { status: 200 }); + } catch (error) { + console.error("Error fetching data:", error); + return Response.json({ + success: false, + message: "Terjadi kesalahan saat mengambil data", + }, { status: 500 }); + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..0c732dac --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/index.ts @@ -0,0 +1,48 @@ +import Elysia, { t } from "elysia"; +import detailDataPengangguranFindMany from "./findMany"; +import detailDataPengangguranCreate from "./create"; +import detailDataPengangguranUpdate from "./updt"; +import detailDataPengangguranFindUnique from "./findUnique"; +import detailDataPengangguranDelete from "./del"; + +const DetailDataPengangguran = new Elysia({ + prefix: "/detaildatapengangguran", + tags: ["Ekonomi/Jumlah Pengangguran/Detail Data Pengangguran"], +}) + .get("/:id", async (context) => { + const response = await detailDataPengangguranFindUnique( + new Request(context.request) + ); + return response; + }) + .get("/find-many", detailDataPengangguranFindMany) + .post("/create", detailDataPengangguranCreate, { + body: t.Object({ + month: t.String(), + year: t.Number(), + totalUnemployment: t.Number(), + educatedUnemployment: t.Number(), + uneducatedUnemployment: t.Number(), + percentageChange: t.Number(), + }), + }) + .put("/:id", detailDataPengangguranUpdate, { + params: t.Object({ + id: t.String(), + }), + body: t.Object({ + month: t.String(), + year: t.Number(), + totalUnemployment: t.Number(), + educatedUnemployment: t.Number(), + uneducatedUnemployment: t.Number(), + percentageChange: t.Number(), + }), + }) + .delete("/del/:id", detailDataPengangguranDelete, { + params: t.Object({ + id: 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 new file mode 100644 index 00000000..502b7a7f --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/detail-data-pengangguran/updt.ts @@ -0,0 +1,68 @@ +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, + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/index.ts new file mode 100644 index 00000000..735dd920 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/index.ts @@ -0,0 +1,13 @@ +import Elysia from "elysia"; +import DetailDataPengangguran from "./detail-data-pengangguran"; +import RingkasanDataPengangguran from "./ringkasan-data-pengangguran"; +import SedangMencariKerja from "./sedang-mencari-kerja"; + +const JumlahPengangguran = new Elysia({ + prefix: "/jumlahpengangguran", +}) +.use(DetailDataPengangguran) +.use(RingkasanDataPengangguran) +.use(SedangMencariKerja) + +export default JumlahPengangguran; \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/create.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/create.ts new file mode 100644 index 00000000..4f8c4b57 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/create.ts @@ -0,0 +1,61 @@ +import prisma from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; + +type FormCreate = Prisma.RingkasanDataPengangguranGetPayload<{ + select: { + year: true; + totalUnemployment: true; + educatedUnemployment: true; + percentageEducatedOfTotal: true; + productiveAgePopulation: true; + percentageProductiveOfTotal: true; + percentageChangeFromPreviousYear: true; + }; +}>; + +export default async function ringkasanDataPengangguranCreate(context: Context) { + const body = context.body as FormCreate; + + const existing = await prisma.ringkasanDataPengangguran.findFirst({ + where: { + year: body.year, + }, + }); + + if (existing) { + return { + success: false, + message: `Data tahun ${body.year} sudah ada.`, + data: null, + }; + } + + const created = await prisma.ringkasanDataPengangguran.create({ + data: { + year: body.year, + totalUnemployment: body.totalUnemployment, + educatedUnemployment: body.educatedUnemployment, + percentageEducatedOfTotal: body.percentageEducatedOfTotal, + productiveAgePopulation: body.productiveAgePopulation, + percentageProductiveOfTotal: body.percentageProductiveOfTotal, + percentageChangeFromPreviousYear: body.percentageChangeFromPreviousYear, + }, + select: { + id: true, + year: true, + totalUnemployment: true, + educatedUnemployment: true, + percentageEducatedOfTotal: true, + productiveAgePopulation: true, + percentageProductiveOfTotal: true, + percentageChangeFromPreviousYear: true, + }, + }); + + return { + success: true, + message: "Berhasil menambahkan data ringkasan pengangguran", + data: created, + }; +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/del.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/del.ts new file mode 100644 index 00000000..f8408c1d --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/del.ts @@ -0,0 +1,38 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function ringkasanDataPengangguranDelete(context: Context) { + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID tidak ditemukan", + } + } + + const existing = await prisma.ringkasanDataPengangguran.findUnique({ + where: { + id: id, + }, + }) + + if (!existing) { + return { + success: false, + message: "Data tidak ditemukan", + } + } + + const deleted = await prisma.ringkasanDataPengangguran.delete({ + where: { + id: id, + }, + }) + + return { + success: true, + message: "Berhasil menghapus data ringkasan pengangguran", + data: deleted, + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/findMany.ts new file mode 100644 index 00000000..9590346d --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/findMany.ts @@ -0,0 +1,10 @@ +import prisma from "@/lib/prisma"; + +export default async function ringkasanDataPengangguranFindMany() { + const res = await prisma.ringkasanDataPengangguran.findMany({ + orderBy: [{ year: "desc" }], + }); + return { + data: res, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/findUnique.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/findUnique.ts new file mode 100644 index 00000000..3239b486 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/findUnique.ts @@ -0,0 +1,45 @@ +import prisma from "@/lib/prisma"; + +export default async function ringkasanDataPengangguranFindUnique(request: Request) { + const url = new URL(request.url); + const pathSegments = url.pathname.split('/'); + const id = pathSegments[pathSegments.length - 1]; + + if (!id) { + return Response.json({ + success: false, + message: "ID tidak boleh kosong", + }, { status: 400 }); + } + + try { + if (typeof id !== 'string') { + return Response.json({ + success: false, + message: "ID tidak valid", + }, { status: 400 }); + } + + const data = await prisma.ringkasanDataPengangguran.findUnique({ + where: { id }, + }); + + if (!data) { + return Response.json({ + success: false, + message: "Data tidak ditemukan", + }, { status: 404 }); + } + + return Response.json({ + success: true, + data: data, + }, { status: 200 }); + } catch (error) { + console.error("Error fetching data:", error); + return Response.json({ + success: false, + message: "Terjadi kesalahan saat mengambil data", + }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/index.ts new file mode 100644 index 00000000..bbcbb514 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/index.ts @@ -0,0 +1,50 @@ +import Elysia, { t } from "elysia"; +import ringkasanDataPengangguranFindUnique from "./findUnique"; +import ringkasanDataPengangguranFindMany from "./findMany"; +import ringkasanDataPengangguranCreate from "./create"; +import ringkasanDataPengangguranUpdate from "./updt"; +import ringkasanDataPengangguranDelete from "./del"; + +const RingkasanDataPengangguran = new Elysia({ + prefix: "/ringkasandatapengangguran", + tags: ["Ekonomi/Jumlah Pengangguran/Ringkasan Data Pengangguran"], +}) +.get("/:id", async (context) => { + const response = await ringkasanDataPengangguranFindUnique( + new Request(context.request) + ); + return response; +}) +.get("/find-many", ringkasanDataPengangguranFindMany) +.post("/create", ringkasanDataPengangguranCreate, { + body: t.Object({ + year: t.Number(), + totalUnemployment: t.Number(), + educatedUnemployment: t.Number(), + percentageEducatedOfTotal: t.Number(), + productiveAgePopulation: t.Number(), + percentageProductiveOfTotal: t.Number(), + percentageChangeFromPreviousYear: t.Number(), + }), +}) +.put("/:id", ringkasanDataPengangguranUpdate, { + params: t.Object({ + id: t.String(), + }), + body: t.Object({ + year: t.Number(), + totalUnemployment: t.Number(), + educatedUnemployment: t.Number(), + percentageEducatedOfTotal: t.Number(), + productiveAgePopulation: t.Number(), + percentageProductiveOfTotal: t.Number(), + percentageChangeFromPreviousYear: t.Number(), + }), +}) +.delete("/del/:id", ringkasanDataPengangguranDelete, { + params: t.Object({ + id: t.String(), + }), +}); + +export default RingkasanDataPengangguran; diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/updt.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/updt.ts new file mode 100644 index 00000000..d81b2a47 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/ringkasan-data-pengangguran/updt.ts @@ -0,0 +1,70 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function ringkasanDataPengangguranUpdate(context: Context) { + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID tidak ditemukan", + } + } + + const { year, totalUnemployment, educatedUnemployment, percentageEducatedOfTotal, productiveAgePopulation, percentageProductiveOfTotal, percentageChangeFromPreviousYear } = context.body as { + year: number; + totalUnemployment: number; + educatedUnemployment: number; + percentageEducatedOfTotal: number; + productiveAgePopulation: number; + percentageProductiveOfTotal: number; + percentageChangeFromPreviousYear: number; + } + + const duplicate = await prisma.ringkasanDataPengangguran.findFirst({ + where: { + year, + NOT: { id }, + }, + }); + + if (duplicate) { + return { + success: false, + message: `Data tahun ${year} sudah ada.`, + }; + } + + const existing = await prisma.ringkasanDataPengangguran.findUnique({ + where: { + id: id, + }, + }) + + if (!existing) { + return { + success: false, + message: "Data tidak ditemukan", + } + } + + const updated = await prisma.ringkasanDataPengangguran.update({ + where: { id }, + data: { + year, + totalUnemployment, + educatedUnemployment, + percentageEducatedOfTotal, + productiveAgePopulation, + percentageProductiveOfTotal, + percentageChangeFromPreviousYear, + }, + }) + + return { + success: true, + message: "Data berhasil diupdate", + data: updated, + } +} + \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/create.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/create.ts new file mode 100644 index 00000000..61a440ea --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/create.ts @@ -0,0 +1,49 @@ +import prisma from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; + +type FormCreate = Prisma.SedangMencariKerjaGetPayload<{ + select: { + count: true; + percentageOfTotal: true; + recordedDate: true; + }; +}>; + +export default async function sedangMencariKerjaCreate(context: Context) { + const body = context.body as FormCreate; + + const existing = await prisma.sedangMencariKerja.findFirst({ + where: { + recordedDate: body.recordedDate, + }, + }); + + if (existing) { + return { + success: false, + message: "Data sudah ada", + data: null, + }; + } + + const created = await prisma.sedangMencariKerja.create({ + data: { + count: body.count, + percentageOfTotal: body.percentageOfTotal, + recordedDate: body.recordedDate, + }, + select: { + id: true, + count: true, + percentageOfTotal: true, + recordedDate: true, + }, + }); + + return { + success: true, + message: "Berhasil menambahkan data sedang mencari kerja", + data: created, + }; +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/del.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/del.ts new file mode 100644 index 00000000..c50d7b58 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/del.ts @@ -0,0 +1,38 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function sedangMencariKerjaDelete(context: Context) { + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID tidak ditemukan", + } + } + + const existing = await prisma.sedangMencariKerja.findUnique({ + where: { + id: id, + }, + }) + + if (!existing) { + return { + success: false, + message: "Data tidak ditemukan", + } + } + + const deleted = await prisma.sedangMencariKerja.delete({ + where: { + id: id, + }, + }) + + return { + success: true, + message: "Berhasil menghapus data sedang mencari kerja", + data: deleted, + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/findMany.ts new file mode 100644 index 00000000..af2b38fb --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/findMany.ts @@ -0,0 +1,10 @@ +import prisma from "@/lib/prisma"; + +export default async function sedangMencariKerjaFindMany() { + const res = await prisma.sedangMencariKerja.findMany({ + orderBy: [{ recordedDate: "desc" }], + }); + return { + data: res, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/findUnique.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/findUnique.ts new file mode 100644 index 00000000..4dc460d2 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/findUnique.ts @@ -0,0 +1,46 @@ +import prisma from "@/lib/prisma"; + +export default async function sedangMencariKerjaFindUnique(request: Request) { + const url = new URL(request.url); + const pathSegments = url.pathname.split('/'); + const id = pathSegments[pathSegments.length - 1]; + + if (!id) { + return Response.json({ + success: false, + message: "ID tidak boleh kosong", + }, { status: 400 }); + } + + try { + if (typeof id !== 'string') { + return Response.json({ + success: false, + message: "ID tidak valid", + }, { status: 400 }); + } + + const data = await prisma.sedangMencariKerja.findUnique({ + where: { id }, + }); + + if (!data) { + return Response.json({ + success: false, + message: "Data tidak ditemukan", + }, { status: 404 }); + } + + return Response.json({ + success: true, + message: "Data ditemukan", + data, + }, { status: 200 }); + } catch (error) { + console.error("Error fetching data:", error); + return Response.json({ + success: false, + message: "Terjadi kesalahan saat mengambil data", + }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/index.ts new file mode 100644 index 00000000..7423c0f9 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/index.ts @@ -0,0 +1,42 @@ +import Elysia, { t } from "elysia"; +import sedangMencariKerjaFindUnique from "./findUnique"; +import sedangMencariKerjaFindMany from "./findMany"; +import sedangMencariKerjaCreate from "./create"; +import sedangMencariKerjaUpdate from "./updt"; +import sedangMencariKerjaDelete from "./del"; + +const SedangMencariKerja = new Elysia({ + prefix: "/sedangmencarikerja", + tags: ["Ekonomi/Jumlah Pengangguran/Sedang Mencari Kerja"], +}) +.get("/:id", async (context) => { + const response = await sedangMencariKerjaFindUnique( + new Request(context.request) + ); + return response; +}) +.get("/find-many", sedangMencariKerjaFindMany) +.post("/create", sedangMencariKerjaCreate, { + body: t.Object({ + count: t.Number(), + percentageOfTotal: t.Number(), + recordedDate: t.String(), + }), +}) +.put("/:id", sedangMencariKerjaUpdate, { + params: t.Object({ + id: t.String(), + }), + body: t.Object({ + count: t.Number(), + percentageOfTotal: t.Number(), + recordedDate: t.String(), + }), +}) +.delete("/del/:id", sedangMencariKerjaDelete, { + params: t.Object({ + id: t.String(), + }), +}); + +export default SedangMencariKerja; diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/updt.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/updt.ts new file mode 100644 index 00000000..9d2a3c36 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/jumlah-pengangguran/sedang-mencari-kerja/updt.ts @@ -0,0 +1,49 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function sedangMencariKerjaUpdate(context: Context) { + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID tidak ditemukan", + } + } + + const { count, percentageOfTotal, recordedDate } = context.body as { + count: number; + percentageOfTotal: number; + recordedDate: string; + } + + const existing = await prisma.sedangMencariKerja.findUnique({ + where: { + id: id, + }, + }) + + if (!existing) { + return { + success: false, + message: "Data tidak ditemukan", + } + } + + const updated = await prisma.sedangMencariKerja.update({ + where: { + id: id, + }, + data: { + count: count, + percentageOfTotal: percentageOfTotal, + recordedDate: recordedDate, + }, + }) + + return { + success: true, + message: "Berhasil mengupdate data sedang mencari kerja", + data: updated, + } +} \ No newline at end of file