From 124dfb81609734a5031808e1a38d7f42655c2677 Mon Sep 17 00:00:00 2001 From: nico Date: Tue, 8 Jul 2025 23:30:48 +0800 Subject: [PATCH] UI & API Menu Ekonomi, Submenu Demografi --- .../migration.sql | 77 +++++++ prisma/schema.prisma | 40 ++-- .../_state/ekonomi/demografi-pekerjaan.ts | 197 ++++++++++++++++++ .../persentaseKelahiran.ts | 152 +++++++------- .../ekonomi/demografi-pekerjaan/[id]/page.tsx | 102 +++++++++ .../demografi-pekerjaan/create/page.tsx | 103 ++++++--- .../demografi-pekerjaan/detail/page.tsx | 62 ------ .../ekonomi/demografi-pekerjaan/edit/page.tsx | 42 ---- .../ekonomi/demografi-pekerjaan/page.tsx | 143 +++++++++++-- .../ekonomi/demografi-pekerjaan/create.ts | 34 +++ .../_lib/ekonomi/demografi-pekerjaan/del.ts | 36 ++++ .../ekonomi/demografi-pekerjaan/findMany.ts | 8 + .../ekonomi/demografi-pekerjaan/findUnique.ts | 46 ++++ .../_lib/ekonomi/demografi-pekerjaan/index.ts | 39 ++++ .../_lib/ekonomi/demografi-pekerjaan/updt.ts | 47 +++++ .../api/[[...slugs]]/_lib/ekonomi/index.ts | 2 + 16 files changed, 897 insertions(+), 233 deletions(-) create mode 100644 prisma/migrations/20250708152314_nico_8_jul_25_1/migration.sql create mode 100644 src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts create mode 100644 src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/[id]/page.tsx delete mode 100644 src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/detail/page.tsx delete mode 100644 src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/edit/page.tsx create mode 100644 src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/del.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findMany.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findUnique.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/updt.ts diff --git a/prisma/migrations/20250708152314_nico_8_jul_25_1/migration.sql b/prisma/migrations/20250708152314_nico_8_jul_25_1/migration.sql new file mode 100644 index 00000000..68303e56 --- /dev/null +++ b/prisma/migrations/20250708152314_nico_8_jul_25_1/migration.sql @@ -0,0 +1,77 @@ +-- CreateTable +CREATE TABLE "GrafikMenganggurBerdasarkanUsia" ( + "id" TEXT NOT NULL, + "usia18_25" TEXT NOT NULL, + "usia26_35" TEXT NOT NULL, + "usia36_45" TEXT NOT NULL, + "usia46_keatas" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "isActive" BOOLEAN NOT NULL DEFAULT true, + + CONSTRAINT "GrafikMenganggurBerdasarkanUsia_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "GrafikMenganggurBerdasarkanPendidikan" ( + "id" TEXT NOT NULL, + "SD" TEXT NOT NULL, + "SMP" TEXT NOT NULL, + "SMA" TEXT NOT NULL, + "D3" TEXT NOT NULL, + "S1" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "isActive" BOOLEAN NOT NULL DEFAULT true, + + CONSTRAINT "GrafikMenganggurBerdasarkanPendidikan_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "GrafikJumlahPendudukMiskin" ( + "id" UUID NOT NULL, + "year" INTEGER NOT NULL, + "totalPoorPopulation" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "isActive" BOOLEAN NOT NULL DEFAULT true, + + CONSTRAINT "GrafikJumlahPendudukMiskin_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SektorUnggulanDesa" ( + "id" UUID NOT NULL, + "name" VARCHAR(100) NOT NULL, + "description" TEXT, + "value" DOUBLE PRECISION, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "isActive" BOOLEAN NOT NULL DEFAULT true, + + CONSTRAINT "SektorUnggulanDesa_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DataDemografiPekerjaan" ( + "id" TEXT NOT NULL, + "pekerjaan" TEXT NOT NULL, + "lakiLaki" INTEGER NOT NULL, + "perempuan" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "isActive" BOOLEAN NOT NULL DEFAULT true, + + CONSTRAINT "DataDemografiPekerjaan_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "GrafikJumlahPendudukMiskin_year_key" ON "GrafikJumlahPendudukMiskin"("year"); + +-- CreateIndex +CREATE UNIQUE INDEX "SektorUnggulanDesa_name_key" ON "SektorUnggulanDesa"("name"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d7e95de5..25a9fe1e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1230,23 +1230,35 @@ model GrafikMenganggurBerdasarkanPendidikan { // ========================================= JUMLAH PENDUDUK MISKIN ========================================= // model GrafikJumlahPendudukMiskin { - id String @id @default(uuid()) @db.Uuid // Menggunakan UUID sebagai primary key - year Int @unique // Tahun data (e.g., 2024, 2025) - totalPoorPopulation Int // Jumlah penduduk miskin (e.g., 4800000) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - deletedAt DateTime @default(now()) - isActive Boolean @default(true) + id String @id @default(uuid()) @db.Uuid // Menggunakan UUID sebagai primary key + year Int @unique // Tahun data (e.g., 2024, 2025) + totalPoorPopulation Int // Jumlah penduduk miskin (e.g., 4800000) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) } // ========================================= SEKTOR UNGGULAN DESA ========================================= // model SektorUnggulanDesa { - id String @id @default(uuid()) @db.Uuid // Menggunakan UUID sebagai primary key - name String @unique @db.VarChar(100) // Nama sektor (e.g., "Sektor Pertanian", "Sektor Peternakan") - description String? @db.Text // Deskripsi lengkap tentang sektor - value Float? // Nilai kuantitatif sektor (misalnya, kontribusi PDB, jumlah produksi, dll.) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id String @id @default(uuid()) @db.Uuid // Menggunakan UUID sebagai primary key + name String @unique @db.VarChar(100) // Nama sektor (e.g., "Sektor Pertanian", "Sektor Peternakan") + description String? @db.Text // Deskripsi lengkap tentang sektor + value Float? // Nilai kuantitatif sektor (misalnya, kontribusi PDB, jumlah produksi, dll.) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + +// ========================================= DEMOGRAFI PEKERJAAN ========================================= // +model DataDemografiPekerjaan { + id String @id @default(cuid()) + pekerjaan String + lakiLaki Int + perempuan Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt deletedAt DateTime @default(now()) isActive Boolean @default(true) -} \ No newline at end of file +} diff --git a/src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts b/src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts new file mode 100644 index 00000000..8814fe8d --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts @@ -0,0 +1,197 @@ +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 templateDemografiPekerjaan = z.object({ + pekerjaan: z.string().min(1, "Pekerjaan harus diisi"), + lakiLaki: z.number().min(1, "Laki - Laki harus diisi"), + perempuan: z.number().min(1, "Perempuan harus diisi"), +}); + +type DemografiPekerjaan = Prisma.DataDemografiPekerjaanGetPayload<{ + select: { + pekerjaan: true; + lakiLaki: true; + perempuan: true; + }; +}>; + +const defaultForm: DemografiPekerjaan = { + pekerjaan: "", + lakiLaki: 0, + perempuan: 0, +}; + +const demografiPekerjaan = proxy({ + create: { + form: defaultForm, + loading: false, + async create() { + const cek = templateDemografiPekerjaan.safeParse( + demografiPekerjaan.create.form + ); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + try { + demografiPekerjaan.create.loading = true; + const res = await ApiFetch.api.ekonomi.demografipekerjaan[ + "create" + ].post(demografiPekerjaan.create.form); + + if (res.status === 200) { + const id = res.data?.data?.id; + if (id) { + toast.success("Success create"); + demografiPekerjaan.create.form = { ...defaultForm }; + demografiPekerjaan.findMany.load(); + return id; + } + } + toast.error("failed create"); + return null; + } catch (error) { + console.log((error as Error).message); + return null; + } finally { + demografiPekerjaan.create.loading = false; + } + }, + }, + + findMany: { + data: null as + | Prisma.DataDemografiPekerjaanGetPayload<{ + 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 ?? []; + } + }, + }, + + findUnique: { + data: null as Prisma.DataDemografiPekerjaanGetPayload<{ + omit: { isActive: true }; + }> | null, + async load(id: string) { + try { + const res = await fetch(`/api/ekonomi/demografipekerjaan/${id}`); + if (res.ok) { + const data = await res.json(); + demografiPekerjaan.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch demografiPekerjaan:", res.statusText); + demografiPekerjaan.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching demografiPekerjaan:", error); + demografiPekerjaan.findUnique.data = null; + } + }, + }, + + update: { + id: "", + form: { ...defaultForm }, + loading: false, + async submit() { + const id = this.id; + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + const formData = { + pekerjaan: this.form.pekerjaan, + lakiLaki: this.form.lakiLaki, + perempuan: this.form.perempuan, + }; + + const cek = templateDemografiPekerjaan.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/demografipekerjaan/${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 demografiPekerjaan.findMany.load(); + return result.data; + } catch (error) { + console.error("Update error:", error); + toast.error("Gagal update data demografi pekerjaan"); + throw error; + } finally { + this.loading = false; + } + }, + }, + + delete: { + loading: false, + async byId(id: string) { + if (!id) return toast.warn("ID tidak valid"); + + try { + demografiPekerjaan.delete.loading = true; + + const response = await fetch( + `/api/ekonomi/demografipekerjaan/del/${id}`, + { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + } + ); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success( + result.message || "Demografi pekerjaan berhasil dihapus" + ); + await demografiPekerjaan.findMany.load(); + } else { + toast.error(result?.message || "Gagal menghapus demografi pekerjaan"); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus persentase kelahiran"); + } finally { + demografiPekerjaan.delete.loading = false; + } + }, + }, +}); +export default demografiPekerjaan diff --git a/src/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran.ts b/src/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran.ts index d20da623..166a835c 100644 --- a/src/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran.ts +++ b/src/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran.ts @@ -34,15 +34,17 @@ const persentasekelahiran = proxy({ async create() { const cek = templatePersentase.safeParse(persentasekelahiran.create.form); if (!cek.success) { - const err = `[${cek.error.issues.map((v) => `${v.path.join(".")}`).join("\n")}] required`; + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; toast.error(err); return null; } try { persentasekelahiran.create.loading = true; - const res = await ApiFetch.api.kesehatan.persentasekelahiran["create"].post( - persentasekelahiran.create.form - ); + const res = await ApiFetch.api.kesehatan.persentasekelahiran[ + "create" + ].post(persentasekelahiran.create.form); if (res.status === 200) { const id = res.data?.data?.id; @@ -65,11 +67,15 @@ const persentasekelahiran = proxy({ }, findMany: { - data: null as Prisma.DataKematian_KelahiranGetPayload<{ - omit: { isActive: true }; - }>[] | null, + data: null as + | Prisma.DataKematian_KelahiranGetPayload<{ + omit: { isActive: true }; + }>[] + | null, async load() { - const res = await ApiFetch.api.kesehatan.persentasekelahiran["find-many"].get(); + const res = await ApiFetch.api.kesehatan.persentasekelahiran[ + "find-many" + ].get(); if (res.status === 200) { persentasekelahiran.findMany.data = res.data?.data ?? []; } @@ -97,62 +103,61 @@ const persentasekelahiran = proxy({ }, }, -update: { - id: "", - form: { ...defaultForm }, - loading: false, - async submit() { - const id = this.id; - if (!id) { - toast.warn("ID tidak valid"); - return null; - } - - const formData = { - tahun: this.form.tahun, - kematianKasar: this.form.kematianKasar, - kelahiranKasar: this.form.kelahiranKasar, - kematianBayi: this.form.kematianBayi, - }; - - const cek = templatePersentase.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/kesehatan/persentasekelahiran/${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"); + update: { + id: "", + form: { ...defaultForm }, + loading: false, + async submit() { + const id = this.id; + if (!id) { + toast.warn("ID tidak valid"); + return null; } - toast.success("Berhasil update data!"); - await persentasekelahiran.findMany.load(); - return result.data; - } catch (error) { - console.error("Update error:", error); - toast.error("Gagal update data persentase kelahiran"); - throw error; - } finally { - this.loading = false; - } - }, -}, + const formData = { + tahun: this.form.tahun, + kematianKasar: this.form.kematianKasar, + kelahiranKasar: this.form.kelahiranKasar, + kematianBayi: this.form.kematianBayi, + }; + const cek = templatePersentase.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/kesehatan/persentasekelahiran/${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 persentasekelahiran.findMany.load(); + return result.data; + } catch (error) { + console.error("Update error:", error); + toast.error("Gagal update data persentase kelahiran"); + throw error; + } finally { + this.loading = false; + } + }, + }, delete: { loading: false, @@ -162,22 +167,29 @@ update: { try { persentasekelahiran.delete.loading = true; - const response = await fetch(`/api/kesehatan/persentasekelahiran/del/${id}`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - }); + const response = await fetch( + `/api/kesehatan/persentasekelahiran/del/${id}`, + { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + } + ); const result = await response.json(); if (response.ok && result?.success) { - toast.success(result.message || "Persentase kelahiran berhasil dihapus"); + toast.success( + result.message || "Persentase kelahiran berhasil dihapus" + ); await persentasekelahiran.findMany.load(); } else { - toast.error(result?.message || "Gagal menghapus persentase kelahiran"); + toast.error( + result?.message || "Gagal menghapus persentase kelahiran" + ); } - } catch (error) { + } catch (error) { console.error("Gagal delete:", error); toast.error("Terjadi kesalahan saat menghapus persentase kelahiran"); } finally { diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/[id]/page.tsx new file mode 100644 index 00000000..fbe60162 --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/[id]/page.tsx @@ -0,0 +1,102 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' + +import colors from '@/con/colors'; +import { Box, Button, Paper, Stack, TextInput, Title } from '@mantine/core'; +import { IconArrowBack } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useEffect } from 'react'; +import { toast } from 'react-toastify'; +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 id = params.id + + useEffect(() => { + if (!id) return; + stateDemografi.update.id = 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) + }; + } + }) + .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; + await stateDemografi.update.submit(); + toast.success('Data berhasil diperbarui'); + router.push('/admin/ekonomi/demografi-pekerjaan'); + } catch (error) { + console.error('Error updating data:', error); + toast.error('Gagal memperbarui data'); + } + }; + + return ( + + + + + + + Edit Demografi Pekerjaan + { + stateDemografi.update.form.pekerjaan = val.currentTarget.value; + }} + /> + { + stateDemografi.update.form.lakiLaki = Number(val.currentTarget.value); + }} + /> + { + stateDemografi.update.form.perempuan = Number(val.currentTarget.value); + }} + /> + + + + + ) +} + +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 5048c1ba..83532936 100644 --- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/create/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/create/page.tsx @@ -1,41 +1,90 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/no-explicit-any */ '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, 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'; +import demografiPekerjaan from '../../../_state/ekonomi/demografi-pekerjaan'; function CreateDemografiPekerjaan() { - const router = useRouter(); + const stateDemografi = useProxy(demografiPekerjaan); + const [chartData, setChartData] = useState([]); + const router = useRouter() + + const resetForm = () => { + stateDemografi.create.form = { + pekerjaan: "", + lakiLaki: 0, + perempuan: 0, + } + } + + const handleSubmit = async () => { + const id = await stateDemografi.create.create(); + if (id) { + const idStr = String(id); + await stateDemografi.findUnique.load(idStr); + if (stateDemografi.findUnique.data) { + setChartData([stateDemografi.findUnique.data]); + } + } + resetForm(); + router.push("/admin/ekonomi/demografi-pekerjaan"); + } return ( - - - - - Create Demografi Pekerjaan - Pekerjaan} - placeholder='Masukkan pekerjaan' - /> - Jumlah Pekerja Laki - Laki} - placeholder='Masukkan jumlah pekerja laki - laki' - /> - Jumlah Pekerja Perempuan} - placeholder='Masukkan jumlah pekerja perempuan' - /> - - - - - - + + + Tambah Demografi Pekerjaan + + { + stateDemografi.create.form.pekerjaan = val.currentTarget.value; + }} + /> + { + stateDemografi.create.form.lakiLaki = Number(val.currentTarget.value); + }} + /> + { + stateDemografi.create.form.perempuan = Number(val.currentTarget.value); + }} + /> + + + + + + + ); } diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/detail/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/detail/page.tsx deleted file mode 100644 index fd52618b..00000000 --- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/detail/page.tsx +++ /dev/null @@ -1,62 +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 DetailDemografiPekerjaan() { - const router = useRouter(); - return ( - - - - - - - Detail Demografi Pekerjaan - - - - - Pekerjaan - Karyawan - - - Jumlah Pekerja Laki - Laki - 200 - - - Jumlah Pekerja Perempuan - 100 - - - - - - - - - - - - - {/* Modal Hapus - setModalHapus(false)} - onConfirm={handleHapus} - text="Apakah anda yakin ingin menghapus potensi ini?" - /> */} - - ); -} - -export default DetailDemografiPekerjaan; - diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/edit/page.tsx deleted file mode 100644 index e992abeb..00000000 --- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/edit/page.tsx +++ /dev/null @@ -1,42 +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 EditDemografiPekerjaan() { - const router = useRouter(); - return ( - - - - - - - - Edit Demografi Pekerjaan - Pekerjaan} - placeholder='Masukkan pekerjaan' - /> - Jumlah Pekerja Laki - Laki} - placeholder='Masukkan jumlah pekerja laki - laki' - /> - Jumlah Pekerja Perempuan} - placeholder='Masukkan jumlah pekerja perempuan' - /> - - - - - - - ); -} - -export default EditDemografiPekerjaan; diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx index f0ff9c12..fb9bb8c7 100644 --- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx @@ -1,26 +1,85 @@ '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 { Box, Button, Paper, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; +import { useMediaQuery, 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'; -import { useRouter } from 'next/navigation'; +import { ModalKonfirmasiHapus } from '../../_com/modalKonfirmasiHapus'; +import demografiPekerjaan from '../../_state/ekonomi/demografi-pekerjaan'; function DemografiPekerjaan() { + const [search, setSearch] = useState(''); return ( } + value={search} + onChange={(e) => setSearch(e.currentTarget.value)} /> - + ); } -function ListDemografiPekerjaan() { +function ListDemografiPekerjaan({ search }: { search: string }) { + type DemografiPekerjaan = { + id: string; + pekerjaan: string; + lakiLaki: number; + perempuan: number; + } + const router = useRouter(); + 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) + + const handleDelete = () => { + if (selectedId) { + stateDemografi.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + + stateDemografi.findMany.load() + } + } + + useShallowEffect(() => { + setMounted(true) + stateDemografi.findMany.load() + }, []) + + 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), + }))); + } + }, [stateDemografi.findMany.data]); + + const filteredData = (stateDemografi.findMany.data || []).filter(item => { + const keyword = search.toLowerCase(); + return ( + item.pekerjaan.toLowerCase().includes(keyword) || + item.lakiLaki.toString().toLowerCase().includes(keyword) || + item.perempuan.toString().toLowerCase().includes(keyword) + ); + }); return ( @@ -34,23 +93,71 @@ function ListDemografiPekerjaan() { Pekerjaan Jumlah Pekerja Laki - Laki Jumlah Pekerja Perempuan - Detail - + Edit + Delete + - - Karyawan - 200 - 100 - - - - + {filteredData.map((item) => ( + + {item.pekerjaan} + {item.lakiLaki} + {item.perempuan} + + + + + + + + ))} - + + + {/* Chart */} + {!mounted && !chartData ? ( + + + Data Kelahiran & Kematian + Belum ada data untuk ditampilkan dalam grafik + + + ) : ( + + + Data Kelahiran & Kematian + {mounted && chartData.length > 0 && ( + + + + + + + + + )} + + + )} + + {/* Modal Konfirmasi Hapus */} + setModalHapus(false)} + onConfirm={handleDelete} + text='Apakah anda yakin ingin menghapus demografi pekerjaan ini?' + /> ); } diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/create.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/create.ts new file mode 100644 index 00000000..69c51e18 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/create.ts @@ -0,0 +1,34 @@ +import prisma from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; + +type FormCreate = Prisma.DataDemografiPekerjaanGetPayload<{ + select: { + pekerjaan: true; + lakiLaki: true; + perempuan: true; + } +}> + +export default async function demografiPekerjaanCreate(context: Context) { + const body = context.body as FormCreate; + + const created = await prisma.dataDemografiPekerjaan.create({ + data: { + pekerjaan: body.pekerjaan, + lakiLaki: body.lakiLaki, + perempuan: body.perempuan, + }, + select: { + id: true, + pekerjaan: true, + lakiLaki: true, + perempuan: true, + } + }); + return { + success: true, + message: "Success create demografi pekerjaan", + data: created, + }; +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/del.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/del.ts new file mode 100644 index 00000000..4f69e9ef --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/del.ts @@ -0,0 +1,36 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function demografiPekerjaanDelete(context: Context) { + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID tidak ditemukan", + } + } + + const existing = await prisma.dataDemografiPekerjaan.findUnique({ + where: { + id: id, + }, + }) + + if (!existing) { + return { + success: false, + message: "Data tidak ditemukan", + } + } + + const deleted = await prisma.dataDemografiPekerjaan.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/demografi-pekerjaan/findMany.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findMany.ts new file mode 100644 index 00000000..009069ed --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findMany.ts @@ -0,0 +1,8 @@ +import prisma from "@/lib/prisma"; + +export default async function demografiPekerjaanFindMany() { + const res = await prisma.dataDemografiPekerjaan.findMany(); + return { + data: res + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findUnique.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findUnique.ts new file mode 100644 index 00000000..104eefef --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/findUnique.ts @@ -0,0 +1,46 @@ +import prisma from "@/lib/prisma"; + +export default async function demografiPekerjaanFindUnique(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.dataDemografiPekerjaan.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/demografi-pekerjaan/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/index.ts new file mode 100644 index 00000000..f917b240 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/index.ts @@ -0,0 +1,39 @@ +import Elysia, { t } from "elysia"; +import demografiPekerjaanFindUnique from "./findUnique"; +import demografiPekerjaanUpdate from "./updt"; +import demografiPekerjaanFindMany from "./findMany"; +import demografiPekerjaanCreate from "./create"; +import demografiPekerjaanDelete from "./del"; + +const DemografiPekerjaan = new Elysia({ + prefix: "/demografipekerjaan", + tags: ["Ekonomi/Demografi Pekerjaan"], +}) +.get("/:id", async (context) => { + const response = await demografiPekerjaanFindUnique(new Request(context.request)) + return response + }) + .get("/find-many", demografiPekerjaanFindMany) + .post("/create", demografiPekerjaanCreate, { + body: t.Object({ + pekerjaan: t.String(), + lakiLaki: t.Number(), + perempuan: t.Number(), + }), + }) + .put("/:id", demografiPekerjaanUpdate, { + params: t.Object({ + id: t.String(), + }), + body: t.Object({ + pekerjaan: t.String(), + lakiLaki: t.Number(), + perempuan: t.Number(), + }), + }) + .delete("/del/:id", demografiPekerjaanDelete, { + params: t.Object({ + id: t.String(), + }), + }) +export default DemografiPekerjaan; \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/updt.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/updt.ts new file mode 100644 index 00000000..049c8aa7 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/demografi-pekerjaan/updt.ts @@ -0,0 +1,47 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function demografiPekerjaanUpdate(context: Context) { + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID tidak ditemukan", + } + } + + const {pekerjaan, lakiLaki, perempuan} = context.body as { + pekerjaan: string; + lakiLaki: number; + perempuan: number; + } + + const existing = await prisma.dataDemografiPekerjaan.findUnique({ + where: { + id: id, + }, + }) + + if (!existing) { + return { + success: false, + message: "Data tidak ditemukan", + } + } + + const updated = await prisma.dataDemografiPekerjaan.update({ + where: { id }, + data: { + pekerjaan, + lakiLaki, + perempuan, + }, + }) + + return { + success: true, + message: "Data berhasil diupdate", + data: updated, + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/index.ts index 24ae0541..d5b1a8cf 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/index.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/index.ts @@ -8,6 +8,7 @@ import GrafikUsiaKerjaYangMenganggur from "./usia-kerja-yang-menganggur"; import GrafikMenganggurBerdasarkanPendidikan from "./usia-kerja-yang-menganggur/pengangguran-berdasrkan-pendidikan"; import JumlahPendudukMiskin from "./jumlah-penduduk-miskin"; import SektorUnggulanDesa from "./sektor-unggulan-desa"; +import DemografiPekerjaan from "./demografi-pekerjaan"; const Ekonomi = new Elysia({ prefix: "/api/ekonomi", @@ -22,5 +23,6 @@ const Ekonomi = new Elysia({ .use(GrafikMenganggurBerdasarkanPendidikan) .use(JumlahPendudukMiskin) .use(SektorUnggulanDesa) +.use(DemografiPekerjaan) export default Ekonomi \ No newline at end of file