diff --git a/bun.lockb b/bun.lockb index 6da03f4d..a4438762 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index a737af3f..f347056c 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@tiptap/react": "^2.11.7", "@tiptap/starter-kit": "^2.11.7", "@types/bun": "^1.2.2", + "@types/leaflet": "^1.9.20", "@types/lodash": "^4.17.16", "add": "^2.0.6", "animate.css": "^4.1.1", @@ -53,6 +54,7 @@ "framer-motion": "^12.23.5", "get-port": "^7.1.0", "jotai": "^2.12.3", + "leaflet": "^1.9.4", "list": "^2.0.19", "lodash": "^4.17.21", "motion": "^12.4.1", @@ -64,6 +66,7 @@ "prisma": "^6.3.1", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-leaflet": "^5.0.0", "react-simple-toasts": "^6.1.0", "react-toastify": "^11.0.5", "readdirp": "^4.1.1", diff --git a/prisma/migrations/20250718031959_nico_18_jul_25/migration.sql b/prisma/migrations/20250718031959_nico_18_jul_25/migration.sql new file mode 100644 index 00000000..f1569287 --- /dev/null +++ b/prisma/migrations/20250718031959_nico_18_jul_25/migration.sql @@ -0,0 +1,67 @@ +-- CreateTable +CREATE TABLE "PengaduanMasyarakat" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "email" TEXT NOT NULL, + "nomorTelepon" TEXT NOT NULL, + "nik" TEXT NOT NULL, + "judulPengaduan" TEXT NOT NULL, + "lokasiKejadian" TEXT NOT NULL, + "imageId" TEXT NOT NULL, + "deskripsiPengaduan" TEXT NOT NULL, + "jenisPengaduanId" 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 "PengaduanMasyarakat_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "JenisPengaduan" ( + "id" TEXT NOT NULL, + "nama" 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 "JenisPengaduan_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PengelolaanSampah" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "icon" 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 "PengelolaanSampah_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "KeteranganBankSampahTerdekat" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "alamat" TEXT NOT NULL, + "namaTempatMaps" TEXT NOT NULL, + "linkPetunjukArah" TEXT NOT NULL, + "lat" DOUBLE PRECISION NOT NULL, + "lng" DOUBLE PRECISION 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 "KeteranganBankSampahTerdekat_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "PengaduanMasyarakat" ADD CONSTRAINT "PengaduanMasyarakat_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PengaduanMasyarakat" ADD CONSTRAINT "PengaduanMasyarakat_jenisPengaduanId_fkey" FOREIGN KEY ("jenisPengaduanId") REFERENCES "JenisPengaduan"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6bcd7c19..d0152d76 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1457,3 +1457,18 @@ model PengelolaanSampah { deletedAt DateTime @default(now()) isActive Boolean @default(true) } + +model KeteranganBankSampahTerdekat { + id String @id @default(cuid()) + name String + alamat String + namaTempatMaps String + linkPetunjukArah String + lat Float + lng Float + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + diff --git a/src/app/admin/(dashboard)/_com/leafletMapCreate.tsx b/src/app/admin/(dashboard)/_com/leafletMapCreate.tsx new file mode 100644 index 00000000..4b4282ab --- /dev/null +++ b/src/app/admin/(dashboard)/_com/leafletMapCreate.tsx @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +'use client'; + +import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet'; +import { useEffect, useState } from 'react'; +import 'leaflet/dist/leaflet.css'; +import L, { LeafletMouseEvent } from 'leaflet'; + +type Props = { + defaultCenter: { lat: number; lng: number }; + onSelect?: (pos: { lat: number; lng: number }) => void; + readOnly?: boolean; +}; + +export default function LeafletMap({ defaultCenter, onSelect, readOnly = false }: Props) { + const [markerPos, setMarkerPos] = useState(defaultCenter); + + useEffect(() => { + // Aman di sini, karena ini hanya jalan di client + delete (L.Icon.Default.prototype as any)._getIconUrl; + L.Icon.Default.mergeOptions({ + iconRetinaUrl: + 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png', + iconUrl: + 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png', + shadowUrl: + 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png', + }); + }, []); + + function LocationMarker() { + useMapEvents({ + click(e: LeafletMouseEvent) { + if (readOnly) return; + + const { lat, lng } = e.latlng; + setMarkerPos({ lat, lng }); + onSelect?.({ lat, lng }); + }, + }); + + return ; + } + + return ( + + + + + ); +} diff --git a/src/app/admin/(dashboard)/_com/leafletMapEdit.tsx b/src/app/admin/(dashboard)/_com/leafletMapEdit.tsx new file mode 100644 index 00000000..bc5580bd --- /dev/null +++ b/src/app/admin/(dashboard)/_com/leafletMapEdit.tsx @@ -0,0 +1,57 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +'use client'; + +import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet'; +import { useState, useEffect } from 'react'; +import 'leaflet/dist/leaflet.css'; +import L, { LeafletMouseEvent } from 'leaflet'; + +delete (L.Icon.Default.prototype as any)._getIconUrl; +L.Icon.Default.mergeOptions({ + iconRetinaUrl: + 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png', + iconUrl: + 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png', + shadowUrl: + 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png', +}); + +type Props = { + initialPosition: { lat: number; lng: number }; + onChange: (pos: { lat: number; lng: number }) => void; +}; + +export default function LeafletMapEdit({ initialPosition, onChange }: Props) { + const [markerPos, setMarkerPos] = useState(initialPosition); + + useEffect(() => { + setMarkerPos(initialPosition); + }, [initialPosition]); + + function LocationMarker() { + useMapEvents({ + click(e: LeafletMouseEvent) { + const { lat, lng } = e.latlng; + setMarkerPos({ lat, lng }); + onChange({ lat, lng }); + }, + }); + + return ; + } + + return ( + + + + + ); +} diff --git a/src/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah.ts b/src/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah.ts index 20a6f041..78d9d5c6 100644 --- a/src/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah.ts +++ b/src/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah.ts @@ -15,12 +15,12 @@ const defaultForm = { icon: "", }; -const pengelolaanSampahState = proxy({ +const pengelolaanSampah = proxy({ create: { form: { ...defaultForm }, loading: false, async create() { - const cek = templateForm.safeParse(pengelolaanSampahState.create.form); + const cek = templateForm.safeParse(pengelolaanSampah.create.form); if (!cek.success) { const err = `[${cek.error.issues .map((v) => `${v.path.join(".")}`) @@ -29,12 +29,12 @@ const pengelolaanSampahState = proxy({ } try { - pengelolaanSampahState.create.loading = true; - const res = await ApiFetch.api.lingkungan.pengelolaansampah["create"].post( - pengelolaanSampahState.create.form - ); + pengelolaanSampah.create.loading = true; + const res = await ApiFetch.api.lingkungan.pengelolaansampah[ + "create" + ].post(pengelolaanSampah.create.form); if (res.status === 200) { - pengelolaanSampahState.findMany.load(); + pengelolaanSampah.findMany.load(); return toast.success("success create"); } console.log(res); @@ -42,7 +42,7 @@ const pengelolaanSampahState = proxy({ } catch (error) { console.log((error as Error).message); } finally { - pengelolaanSampahState.create.loading = false; + pengelolaanSampah.create.loading = false; } }, }, @@ -54,33 +54,35 @@ const pengelolaanSampahState = proxy({ 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; + pengelolaanSampah.findMany.loading = true; // Use the full path to access the property + pengelolaanSampah.findMany.page = page; try { - const res = await ApiFetch.api.lingkungan.pengelolaansampah["find-many"].get({ + 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; + pengelolaanSampah.findMany.data = res.data.data || []; + pengelolaanSampah.findMany.total = res.data.total || 0; + pengelolaanSampah.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; + pengelolaanSampah.findMany.data = []; + pengelolaanSampah.findMany.total = 0; + pengelolaanSampah.findMany.totalPages = 1; } } catch (error) { console.error("Error loading pengelolaan sampah:", error); - pengelolaanSampahState.findMany.data = []; - pengelolaanSampahState.findMany.total = 0; - pengelolaanSampahState.findMany.totalPages = 1; + pengelolaanSampah.findMany.data = []; + pengelolaanSampah.findMany.total = 0; + pengelolaanSampah.findMany.totalPages = 1; } finally { - pengelolaanSampahState.findMany.loading = false; + pengelolaanSampah.findMany.loading = false; } }, }, @@ -95,12 +97,15 @@ const pengelolaanSampahState = proxy({ } try { - const response = await fetch(`/api/lingkungan/pengelolaansampah/${id}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); + 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}`); @@ -143,19 +148,22 @@ const pengelolaanSampahState = proxy({ } 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 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(); + await pengelolaanSampah.findMany.load(); return result.data; } catch (error) { console.error("Error update data:", error); @@ -174,14 +182,14 @@ const pengelolaanSampahState = proxy({ const res = await fetch(`/api/lingkungan/pengelolaansampah/${id}`); if (res.ok) { const data = await res.json(); - pengelolaanSampahState.findUnique.data = data.data ?? null; + pengelolaanSampah.findUnique.data = data.data ?? null; } else { console.error("Failed to fetch data", res.status, res.statusText); - pengelolaanSampahState.findUnique.data = null; + pengelolaanSampah.findUnique.data = null; } } catch (error) { console.error("Error loading pengelolaan sampah:", error); - pengelolaanSampahState.findUnique.data = null; + pengelolaanSampah.findUnique.data = null; } }, }, @@ -191,20 +199,25 @@ const pengelolaanSampahState = proxy({ if (!id) return toast.warn("ID tidak valid"); try { - pengelolaanSampahState.delete.loading = true; + pengelolaanSampah.delete.loading = true; - const response = await fetch(`/api/lingkungan/pengelolaansampah/del/${id}`, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - }); + 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 + toast.success( + result.message || "pengelolaan sampah berhasil dihapus" + ); + await pengelolaanSampah.findMany.load(); // refresh list } else { toast.error(result?.message || "Gagal menghapus pengelolaan sampah"); } @@ -212,10 +225,236 @@ const pengelolaanSampahState = proxy({ console.error("Gagal delete:", error); toast.error("Terjadi kesalahan saat menghapus pengelolaan sampah"); } finally { - pengelolaanSampahState.delete.loading = false; + pengelolaanSampah.delete.loading = false; } }, }, }); +const templateKeteranganSampahForm = z.object({ + name: z.string().min(1, "Nama minimal 1 karakter"), + alamat: z.string().min(1, "Alamat minimal 1 karakter"), + namaTempatMaps: z.string().min(1, "Nama Tempat Maps minimal 1 karakter"), + lat: z.number(), + lng: z.number(), +}); + +const defaultKeteranganSampahForm = { + name: "", + alamat: "", + namaTempatMaps: "", + lat: 0, + lng: 0, +}; + + +const keteranganSampah = proxy({ + create: { + form: { ...defaultKeteranganSampahForm }, + loading: false, + async create() { + const cek = templateKeteranganSampahForm.safeParse( + keteranganSampah.create.form + ); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + keteranganSampah.create.loading = true; + const res = + await ApiFetch.api.lingkungan.pengelolaansampah.keteranganbankterdekat[ + "create" + ].post(keteranganSampah.create.form); + if (res.status === 200) { + keteranganSampah.findMany.load(); + return toast.success("Data berhasil ditambahkan"); + } + return toast.error("Gagal menambahkan data"); + } catch (error) { + console.log(error); + toast.error("Gagal menambahkan data"); + } finally { + keteranganSampah.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.KeteranganBankSampahTerdekatGetPayload<{ + omit: { isActive: true }; + }>[] + | null, + async load() { + const res = await ApiFetch.api.lingkungan.pengelolaansampah.keteranganbankterdekat[ + "find-many" + ].get(); + if (res.status === 200) { + keteranganSampah.findMany.data = res.data?.data ?? []; + } + }, + }, + findUnique: { + data: null as Prisma.KeteranganBankSampahTerdekatGetPayload<{ + omit: { isActive: true }; + }> | null, + async load(id: string) { + try { + const res = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${id}`); + if (res.ok) { + const data = await res.json(); + keteranganSampah.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch data", res.status, res.statusText); + keteranganSampah.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching data:", error); + keteranganSampah.findUnique.data = null; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + if (!id) return toast.warn("ID tidak valid"); + + try { + keteranganSampah.delete.loading = true; + + const response = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/del/${id}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + }); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success(result.message || "Keterangan sampah berhasil dihapus"); + await keteranganSampah.findMany.load(); // refresh list + } else { + toast.error(result?.message || "Gagal menghapus keterangan sampah"); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus keterangan sampah"); + } finally { + keteranganSampah.delete.loading = false; + } + }, + }, + edit: { + id: "", + form: { ...defaultKeteranganSampahForm }, + loading: false, + + async load(id: string) { + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + try { + const response = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${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, + alamat: data.alamat, + namaTempatMaps: data.namaTempatMaps, + lat: data.lat, + lng: data.lng, + }; + return data; + } else { + throw new Error(result?.message || "Gagal memuat data"); + } + } catch (error) { + console.error("Error loading keterangan sampah:", error); + toast.error( + error instanceof Error ? error.message : "Gagal memuat data" + ); + return null; + } + }, + + async update() { + const cek = templateKeteranganSampahForm.safeParse(keteranganSampah.edit.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + keteranganSampah.edit.loading = true; + const response = await fetch( + `/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${this.id}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: this.form.name, + alamat: this.form.alamat, + namaTempatMaps: this.form.namaTempatMaps, + lat: this.form.lat, + lng: this.form.lng, + }), + } + ); + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new Error( + errorData.message || `HTTP error! status: ${response.status}` + ); + } + const result = await response.json(); + if (result.success) { + toast.success("Berhasil update keterangan sampah"); + await keteranganSampah.findMany.load(); // refresh list + return true; + } else { + throw new Error(result.message || "Gagal mengupdate keterangan sampah"); + } + } catch (error) { + console.error("Error updating keterangan sampah:", error); + toast.error( + error instanceof Error + ? error.message + : "Gagal mengupdate keterangan sampah" + ); + return false; + } finally { + keteranganSampah.edit.loading = false; + } + }, + reset() { + keteranganSampah.edit.id = ""; + keteranganSampah.edit.form = { ...defaultKeteranganSampahForm }; + }, + }, +}); + +const pengelolaanSampahState = proxy({ + pengelolaanSampah, + keteranganSampah, +}); + export default pengelolaanSampahState; diff --git a/src/app/admin/(dashboard)/inovasi/layanan-online-desa/_lib/layoutTabs.tsx b/src/app/admin/(dashboard)/inovasi/layanan-online-desa/_lib/layoutTabs.tsx index 11ee3621..dfee28d2 100644 --- a/src/app/admin/(dashboard)/inovasi/layanan-online-desa/_lib/layoutTabs.tsx +++ b/src/app/admin/(dashboard)/inovasi/layanan-online-desa/_lib/layoutTabs.tsx @@ -28,13 +28,7 @@ function LayoutTabsLayananOnlineDesa({ children }: { children: React.ReactNode } label: "Jenis Pengaduan", value: "jenispengaduan", href: "/admin/inovasi/layanan-online-desa/jenis-pengaduan" - }, - { - label: "Informasi Desa", - value: "informasidesa", - href: "/admin/inovasi/layanan-online-desa/informasi-desa" } - ]; const curentTab = tabs.find(tab => tab.href === pathname) const [activeTab, setActiveTab] = useState(curentTab?.value || tabs[0].value); diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/[id]/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/[id]/edit/page.tsx new file mode 100644 index 00000000..004fe1ea --- /dev/null +++ b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/[id]/edit/page.tsx @@ -0,0 +1,141 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' +import pengelolaanSampahState from '@/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah'; +import colors from '@/con/colors'; +import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { IconArrowBack } from '@tabler/icons-react'; +import dynamic from 'next/dynamic'; +import { useParams, useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; + +const LeafletMapEdit = dynamic(() => import('@/app/admin/(dashboard)/_com/leafletMapEdit'), { ssr: false }); + +function EditKeteranganBankSampahTerdekat() { + const keteranganState = useProxy(pengelolaanSampahState.keteranganSampah) + const router = useRouter(); + const params = useParams() + const [markerPosition, setMarkerPosition] = useState<{ lat: number; lng: number } | null>(null); + + const [formData, setFormData] = useState({ + name: '', + alamat: '', + namaTempatMaps: '', + lat: 0, + lng: 0, + }) + + useEffect(() => { + const loadKeteranganBankSampahTerdekat = async () => { + const id = params?.id as string; + if (!id) return; + + try { + const data = await keteranganState.edit.load(id); + if (data) { + keteranganState.edit.id = id; + keteranganState.edit.form = { + name: data.name, + alamat: data.alamat, + namaTempatMaps: data.namaTempatMaps, + lat: data.lat, + lng: data.lng, + }; + + setFormData({ + name: data.name, + alamat: data.alamat, + namaTempatMaps: data.namaTempatMaps, + lat: data.lat, + lng: data.lng, + }); + + setMarkerPosition({ lat: data.lat, lng: data.lng }); + } + } catch (error) { + console.error("Error loading pengelolaan sampah:", error); + toast.error("Gagal memuat data pengelolaan sampah"); + } + } + + loadKeteranganBankSampahTerdekat(); + }, [params?.id]); + + const handleSubmit = async () => { + try { + keteranganState.edit.form = { + ...keteranganState.edit.form, + name: formData.name.trim(), + alamat: formData.alamat.trim(), + namaTempatMaps: formData.namaTempatMaps.trim(), + lat: formData.lat, + lng: formData.lng, + } + await keteranganState.edit.update(); + keteranganState.findUnique.data = null; + router.push("/admin/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat"); + } catch (error) { + console.error("Error updating pengelolaan sampah:", error); + toast.error("Gagal memuat data pengelolaan sampah"); + } + } + return ( + + + + + + + + Edit Keterangan Bank Sampah Terdekat + setFormData({ ...formData, name: val.target.value })} + label={Nama Bank Sampah Terdekat} + placeholder='Masukkan nama Bank Sampah Terdekat' + /> + + setFormData({ ...formData, alamat: val.target.value })} + label={Alamat} + placeholder='Masukkan alamat Bank Sampah' + /> + + setFormData({ ...formData, namaTempatMaps: val.target.value })} + label={Nama Tempat Maps} + placeholder='Masukkan nama tempat maps Bank Sampah' + /> + + + Pilih Lokasi di Peta + + { + setMarkerPosition(pos); + setFormData((prev) => ({ + ...prev, + lat: pos.lat, + lng: pos.lng, + })); + }} + /> + + + + + + + + + ); +} + +export default EditKeteranganBankSampahTerdekat; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/[id]/page.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/[id]/page.tsx new file mode 100644 index 00000000..0daa10e0 --- /dev/null +++ b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/[id]/page.tsx @@ -0,0 +1,148 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' +import { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus'; +import pengelolaanSampahState from '@/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah'; +import colors from '@/con/colors'; +import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core'; +import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { useProxy } from 'valtio/utils'; + +import dynamic from 'next/dynamic' + +const LeafletMap = dynamic(() => import('@/app/admin/(dashboard)/_com/leafletMapCreate'), { + ssr: false +}) + + +function DetailKeteranganBankSampahTerdekat() { + const router = useRouter(); + const keteranganState = useProxy(pengelolaanSampahState.keteranganSampah) + const [selectedId, setSelectedId] = useState(null) + const [modalHapus, setModalHapus] = useState(false) + const params = useParams() + + useEffect(() => { + keteranganState.findUnique.load(params?.id as string) + }, []) + + const handleHapus = () => { + if (selectedId) { + keteranganState.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + router.push("/admin/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat") + } + } + + if (!keteranganState.findUnique.data) { + return ( + + + + ) + } + return ( + + + + + + + + Detail Keterangan Bank Sampah Terdekat + + + + + Nama Bank Sampah Terdekat + {keteranganState.findUnique.data?.name} + + + + Alamat + {keteranganState.findUnique.data?.alamat} + + + + Nama Tempat Maps + {keteranganState.findUnique.data?.namaTempatMaps} + + + + Peta Lokasi + {keteranganState.findUnique.data?.lat && keteranganState.findUnique.data?.lng ? ( + + + + ) : ( + Koordinat belum tersedia + )} + + + + + Link Petunjuk Arah + {keteranganState.findUnique.data?.lat && keteranganState.findUnique.data?.lng ? ( + + Buka Petunjuk Arah di Google Maps + + ) : ( + Koordinat belum tersedia + )} + + + + + + + + + + + + + + setModalHapus(false)} + onConfirm={handleHapus} + text="Apakah anda yakin ingin menghapus keterangan bank sampah terdekat ini?" + /> + + + ); +} + +export default DetailKeteranganBankSampahTerdekat; 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 index 84db20f6..7405dcad 100644 --- 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 @@ -1,14 +1,42 @@ 'use client' -import { KeamananEditor } from '@/app/admin/(dashboard)/keamanan/_com/keamananEditor'; + +import pengelolaanSampahState from '@/app/admin/(dashboard)/_state/lingkungan/pengelolaan-sampah'; 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 { IconArrowBack } from '@tabler/icons-react'; +import dynamic from 'next/dynamic'; import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useProxy } from 'valtio/utils'; - +const LeafletMap = dynamic(() => import('@/app/admin/(dashboard)/_com/leafletMapCreate'), { ssr: false }); function CreateKeteranganBankSampahTerdekat() { + const keteranganState = useProxy(pengelolaanSampahState.keteranganSampah) const router = useRouter(); + + const [markerPosition, setMarkerPosition] = useState<{ lat: number; lng: number } | null>(null); + + const resetForm = () => { + keteranganState.create.form = { + name: "", + alamat: "", + namaTempatMaps: "", + lat: 0, + lng: 0, + } + setMarkerPosition(null) + } + const handleSubmit = async () => { + if (markerPosition) { + keteranganState.create.form.lat = markerPosition.lat + keteranganState.create.form.lng = markerPosition.lng + } + await keteranganState.create.create() + resetForm() + router.push("/admin/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat") + } + return ( @@ -20,22 +48,38 @@ function CreateKeteranganBankSampahTerdekat() { Create Keterangan Bank Sampah Terdekat - - Masukkan Image - - Nama Bank Sampah Terdekat} - placeholder='Masukkan nama bank sampah terdekat' + value={keteranganState.create.form.name} + onChange={(val) => keteranganState.create.form.name = val.target.value} + label={Nama Bank Sampah Terdekat} + placeholder='Masukkan nama Bank Sampah Terdekat' /> + + keteranganState.create.form.alamat = val.target.value} + label={Alamat} + placeholder='Masukkan alamat Bank Sampah' + /> + + keteranganState.create.form.namaTempatMaps = val.target.value} + label={Nama Tempat Maps} + placeholder='Masukkan nama tempat maps Bank Sampah' + /> + - Deskripsi Bank Sampah Terdekat - + Pilih Lokasi di Peta + + setMarkerPosition(pos)} + defaultCenter={{ lat: -8.65, lng: 115.2 }} + /> + - + @@ -44,3 +88,4 @@ function CreateKeteranganBankSampahTerdekat() { } export default CreateKeteranganBankSampahTerdekat; + 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 deleted file mode 100644 index 9d90797e..00000000 --- a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/detail/page.tsx +++ /dev/null @@ -1,62 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Flex, Text, Image } from '@mantine/core'; -import { IconArrowBack, IconX, IconEdit } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; -import React from 'react'; -// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; - -function DetailKeteranganBankSampahTerdekat() { - const router = useRouter(); - return ( - - - - - - - Detail Keterangan Bank Sampah Terdekat - - - - - Nama Bank Sampah Terdekat - Test Judul - - - Gambar - gambar - - - Deskripsi - Test Deskripsi - - - - - - - - - - - - - {/* Modal Hapus - setModalHapus(false)} - onConfirm={handleHapus} - text="Apakah anda yakin ingin menghapus potensi ini?" - /> */} - - ); -} - -export default DetailKeteranganBankSampahTerdekat; 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 deleted file mode 100644 index 3ef09d42..00000000 --- a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/keterangan-bank-sampah-terdekat/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 EditKeteranganBankSampahTerdekat() { - const router = useRouter(); - return ( - - - - - - - - Edit Keterangan Bank Sampah Terdekat - - Masukkan Image - - - Nama Bank Sampah Terdekat} - placeholder='Masukkan nama bank sampah terdekat' - /> - - Deskripsi Bank Sampah Terdekat - - - - - - - - - ); -} - -export default EditKeteranganBankSampahTerdekat; 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 index 60f9150e..5928838d 100644 --- 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 @@ -1,55 +1,90 @@ +/* eslint-disable react-hooks/exhaustive-deps */ '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 { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core'; +import { IconDeviceImac, IconSearch } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; -import JudulListTab from '../../../_com/judulListTab'; +import { useProxy } from 'valtio/utils'; + +import { useEffect, useState } from 'react'; +import HeaderSearch from '../../../_com/header'; +import JudulList from '../../../_com/judulList'; +import pengelolaanSampahState from '../../../_state/lingkungan/pengelolaan-sampah'; function KeteranganBankSampahTerdekat() { + const [search, setSearch] = useState(""); + return ( + + } + value={search} + onChange={(e) => setSearch(e.currentTarget.value)} + /> + + + ); +} + +function ListKeteranganBankSampahTerdekat({ search }: { search: string }) { + const keteranganState = useProxy(pengelolaanSampahState.keteranganSampah) const router = useRouter(); + + useEffect(() => { + keteranganState.findMany.load() + }, []) + + const filteredData = (keteranganState.findMany.data || []).filter(item => { + const keyword = search.toLowerCase(); + return ( + item.name.toLowerCase().includes(keyword) || + item.alamat.toLowerCase().includes(keyword) || + item.namaTempatMaps.toLowerCase().includes(keyword) + ); + }); + + if (!keteranganState.findMany.data) { + return ( + + + + ) + } return ( - - } - /> - List Keterangan Bank Sampah Terdekat - - - - - Nama Bank Sampah Terdekat - Gambar - Detail - - - - - - - Bank Sampah Sarana Gathi - - - - - - - - - - -
-
-
+ + + + + Nama Bank Sampah Terdekat + Alamat + Nama Tempat Maps + Detail + + + + {filteredData.map((item) => ( + + {item.name} + {item.alamat} + {item.namaTempatMaps} + + + + + ))} + +
- ) + ); } export default KeteranganBankSampahTerdekat; 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 index 816fdc03..a39f4a62 100644 --- 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 @@ -19,7 +19,7 @@ type IconKey = 'ekowisata' | 'kompetisi' | 'wisata' | 'ekonomi' | 'sampah' | 'tr function EditProgramKreatifDesa() { - const stateSampah = useProxy(pengelolaanSampahState) + const stateSampah = useProxy(pengelolaanSampahState.pengelolaanSampah) const params = useParams() const router = useRouter(); const [formData, setFormData] = useState({ 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 index 95acc819..99058152 100644 --- 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 @@ -11,7 +11,7 @@ import { useProxy } from 'valtio/utils'; function CreatePengelolaanSampahBankSampah() { - const stateCreate = useProxy(pengelolaanSampahState) + const stateCreate = useProxy(pengelolaanSampahState.pengelolaanSampah) const router = useRouter(); const resetForm = () => { 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 index 2792b45c..e9f107eb 100644 --- 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 @@ -31,7 +31,7 @@ function PengelolaanSampahBankSampah() { } function ListPengelolaanSampahBankSampah({ search }: { search: string }) { - const stateList = useProxy(pengelolaanSampahState) + const stateList = useProxy(pengelolaanSampahState.pengelolaanSampah) const [modalHapus, setModalHapus] = useState(false) const [selectedId, setSelectedId] = useState(null) const router = useRouter() diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/index.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/index.ts index ba1bd47e..568e0e6c 100644 --- a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/index.ts +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/index.ts @@ -4,6 +4,7 @@ import pengelolaanSampahDelete from "./del"; import pengelolaanSampahFindMany from "./findMany"; import pengelolaanSampahFindUnique from "./findUnique"; import pengelolaanSampahUpdate from "./updt"; +import KeteranganBankSampahTerdekat from "./keterangan-bank-sampah"; const PengelolaanSampah = new Elysia({ prefix: "/pengelolaansampah", @@ -33,5 +34,6 @@ const PengelolaanSampah = new Elysia({ }), } ) - .delete("/del/:id", pengelolaanSampahDelete); + .delete("/del/:id", pengelolaanSampahDelete) + .use(KeteranganBankSampahTerdekat); export default PengelolaanSampah; diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/create.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/create.ts new file mode 100644 index 00000000..51950fdb --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/create.ts @@ -0,0 +1,33 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +type FormCreateKeteranganBankSampahTerdekat = { + name: string; + alamat: string; + namaTempatMaps: string; + lat: number; + lng: number; +} + +export default async function keteranganBankSampahTerdekatCreate(context: Context) { + const body = context.body as FormCreateKeteranganBankSampahTerdekat; + + const linkPetunjukArah = `https://www.google.com/maps/dir/?api=1&destination=${body.lat},${body.lng}`; + + const created = await prisma.keteranganBankSampahTerdekat.create({ + data: { + name: body.name, + alamat: body.alamat, + namaTempatMaps: body.namaTempatMaps, + lat: body.lat, + lng: body.lng, + linkPetunjukArah, + }, + }); + + return { + success: true, + message: "Success create keterangan bank sampah terdekat", + data: created, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/del.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/del.ts new file mode 100644 index 00000000..c0f7da2d --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/del.ts @@ -0,0 +1,36 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +const keteranganBankSampahTerdekatDelete = async (context: Context) => { + const id = context.params?.id as string; + + if (!id) { + return { + status: 400, + body: "ID tidak diberikan", + }; + } + + const keteranganBankSampahTerdekat = await prisma.keteranganBankSampahTerdekat.findUnique({ + where: { id }, + }); + + if (!keteranganBankSampahTerdekat) { + return { + status: 404, + body: "Keterangan bank sampah terdekat tidak ditemukan", + }; + } + + await prisma.keteranganBankSampahTerdekat.delete({ + where: { id }, + }); + + return { + success: true, + status: 200, + message: "Keterangan bank sampah terdekat berhasil dihapus", + }; +}; + +export default keteranganBankSampahTerdekatDelete; \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/findMany.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/findMany.ts new file mode 100644 index 00000000..5928f238 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/findMany.ts @@ -0,0 +1,21 @@ +import prisma from "@/lib/prisma"; + +export default async function keteranganBankSampahTerdekatFindMany() { + try { + const data = await prisma.keteranganBankSampahTerdekat.findMany({ + where: { isActive: true }, + }); + + return { + success: true, + message: "Success fetch keterangan bank sampah terdekat", + data, + }; + } catch (e) { + console.error("Find many error:", e); + return { + success: false, + message: "Failed fetch keterangan bank sampah terdekat", + }; + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/findUnique.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/findUnique.ts new file mode 100644 index 00000000..2b24cef7 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-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 keteranganBankSampahTerdekatFindUnique(context: Context) { + const { id } = context.params as { id: string }; + + if (!id) { + return { + success: false, + message: "ID keterangan bank sampah terdekat diperlukan", + }; + } + + try { + const keteranganBankSampahTerdekat = await prisma.keteranganBankSampahTerdekat.findUnique({ + where: { id }, + }); + + if (!keteranganBankSampahTerdekat) { + return { + success: false, + message: "Keterangan bank sampah terdekat tidak ditemukan", + }; + } + + return { + success: true, + data: keteranganBankSampahTerdekat, + }; + } catch (error: any) { + console.error("Error findUnique keterangan bank sampah terdekat:", error); + return { + success: false, + message: "Gagal mengambil data keterangan bank sampah terdekat", + error: error.message, + }; + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/index.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/index.ts new file mode 100644 index 00000000..42cb1f82 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/index.ts @@ -0,0 +1,44 @@ +import Elysia, { t } from "elysia"; +import keteranganBankSampahTerdekatCreate from "./create"; +import keteranganBankSampahTerdekatDelete from "./del"; +import keteranganBankSampahTerdekatFindMany from "./findMany"; +import keteranganBankSampahTerdekatFindUnique from "./findUnique"; +import keteranganBankSampahTerdekatUpdate from "./updt"; + +const KeteranganBankSampahTerdekat = new Elysia({ + prefix: "/keteranganbankterdekat", + tags: ["Lingkungan/Pengelolaan Sampah/Keterangan Bank Sampah Terdekat"], +}) + .get("/find-many", keteranganBankSampahTerdekatFindMany) + .get("/:id", async (context) => { + const response = await keteranganBankSampahTerdekatFindUnique(context); + return response; + }) + .post("/create", keteranganBankSampahTerdekatCreate, { + body: t.Object({ + name: t.String(), + alamat: t.String(), + namaTempatMaps: t.String(), + lat: t.Number(), + lng: t.Number(), + }), + }) + .put( + "/:id", + async (context) => { + const response = await keteranganBankSampahTerdekatUpdate(context); + return response; + }, + { + body: t.Object({ + name: t.String(), + alamat: t.String(), + namaTempatMaps: t.String(), + lat: t.Number(), + lng: t.Number(), + }), + } + ) + .delete("/del/:id", keteranganBankSampahTerdekatDelete); + +export default KeteranganBankSampahTerdekat; diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/updt.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/updt.ts new file mode 100644 index 00000000..ee1bdec0 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/keterangan-bank-sampah/updt.ts @@ -0,0 +1,55 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +type FormUpdateKeteranganBankSampahTerdekat = { + id: string; + name?: string; + alamat?: string; + namaTempatMaps?: string; + lat?: number; + lng?: number; +}; + +export default async function keteranganBankSampahTerdekatUpdate(context: Context) { + const body = context.body as FormUpdateKeteranganBankSampahTerdekat; + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID keterangan bank sampah terdekat wajib diisi", + }; + } + + try { + const updateData: any = { + name: body.name, + alamat: body.alamat, + namaTempatMaps: body.namaTempatMaps, + }; + + if (body.lat !== undefined && body.lng !== undefined) { + updateData.lat = body.lat; + updateData.lng = body.lng; + updateData.linkPetunjukArah = `https://www.google.com/maps/dir/?api=1&destination=${body.lat},${body.lng}`; + } + + const updated = await prisma.keteranganBankSampahTerdekat.update({ + where: { id }, + data: updateData, + }); + + return { + success: true, + message: "Success update keterangan bank sampah terdekat", + data: updated, + }; + } catch (error) { + console.error("Update error:", error); + return { + success: false, + message: "Gagal mengupdate keterangan bank sampah terdekat", + }; + } +} diff --git a/src/app/darmasaba/(pages)/inovasi/layanan-online-desa/informasi-desa/page.tsx b/src/app/darmasaba/(pages)/inovasi/layanan-online-desa/informasi-desa/page.tsx index 4ac2d9c8..6f822525 100644 --- a/src/app/darmasaba/(pages)/inovasi/layanan-online-desa/informasi-desa/page.tsx +++ b/src/app/darmasaba/(pages)/inovasi/layanan-online-desa/informasi-desa/page.tsx @@ -39,96 +39,102 @@ function InformasiDesa() {
- {dataBerita && ( - + {dataBerita && ( + + + + {dataBerita.judul} + + + + {dataBerita.kategoriBerita?.name} • {dayjs(dataBerita.createdAt).fromNow()} + {dataBerita.judul} + + + + + + )} + + Berita Terbaru - - {dataBerita.judul} - - - - {dataBerita.kategoriBerita?.name} • {dayjs(dataBerita.createdAt).fromNow()} - {dataBerita.judul} - - - + {stateBerita.findRecent.data.map((item) => ( + + + + {item.judul} + + + + {item.judul} + + + {item.deskripsi} + + + {dayjs(item.createdAt).fromNow()} + + + + + ))} - - )} - - Berita Terbaru - - {stateBerita.findRecent.data.map((item) => ( - - - - {item.judul} - - - - {item.judul} - - - {item.deskripsi} - - - {dayjs(item.createdAt).fromNow()} - - - - - ))} - - - - {dataPengumuman && ( - - - {dataPengumuman.judul} - {dataPengumuman.CategoryPengumuman?.name} • {dayjs(dataPengumuman.createdAt).fromNow()} - - - - - - )} - - Pengumuman Terbaru + + - {statePengumuman.findRecent.data.map((item) => ( - - - - - {item.judul} - - - {item.deskripsi} - - - {dayjs(item.createdAt).fromNow()} - + + {dataPengumuman && ( + + + {dataPengumuman.judul} + {dataPengumuman.CategoryPengumuman?.name} • {dayjs(dataPengumuman.createdAt).fromNow()} + + + - - - ))} - + + )} + + + + Pengumuman Terbaru + + {statePengumuman.findRecent.data.map((item) => ( + + + + + {item.judul} + + + {item.deskripsi} + + + {dayjs(item.createdAt).fromNow()} + + + + + ))} + + + + - );