From 7439eb76879acca69df3c204a4b0bd69f5499137 Mon Sep 17 00:00:00 2001 From: nico Date: Thu, 17 Jul 2025 17:09:28 +0800 Subject: [PATCH] API & UI Menu Lingkungan, Submenu Penglolaan Sampah --- prisma/schema.prisma | 11 + .../_state/lingkungan/pengelolaan-sampah.ts | 221 ++++++++++++++++++ .../program-kreatif-desa/_lib/selectIcon.tsx | 9 + .../_lib/selectIconEdit.tsx | 8 + .../_lib/layoutTabs.tsx | 63 +++++ .../create/page.tsx | 0 .../detail/page.tsx | 0 .../edit/page.tsx | 0 .../page.tsx | 0 .../pengelolaan-sampah-bank-sampah/layout.tsx | 11 + .../[id]/page.tsx | 115 +++++++++ .../create/page.tsx | 58 +++++ .../page.tsx | 135 +++++++++++ .../create/page.tsx | 46 ---- .../detail/page.tsx | 61 ----- .../edit/page.tsx | 46 ---- .../page.tsx | 55 ----- .../pengelolaan-sampah-bank-sampah/page.tsx | 36 --- src/app/admin/_com/list_PageAdmin.tsx | 2 +- .../api/[[...slugs]]/_lib/lingkungan/index.ts | 11 + .../lingkungan/pengelolaan-sampah/create.ts | 26 +++ .../_lib/lingkungan/pengelolaan-sampah/del.ts | 33 +++ .../lingkungan/pengelolaan-sampah/findMany.ts | 44 ++++ .../pengelolaan-sampah/findUnique.ts | 39 ++++ .../lingkungan/pengelolaan-sampah/index.ts | 37 +++ .../lingkungan/pengelolaan-sampah/updt.ts | 44 ++++ src/app/api/[[...slugs]]/route.ts | 2 + 27 files changed, 868 insertions(+), 245 deletions(-) create mode 100644 src/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah.ts create mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/_lib/layoutTabs.tsx rename src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/{keterangan_bank_sampah_terdekat => keterangan-bank-sampah-terdekat}/create/page.tsx (100%) rename src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/{keterangan_bank_sampah_terdekat => keterangan-bank-sampah-terdekat}/detail/page.tsx (100%) rename src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/{keterangan_bank_sampah_terdekat => keterangan-bank-sampah-terdekat}/edit/page.tsx (100%) rename src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/{keterangan_bank_sampah_terdekat => keterangan-bank-sampah-terdekat}/page.tsx (100%) create mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/layout.tsx create mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/[id]/page.tsx create mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/create/page.tsx create mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/page.tsx delete mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/create/page.tsx delete mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/detail/page.tsx delete mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/edit/page.tsx delete mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/page.tsx delete mode 100644 src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/page.tsx create mode 100644 src/app/api/[[...slugs]]/_lib/lingkungan/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/del.ts create mode 100644 src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findMany.ts create mode 100644 src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findUnique.ts create mode 100644 src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/updt.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8adecc3a..6bcd7c19 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1446,3 +1446,14 @@ model JenisPengaduan { isActive Boolean @default(true) PengaduanMasyarakat PengaduanMasyarakat[] } + +// ========================================= PENGELOLAAN SAMPAH ========================================= // +model PengelolaanSampah { + id String @id @default(cuid()) + name String + icon String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} diff --git a/src/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah.ts b/src/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah.ts new file mode 100644 index 00000000..20a6f041 --- /dev/null +++ b/src/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah.ts @@ -0,0 +1,221 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +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 templateForm = z.object({ + name: z.string().min(1, "Nama minimal 1 karakter"), + icon: z.string().min(1, "Icon minimal 1 karakter"), +}); + +const defaultForm = { + name: "", + icon: "", +}; + +const pengelolaanSampahState = proxy({ + create: { + form: { ...defaultForm }, + loading: false, + async create() { + const cek = templateForm.safeParse(pengelolaanSampahState.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + pengelolaanSampahState.create.loading = true; + const res = await ApiFetch.api.lingkungan.pengelolaansampah["create"].post( + pengelolaanSampahState.create.form + ); + if (res.status === 200) { + pengelolaanSampahState.findMany.load(); + return toast.success("success create"); + } + console.log(res); + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + pengelolaanSampahState.create.loading = false; + } + }, + }, + findMany: { + data: null as any[] | null, + page: 1, + totalPages: 1, + total: 0, + loading: false, + load: async (page = 1, limit = 10) => { + // Change to arrow function + pengelolaanSampahState.findMany.loading = true; // Use the full path to access the property + pengelolaanSampahState.findMany.page = page; + try { + const res = await ApiFetch.api.lingkungan.pengelolaansampah["find-many"].get({ + query: { page, limit }, + }); + + if (res.status === 200 && res.data?.success) { + pengelolaanSampahState.findMany.data = res.data.data || []; + pengelolaanSampahState.findMany.total = res.data.total || 0; + pengelolaanSampahState.findMany.totalPages = res.data.totalPages || 1; + } else { + console.error( + "Failed to load pengelolaan sampah:", + res.data?.message + ); + pengelolaanSampahState.findMany.data = []; + pengelolaanSampahState.findMany.total = 0; + pengelolaanSampahState.findMany.totalPages = 1; + } + } catch (error) { + console.error("Error loading pengelolaan sampah:", error); + pengelolaanSampahState.findMany.data = []; + pengelolaanSampahState.findMany.total = 0; + pengelolaanSampahState.findMany.totalPages = 1; + } finally { + pengelolaanSampahState.findMany.loading = false; + } + }, + }, + update: { + id: "", + form: { ...defaultForm }, + loading: false, + async load(id: string) { + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + try { + const response = await fetch(`/api/lingkungan/pengelolaansampah/${id}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const result = await response.json(); + + if (result?.success) { + const data = result.data; + this.id = data.id; + this.form = { + name: data.name, + icon: data.icon, + }; + return data; + } else { + throw new Error(result?.message || "Gagal mengambil data"); + } + } catch (error) { + console.error("Error loading pengelolaan sampah:", error); + toast.error( + error instanceof Error ? error.message : "Gagal memuat data" + ); + return null; + } + }, + + async submit() { + const id = this.id; + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + const cek = templateForm.safeParse(this.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + this.loading = true; + try { + const response = await fetch(`/api/lingkungan/pengelolaansampah/${id}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(this.form), + }); + const result = await response.json(); + if (!response.ok || !result?.success) { + throw new Error(result?.message || "Gagal update data"); + } + toast.success("Berhasil update data!"); + await pengelolaanSampahState.findMany.load(); + return result.data; + } catch (error) { + console.error("Error update data:", error); + toast.error("Gagal update data pengelolaan sampah"); + } finally { + this.loading = false; + } + }, + }, + findUnique: { + data: null as Prisma.ProgramKreatifGetPayload<{ + omit: { isActive: true }; + }> | null, + async load(id: string) { + try { + const res = await fetch(`/api/lingkungan/pengelolaansampah/${id}`); + if (res.ok) { + const data = await res.json(); + pengelolaanSampahState.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch data", res.status, res.statusText); + pengelolaanSampahState.findUnique.data = null; + } + } catch (error) { + console.error("Error loading pengelolaan sampah:", error); + pengelolaanSampahState.findUnique.data = null; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + if (!id) return toast.warn("ID tidak valid"); + + try { + pengelolaanSampahState.delete.loading = true; + + const response = await fetch(`/api/lingkungan/pengelolaansampah/del/${id}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + }); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success(result.message || "pengelolaan sampah berhasil dihapus"); + await pengelolaanSampahState.findMany.load(); // refresh list + } else { + toast.error(result?.message || "Gagal menghapus pengelolaan sampah"); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus pengelolaan sampah"); + } finally { + pengelolaanSampahState.delete.loading = false; + } + }, + }, +}); + +export default pengelolaanSampahState; diff --git a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIcon.tsx b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIcon.tsx index 0d92dc75..d2fd42c1 100644 --- a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIcon.tsx +++ b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIcon.tsx @@ -4,10 +4,14 @@ import { Box, rem, Select } from '@mantine/core'; import { IconChartLine, + IconClipboardTextFilled, IconLeaf, IconRecycle, + IconScale, IconTent, + IconTrashFilled, IconTrophy, + IconTruckFilled, } from '@tabler/icons-react'; import { useEffect, useState } from 'react'; @@ -17,6 +21,11 @@ const iconMap = { wisata: { label: 'Wisata', icon: IconTent }, ekonomi: { label: 'Ekonomi', icon: IconChartLine }, sampah: { label: 'Sampah', icon: IconRecycle }, + truck: { label: 'Truck', icon: IconTruckFilled }, + scale: { label: 'Scale', icon: IconScale }, + clipboard: { label: 'Clipboard', icon: IconClipboardTextFilled }, + trash: { label: 'Trash', icon: IconTrashFilled }, + }; type IconKey = keyof typeof iconMap; diff --git a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIconEdit.tsx b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIconEdit.tsx index eff26d48..217b50e0 100644 --- a/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIconEdit.tsx +++ b/src/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIconEdit.tsx @@ -3,10 +3,14 @@ import { Box, rem, Select } from '@mantine/core'; import { IconChartLine, + IconClipboardTextFilled, IconLeaf, IconRecycle, + IconScale, IconTent, + IconTrashFilled, IconTrophy, + IconTruckFilled, } from '@tabler/icons-react'; const iconMap = { @@ -15,6 +19,10 @@ const iconMap = { wisata: { label: 'Wisata', icon: IconTent }, ekonomi: { label: 'Ekonomi', icon: IconChartLine }, sampah: { label: 'Sampah', icon: IconRecycle }, + truck: { label: 'Truck', icon: IconTruckFilled }, + scale: { label: 'Scale', icon: IconScale }, + clipboard: { label: 'Clipboard', icon: IconClipboardTextFilled }, + trash: { label: 'Trash', icon: IconTrashFilled }, }; type IconKey = keyof typeof iconMap; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/_lib/layoutTabs.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/_lib/layoutTabs.tsx new file mode 100644 index 00000000..8a8bf30c --- /dev/null +++ b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/_lib/layoutTabs.tsx @@ -0,0 +1,63 @@ +/* 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 LayoutTabsPengelolaanSampahBankSampah({ children }: { children: React.ReactNode }) { + const router = useRouter() + const pathname = usePathname() + const tabs = [ + { + label: "List Pengelolaan Sampah Bank Sampah", + value: "listpengelolaansampahbanksampah", + href: "/admin/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah" + }, + { + label: "Keterangan Bank Sampah Terdekat", + value: "keteranganbanksampahterdekat", + href: "/admin/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat" + }, + + ]; + 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 ( + + Layanan Online Desa + + + {tabs.map((e, i) => ( + {e.label} + ))} + + {tabs.map((e, i) => ( + + {/* Konten dummy, bisa diganti tergantung routing */} + <> + + ))} + + {children} + + ); +} + +export default LayoutTabsPengelolaanSampahBankSampah; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan_bank_sampah_terdekat/create/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/create/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan_bank_sampah_terdekat/create/page.tsx rename to src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/create/page.tsx diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan_bank_sampah_terdekat/detail/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/detail/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan_bank_sampah_terdekat/detail/page.tsx rename to src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/detail/page.tsx diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan_bank_sampah_terdekat/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/edit/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan_bank_sampah_terdekat/edit/page.tsx rename to src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/edit/page.tsx diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan_bank_sampah_terdekat/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/page.tsx similarity index 100% rename from src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan_bank_sampah_terdekat/page.tsx rename to src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/page.tsx diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/layout.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/layout.tsx new file mode 100644 index 00000000..7a103d71 --- /dev/null +++ b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/layout.tsx @@ -0,0 +1,11 @@ +import LayoutTabsPengelolaanSampahBankSampah from './_lib/layoutTabs'; + +function PengelolaanSampahBankSampah({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} + +export default PengelolaanSampahBankSampah; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/[id]/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/[id]/page.tsx new file mode 100644 index 00000000..816fdc03 --- /dev/null +++ b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/[id]/page.tsx @@ -0,0 +1,115 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' +import pengelolaanSampahState from '@/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah'; +import SelectIconProgramEdit from '@/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIconEdit'; +import colors from '@/con/colors'; +import { Box, Button, 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'; + +interface FormProgramKreatif { + name: string; + icon: string; +} + +type IconKey = 'ekowisata' | 'kompetisi' | 'wisata' | 'ekonomi' | 'sampah' | 'truck' | 'scale' | 'clipboard' | 'trash'; + + +function EditProgramKreatifDesa() { + const stateSampah = useProxy(pengelolaanSampahState) + const params = useParams() + const router = useRouter(); + const [formData, setFormData] = useState({ + name: '', + icon: '', + }) + + useEffect(() => { + const loadProgramKreatif = async () => { + const id = params?.id as string; + if (!id) return; + + try { + const data = await stateSampah.update.load(id); + if (data) { + // ⬇️ FIX PENTING: tambahkan ini + stateSampah.update.id = id; + + stateSampah.update.form = { + name: data.name, + icon: data.icon, + }; + + setFormData({ + name: data.name, + icon: data.icon, + }); + } + } catch (error) { + console.error("Error loading pengelolaan sampah:", error); + toast.error("Gagal memuat data pengelolaan sampah"); + } + } + + loadProgramKreatif(); + }, [params?.id]); + + + + const handleSubmit = async () => { + try { + stateSampah.update.form = { + ...stateSampah.update.form, + name: formData.name.trim(), + icon: formData.icon.trim(), + } + await stateSampah.update.submit(); + router.push("/admin/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah"); + } catch (error) { + console.error("Error updating pengelolaan sampah:", error); + toast.error("Gagal memuat data pengelolaan sampah"); + } + } + return ( + + + + + + + + Edit List Pengelolaan Sampah Bank Sampah + Nama List Pengelolaan Sampah Bank Sampah} + placeholder="masukkan nama list pengelolaan sampah bank sampah" + onChange={(val) => { + setFormData({ + ...formData, + name: val.target.value + }) + }} + /> + + Ikon List Pengelolaan Sampah Bank Sampah + { + setFormData((prev) => ({ ...prev, icon: value })); + stateSampah.update.form.icon = value; + }} + /> + + + + + + ); +} + +export default EditProgramKreatifDesa; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/create/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/create/page.tsx new file mode 100644 index 00000000..95acc819 --- /dev/null +++ b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/create/page.tsx @@ -0,0 +1,58 @@ +'use client' +import pengelolaanSampahState from '@/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah'; +import SelectIconProgram from '@/app/admin/(dashboard)/inovasi/program-kreatif-desa/_lib/selectIcon'; +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 { useProxy } from 'valtio/utils'; + + + + +function CreatePengelolaanSampahBankSampah() { + const stateCreate = useProxy(pengelolaanSampahState) + const router = useRouter(); + + const resetForm = () => { + stateCreate.create.form = { + name: "", + icon: "", + } + } + + const handleSubmit = async () => { + await stateCreate.create.create(); + resetForm(); + router.push("/admin/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah") + } + return ( + + + + + + + + Create List Pengelolaan Sampah Bank Sampah + Nama Pengelolaan Sampah Bank Sampah} + placeholder="masukkan nama pengelolaan sampah bank sampah" + onChange={(val) => stateCreate.create.form.name = val.target.value} + /> + + Ikon Pengelolaan Sampah Bank Sampah + stateCreate.create.form.icon = value} /> + + + + + + + + ); +} + +export default CreatePengelolaanSampahBankSampah; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/page.tsx new file mode 100644 index 00000000..2792b45c --- /dev/null +++ b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah/page.tsx @@ -0,0 +1,135 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +'use client' +import colors from '@/con/colors'; +import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { IconChartLine, IconClipboardTextFilled, IconEdit, IconLeaf, IconRecycle, IconScale, IconSearch, IconTent, IconTrashFilled, IconTrophy, IconTruckFilled, IconX } from '@tabler/icons-react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useProxy } from 'valtio/utils'; +import HeaderSearch from '../../../_com/header'; +import JudulList from '../../../_com/judulList'; +import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; +import pengelolaanSampahState from '../../../_state/lingkungan/pengelolaan-sampah'; +import React from 'react'; + + +function PengelolaanSampahBankSampah() { + const [search, setSearch] = useState("") + return ( + + } + value={search} + onChange={(e) => setSearch(e.currentTarget.value)} + /> + + + ); +} + +function ListPengelolaanSampahBankSampah({ search }: { search: string }) { + const stateList = useProxy(pengelolaanSampahState) + const [modalHapus, setModalHapus] = useState(false) + const [selectedId, setSelectedId] = useState(null) + const router = useRouter() + + useShallowEffect(() => { + stateList.findMany.load() + }, []) + + const handleHapus = () => { + if (selectedId) { + stateList.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + } + } + + const filteredData = (stateList.findMany.data || []).filter(item => { + const keyword = search.toLowerCase(); + return ( + item.name.toLowerCase().includes(keyword) + || item.icon.toLowerCase().includes(keyword) + ); + }); + + const iconMap: Record> = { + ekowisata: IconLeaf, + kompetisi: IconTrophy, + wisata: IconTent, + ekonomi: IconChartLine, + sampah: IconRecycle, + truck: IconTruckFilled, + scale: IconScale, + clipboard: IconClipboardTextFilled, + trash: IconTrashFilled, + }; + + if (!stateList.findMany.data) { + return ( + + + + ) + } + + return ( + + + + + + + Nama Pengelolaan Sampah + Icon + Edit + Delete + + + + {filteredData.map((item) => ( + + {item.name} + + {iconMap[item.icon] && ( + + {React.createElement(iconMap[item.icon], { size: 24 })} + + )} + + + + + + + + + ))} + +
+
+ {/* Modal Konfirmasi Hapus */} + setModalHapus(false)} + onConfirm={handleHapus} + text='Apakah anda yakin ingin menghapus pengelolaan sampah bank sampah ini?' + /> +
+ ); +} + +export default PengelolaanSampahBankSampah; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/create/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/create/page.tsx deleted file mode 100644 index 58b82dcc..00000000 --- a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/create/page.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' -import { KeamananEditor } from '@/app/admin/(dashboard)/keamanan/_com/keamananEditor'; -import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; -import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; - - - -function CreateMekanismeBankSampah() { - const router = useRouter(); - return ( - - - - - - - - Create Mekanisme Bank Sampah - - Masukkan Image - - - Judul} - placeholder='Masukkan judul' - /> - - Deskripsi - - - - - - - - - ); -} - -export default CreateMekanismeBankSampah; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/detail/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/detail/page.tsx deleted file mode 100644 index 2621b440..00000000 --- a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/detail/page.tsx +++ /dev/null @@ -1,61 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Button, Flex, Paper, Stack, Text } from '@mantine/core'; -import { IconArrowBack, IconEdit, IconImageInPicture, IconX } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; -// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; - -function DetailPengelolaanSampahBankSampah() { - const router = useRouter(); - return ( - - - - - - - Detail Mekanisme Bank Sampah - - - - - Judul - Test Judul - - - Gambar - - - - Deskripsi - Test Deskripsi - - - - - - - - - - - - - {/* Modal Hapus - setModalHapus(false)} - onConfirm={handleHapus} - text="Apakah anda yakin ingin menghapus potensi ini?" - /> */} - - ); -} - -export default DetailPengelolaanSampahBankSampah; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/edit/page.tsx deleted file mode 100644 index 70086bdb..00000000 --- a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/edit/page.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' -import { KeamananEditor } from '@/app/admin/(dashboard)/keamanan/_com/keamananEditor'; -import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; -import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; - - - -function EditMekanismeBankSampah() { - const router = useRouter(); - return ( - - - - - - - - Edit Mekanisme Bank Sampah - - Masukkan Image - - - Judul} - placeholder='Masukkan judul' - /> - - Deskripsi - - - - - - - - - ); -} - -export default EditMekanismeBankSampah; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/page.tsx deleted file mode 100644 index 632e60ca..00000000 --- a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/list_pengelolaan_sampah_bank_sampah/page.tsx +++ /dev/null @@ -1,55 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Button, Image, Paper, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; -import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; -import JudulListTab from '../../../_com/judulListTab'; - -function ListPengelolaanSampahBankSampah() { - const router = useRouter(); - return ( - - - - } - /> - List Mekanisme Bank Sampah - - - - - Judul - Gambar - Detail - - - - - - - Judul - - - - - - - - - - -
-
-
-
-
- ) -} - -export default ListPengelolaanSampahBankSampah; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/page.tsx deleted file mode 100644 index d7ad5a36..00000000 --- a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/page.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Box, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core'; - -import colors from '@/con/colors'; -import ListPengelolaanSampahBankSampah from './list_pengelolaan_sampah_bank_sampah/page'; -import KeteranganBankSampahTerdekat from './keterangan_bank_sampah_terdekat/page'; - - -function PengelolaanSampahBankSampah() { - return ( - - - Pengelolaan Sampah Bank Sampah - - - - List Pengelolaan Sampah Bank Sampah - - - Keterangan Bank Sampah Terdekat - - - - - - - - - - - - - - ) -} - -export default PengelolaanSampahBankSampah; diff --git a/src/app/admin/_com/list_PageAdmin.tsx b/src/app/admin/_com/list_PageAdmin.tsx index 3004b84d..d37b20de 100644 --- a/src/app/admin/_com/list_PageAdmin.tsx +++ b/src/app/admin/_com/list_PageAdmin.tsx @@ -308,7 +308,7 @@ export const navBar = [ { id: "Lingkungan_1", name: "Pengelolaan Sampah (Bank Sampah)", - path: "/admin/lingkungan/pengelolaan-sampah-bank-sampah" + path: "/admin/lingkungan/pengelolaan-sampah-bank-sampah/list-pengelolaan-sampah-bank-sampah" }, { id: "Lingkungan_2", diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/index.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/index.ts new file mode 100644 index 00000000..be2fca30 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/index.ts @@ -0,0 +1,11 @@ +import Elysia from "elysia"; +import PengelolaanSampah from "./pengelolaan-sampah"; + +const Lingkungan = new Elysia({ + prefix: "/api/lingkungan", + tags: ["Lingkungan"], +}) + +.use(PengelolaanSampah) + +export default Lingkungan; diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/create.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/create.ts new file mode 100644 index 00000000..b3691ef3 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/create.ts @@ -0,0 +1,26 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +type FormCreatePengelolaanSampah = { + name: string; + icon: string; +} + +export default async function pengelolaanSampahCreate(context: Context){ + const body = context.body as FormCreatePengelolaanSampah; + + await prisma.pengelolaanSampah.create({ + data: { + name: body.name, + icon: body.icon, + } + }) + + return { + success: true, + message: "Success create program kreatif", + data: { + ...body, + } + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/del.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/del.ts new file mode 100644 index 00000000..2c5f1810 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/del.ts @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function pengelolaanSampahDelete(context: Context) { + const { id } = context.params as { id: string }; + + if (!id) { + return { + success: false, + message: "ID pengelolaan sampah tidak ditemukan", + }; + } + + try { + const deleted = await prisma.pengelolaanSampah.delete({ + where: { id }, + }); + + return { + success: true, + message: "Pengelolaan sampah berhasil dihapus", + data: deleted, + }; + } catch (error: any) { + console.error("Error delete pengelolaan sampah:", error); + return { + success: false, + message: "Terjadi kesalahan saat menghapus pengelolaan sampah", + error: error.message, + }; + } +} diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findMany.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findMany.ts new file mode 100644 index 00000000..2e575465 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findMany.ts @@ -0,0 +1,44 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +// Di findMany.ts +export default async function pengelolaanSampahFindMany(context: Context) { + const page = Number(context.query.page) || 1; + const limit = Number(context.query.limit) || 10; + const skip = (page - 1) * limit; + + try { + const [data, total] = await Promise.all([ + prisma.pengelolaanSampah.findMany({ + where: { isActive: true }, + skip, + take: limit, + orderBy: { createdAt: 'desc' }, + }), + prisma.pengelolaanSampah.count({ + where: { isActive: true } + }) + ]); + + const totalPages = Math.ceil(total / limit); + + return { + success: true, + message: "Success fetch pengelolaan sampah with pagination", + data, + page, + totalPages, + total, + }; + } catch (e) { + console.error("Find many paginated error:", e); + return { + success: false, + message: "Failed fetch pengelolaan sampah with pagination", + data: [], + page: 1, + totalPages: 1, + total: 0, + }; + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findUnique.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findUnique.ts new file mode 100644 index 00000000..62fca23d --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findUnique.ts @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function pengelolaanSampahFindUnique(context: Context) { + const { id } = context.params as { id: string }; + + if (!id) { + return { + success: false, + message: "ID pengelolaan sampah diperlukan", + }; + } + + try { + const pengelolaanSampah = await prisma.pengelolaanSampah.findUnique({ + where: { id }, + }); + + if (!pengelolaanSampah) { + return { + success: false, + message: "Pengelolaan sampah tidak ditemukan", + }; + } + + return { + success: true, + data: pengelolaanSampah, + }; + } catch (error: any) { + console.error("Error findUnique pengelolaan sampah:", error); + return { + success: false, + message: "Gagal mengambil data pengelolaan sampah", + error: error.message, + }; + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/index.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/index.ts new file mode 100644 index 00000000..ba1bd47e --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/index.ts @@ -0,0 +1,37 @@ +import Elysia, { t } from "elysia"; +import pengelolaanSampahCreate from "./create"; +import pengelolaanSampahDelete from "./del"; +import pengelolaanSampahFindMany from "./findMany"; +import pengelolaanSampahFindUnique from "./findUnique"; +import pengelolaanSampahUpdate from "./updt"; + +const PengelolaanSampah = new Elysia({ + prefix: "/pengelolaansampah", + tags: ["Lingkungan/Pengelolaan Sampah"], +}) + .get("/find-many", pengelolaanSampahFindMany) + .get("/:id", async (context) => { + const response = await pengelolaanSampahFindUnique(context); + return response; + }) + .post("/create", pengelolaanSampahCreate, { + body: t.Object({ + name: t.String(), + icon: t.String(), + }), + }) + .put( + "/:id", + async (context) => { + const response = await pengelolaanSampahUpdate(context); + return response; + }, + { + body: t.Object({ + name: t.String(), + icon: t.String(), + }), + } + ) + .delete("/del/:id", pengelolaanSampahDelete); +export default PengelolaanSampah; diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/updt.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/updt.ts new file mode 100644 index 00000000..a5d66fbc --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/updt.ts @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +type FormUpdatePengelolaanSampah = { + id: string; + name?: string; + icon?: string; +}; +export default async function pengelolaanSampahUpdate(context: Context) { + const body = context.body as FormUpdatePengelolaanSampah; + const id = context.params?.id; // ambil dari URL param + + if (!id) { + return { + success: false, + message: "ID pengelolaan sampah wajib diisi", + }; + } + + try { + const updated = await prisma.pengelolaanSampah.update({ + where: { id }, + data: { + name: body.name, + icon: body.icon, + }, + }); + + return { + success: true, + message: "Pengelolaan sampah berhasil diupdate", + data: updated, + }; + } catch (error: any) { + console.error("Error update pengelolaan sampah:", error); + return { + success: false, + message: "Gagal mengupdate pengelolaan sampah", + error: error.message, + }; + } +} + diff --git a/src/app/api/[[...slugs]]/route.ts b/src/app/api/[[...slugs]]/route.ts index a8555757..ff3726e3 100644 --- a/src/app/api/[[...slugs]]/route.ts +++ b/src/app/api/[[...slugs]]/route.ts @@ -20,6 +20,7 @@ import FileStorage from "./_lib/fileStorage"; import Keamanan from "./_lib/keamanan"; import Ekonomi from "./_lib/ekonomi"; import Inovasi from "./_lib/inovasi"; +import Lingkungan from "./_lib/lingkungan"; const ROOT = process.cwd(); @@ -83,6 +84,7 @@ const ApiServer = new Elysia() .use(FileStorage) .use(Ekonomi) .use(Inovasi) + .use(Lingkungan) .onError(({ code }) => { if (code === "NOT_FOUND") { return {