From 4a5524ce88f573108b7d7ced63f2f286054da057 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 20 Jun 2025 00:08:13 +0800 Subject: [PATCH] API & UI Kesehatan Sudah Sampai Di Penanganan Darurat --- .../penanganan-darurat/penangananDarurat.ts | 208 +++++++++++++++++ .../program-kesehatan/programKesehatan.ts | 214 ++++++++++++++++++ .../penanganan-darurat/[id]/edit/page.tsx | 140 ++++++++++++ .../penanganan-darurat/[id]/page.tsx | 101 +++++++++ .../penanganan-darurat/create/page.tsx | 124 ++++++---- .../penanganan-darurat/detail/page.tsx | 70 ------ .../penanganan-darurat/edit/page.tsx | 62 ----- .../kesehatan/penanganan-darurat/page.tsx | 36 ++- .../program-kesehatan/[id]/edit/page.tsx | 150 ++++++++++++ .../kesehatan/program-kesehatan/[id]/page.tsx | 103 +++++++++ .../program-kesehatan/create/page.tsx | 105 ++++++--- .../program-kesehatan/detail/page.tsx | 70 ------ .../kesehatan/program-kesehatan/edit/page.tsx | 64 ------ .../kesehatan/program-kesehatan/page.tsx | 100 ++++---- src/app/admin/_com/list_PageAdmin.tsx | 23 +- .../_lib/kesehatan/penanganan-darurat/del.ts | 81 ++++--- .../kesehatan/penanganan-darurat/index.ts | 2 +- 17 files changed, 1212 insertions(+), 441 deletions(-) create mode 100644 src/app/admin/(dashboard)/_state/kesehatan/penanganan-darurat/penangananDarurat.ts create mode 100644 src/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan.ts create mode 100644 src/app/admin/(dashboard)/kesehatan/penanganan-darurat/[id]/edit/page.tsx create mode 100644 src/app/admin/(dashboard)/kesehatan/penanganan-darurat/[id]/page.tsx delete mode 100644 src/app/admin/(dashboard)/kesehatan/penanganan-darurat/detail/page.tsx delete mode 100644 src/app/admin/(dashboard)/kesehatan/penanganan-darurat/edit/page.tsx create mode 100644 src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/edit/page.tsx create mode 100644 src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/page.tsx delete mode 100644 src/app/admin/(dashboard)/kesehatan/program-kesehatan/detail/page.tsx delete mode 100644 src/app/admin/(dashboard)/kesehatan/program-kesehatan/edit/page.tsx diff --git a/src/app/admin/(dashboard)/_state/kesehatan/penanganan-darurat/penangananDarurat.ts b/src/app/admin/(dashboard)/_state/kesehatan/penanganan-darurat/penangananDarurat.ts new file mode 100644 index 00000000..b47e0b17 --- /dev/null +++ b/src/app/admin/(dashboard)/_state/kesehatan/penanganan-darurat/penangananDarurat.ts @@ -0,0 +1,208 @@ +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(3, "Judul minimal 3 karakter"), + deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"), + imageId: z.string().nonempty(), +}) + +const defaultForm = { + name: "", + deskripsi: "", + imageId: "", +} + +const penangananDarurat = proxy({ + findMany: { + data: [] as Prisma.PenangananDaruratGetPayload<{ + include: { + image: true; + }; + }>[], + async load() { + const res = await ApiFetch.api.kesehatan.penanganandarurat[ + "find-many" + ].get(); + if (res.status === 200) { + penangananDarurat.findMany.data = res.data?.data ?? []; + } + }, + }, + create:{ + form: {...defaultForm}, + loading: false, + async create() { + const cek = templateForm.safeParse(penangananDarurat.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + penangananDarurat.create.loading = true; + const res = await ApiFetch.api.kesehatan.penanganandarurat[ + "create" + ].post(penangananDarurat.create.form); + if (res.status === 200) { + penangananDarurat.findMany.load(); + return toast.success("Penanganan Darurat berhasil disimpan!"); + } + + return toast.error("Gagal menyimpan penanganan darurat"); + } catch (error) { + console.log((error as Error).message); + } finally { + penangananDarurat.create.loading = false; + } + }, + resetForm() { + penangananDarurat.create.form = {...defaultForm}; + } + }, + findUnique: { + data: null as Prisma.PenangananDaruratGetPayload<{ + include: { + image: true; + }; + }> | null, + async load(id: string) { + try { + const res = await fetch(`/api/kesehatan/penanganandarurat/${id}`); + if (res.ok) { + const data = await res.json(); + penangananDarurat.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch data", res.status, res.statusText); + penangananDarurat.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching data:", error); + penangananDarurat.findUnique.data = null; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + try { + penangananDarurat.delete.loading = true; + const response = await fetch(`/api/kesehatan/penanganandarurat/del/${id}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + }); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success(result.message || "Penanganan darurat berhasil dihapus"); + await penangananDarurat.findMany.load(); // refresh list + } else { + toast.error(result?.message || "Gagal menghapus penanganan darurat"); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus penanganan darurat"); + } finally { + penangananDarurat.delete.loading = false; + } + } + }, + edit: { + id: "", + form: { ...defaultForm }, + loading: false, + + async load(id: string) { + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + try { + const response = await fetch(`/api/kesehatan/penanganandarurat/${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, + deskripsi: data.deskripsi, + imageId: data.imageId, + }; + return data; // Return the loaded data + } else { + throw new Error(result?.message || "Gagal memuat data"); + } + } catch (error) { + console.error("Error fetching penanganan darurat:", error); + toast.error(error instanceof Error ? error.message : "Gagal memuat data"); + return null; + } + }, + + async update() { + const cek = templateForm.safeParse(penangananDarurat.edit.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + penangananDarurat.edit.loading = true; + const response = await fetch(`/api/kesehatan/penanganandarurat/${this.id}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: this.form.name, + deskripsi: this.form.deskripsi, + imageId: this.form.imageId, + }), + }); + 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(result.message || "Penanganan darurat berhasil diupdate"); + await penangananDarurat.findMany.load(); + return true; + } else { + throw new Error(result.message || "Gagal update penanganan darurat"); + } + } catch (error) { + console.error("Gagal update:", error); + toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat mengupdate penanganan darurat"); + return false; + } finally { + penangananDarurat.edit.loading = false; + } + }, + reset() { + penangananDarurat.edit.id = ""; + penangananDarurat.edit.form = { ...defaultForm }; + }, + }, +}); + +export default penangananDarurat diff --git a/src/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan.ts b/src/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan.ts new file mode 100644 index 00000000..47676d85 --- /dev/null +++ b/src/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan.ts @@ -0,0 +1,214 @@ +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(3, "Judul minimal 3 karakter"), + deskripsiSingkat: z.string().min(3, "Deskripsi singkat minimal 3 karakter"), + deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"), + imageId: z.string().nonempty(), +}); + +const defaultForm = { + name: "", + deskripsiSingkat: "", + deskripsi: "", + imageId: "", +}; + +const programKesehatan = proxy({ + findMany: { + data: [] as Prisma.ProgramKesehatanGetPayload<{ + include: { + image: true; + }; + }>[], + async load() { + const res = await ApiFetch.api.kesehatan.programkesehatan[ + "find-many" + ].get(); + if (res.status === 200) { + programKesehatan.findMany.data = res.data?.data ?? []; + } + }, + }, + create: { + form: { ...defaultForm }, + loading: false, + async create() { + const cek = templateForm.safeParse(programKesehatan.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + programKesehatan.create.loading = true; + const res = await ApiFetch.api.kesehatan.programkesehatan[ + "create" + ].post(programKesehatan.create.form); + if (res.status === 200) { + programKesehatan.findMany.load(); + return toast.success("Program Kesehatan berhasil disimpan!"); + } + + return toast.error("Gagal menyimpan program kesehatan"); + } catch (error) { + console.log((error as Error).message); + } finally { + programKesehatan.create.loading = false; + } + }, + resetForm() { + programKesehatan.create.form = { ...defaultForm }; + }, + }, + findUnique: { + data: null as Prisma.ProgramKesehatanGetPayload<{ + include: { + image: true; + }; + }> | null, + async load(id: string) { + try { + const res = await fetch(`/api/kesehatan/programkesehatan/${id}`); + if (res.ok) { + const data = await res.json(); + programKesehatan.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch program kesehatan:", res.statusText); + programKesehatan.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching program kesehatan:", error); + programKesehatan.findUnique.data = null; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + if (!id) return toast.warn("ID tidak valid"); + + try { + programKesehatan.delete.loading = true; + + const response = await fetch(`/api/kesehatan/programkesehatan/del/${id}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + }); + + const result = await response.json(); + if (response.ok && result?.success) { + toast.success(result.message || "Program kesehatan berhasil dihapus"); + await programKesehatan.findMany.load(); // refresh list + } else { + toast.error(result?.message || "Gagal menghapus program kesehatan"); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus program kesehatan"); + } finally { + programKesehatan.delete.loading = false; + } + }, + }, + edit: { + id: "", + form: { ...defaultForm }, + loading: false, + + async load(id: string) { + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + try { + const response = await fetch(`/api/kesehatan/programkesehatan/${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, + deskripsiSingkat: data.deskripsiSingkat, + deskripsi: data.deskripsi, + imageId: data.imageId, + }; + return data; // Return the loaded data + } else { + throw new Error(result?.message || "Gagal memuat data"); + } + } catch (error) { + console.error("Error fetching program kesehatan:", error); + toast.error(error instanceof Error ? error.message : "Gagal memuat data"); + return null; + } + }, + + async update() { + const cek = templateForm.safeParse(programKesehatan.edit.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + programKesehatan.edit.loading = true; + const response = await fetch(`/api/kesehatan/programkesehatan/${this.id}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: this.form.name, + deskripsiSingkat: this.form.deskripsiSingkat, + deskripsi: this.form.deskripsi, + imageId: this.form.imageId, + }), + }); + 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(result.message || "Program kesehatan berhasil diupdate"); + await programKesehatan.findMany.load(); + return true; + } else { + throw new Error(result.message || "Gagal update program kesehatan"); + } + } catch (error) { + console.error("Gagal update:", error); + toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat mengupdate program kesehatan"); + return false; + } finally { + programKesehatan.edit.loading = false; + } + }, + reset() { + programKesehatan.edit.id = ""; + programKesehatan.edit.form = { ...defaultForm }; + }, + }, +}); + +export default programKesehatan; diff --git a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/[id]/edit/page.tsx b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/[id]/edit/page.tsx new file mode 100644 index 00000000..3f1c5019 --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/[id]/edit/page.tsx @@ -0,0 +1,140 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' +import EditEditor from '@/app/admin/(dashboard)/_com/editEditor'; +import penangananDarurat from '@/app/admin/(dashboard)/_state/kesehatan/penanganan-darurat/penangananDarurat'; +import colors from '@/con/colors'; +import ApiFetch from '@/lib/api-fetch'; +import { Box, Button, Center, FileInput, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; + +function EditPenangananDarurat() { + const penangananDaruratState = useProxy(penangananDarurat) + const router = useRouter(); + const params = useParams() + + const [previewImage, setPreviewImage] = useState(null); + const [file, setFile] = useState(null); + const [formData, setFormData] = useState({ + name: penangananDaruratState.edit.form.name || '', + deskripsi: penangananDaruratState.edit.form.deskripsi || '', + imageId: penangananDaruratState.edit.form.imageId || '', + }) + + useEffect(() => { + const loadPenangananDarurat = async () => { + const id = params?.id as string; + if (!id) return; + + try { + const data = await penangananDaruratState.edit.load(id); + if (data) { + setFormData({ + name: data.name || '', + deskripsi: data.deskripsi || '', + imageId: data.imageId || '', + }) + + if (data?.image?.link) { + setPreviewImage(data.image.link); + } + } + } catch (error) { + console.error('Error loading penanganan darurat:', error); + toast.error('Gagal memuat data penanganan darurat'); + } + } + + loadPenangananDarurat(); + }, [params?.id]) + + const handleSubmit = async () => { + try { + penangananDaruratState.edit.form = { + ...penangananDaruratState.edit.form, + name: formData.name, + deskripsi: formData.deskripsi, + imageId: formData.imageId, + } + + if (file) { + const res = await ApiFetch.api.fileStorage.create.post({ file, name: file.name }); + const uploaded = res.data?.data; + + if (!uploaded?.id) { + return toast.error("Gagal upload gambar"); + } + + penangananDaruratState.edit.form.imageId = uploaded.id; + } + + await penangananDaruratState.edit.update(); + toast.success("Penanganan darurat berhasil diperbarui!"); + router.push("/admin/kesehatan/penanganan-darurat"); + } catch (error) { + console.error("Error updating penanganan darurat:", error); + toast.error("Gagal memuat data penanganan darurat"); + } + } + return ( + + + + + + + + Edit Penanganan Darurat + + setFormData({ ...formData, name: e.target.value })} + label={Judul} + placeholder="masukkan judul" + /> + + + Deskripsi + setFormData({ ...formData, deskripsi: val })} + /> + + + Upload Gambar} + value={file} + onChange={async (e) => { + if (!e) return; + setFile(e); + const base64 = await e.arrayBuffer().then((buf) => + 'data:image/png;base64,' + Buffer.from(buf).toString('base64') + ); + setPreviewImage(base64); + }} + /> + + {previewImage ? ( + + ) : ( +
+ +
+ )} + + +
+
+
+
+ ); +} + +export default EditPenangananDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/[id]/page.tsx b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/[id]/page.tsx new file mode 100644 index 00000000..46615005 --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/[id]/page.tsx @@ -0,0 +1,101 @@ +'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, { useState } from 'react'; +// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; +import penangananDarurat from '../../../_state/kesehatan/penanganan-darurat/penangananDarurat'; +import { useProxy } from 'valtio/utils'; +import { useShallowEffect } from '@mantine/hooks'; +import { useParams } from 'next/navigation'; +import { Skeleton } from '@mantine/core'; +import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; + +function DetailPenangananDarurat() { + const penangananDaruratState = useProxy(penangananDarurat) + const [modalHapus, setModalHapus] = useState(false) + const [selectedId, setSelectedId] = useState(null) + const router = useRouter(); + const params = useParams() + + useShallowEffect(() => { + penangananDaruratState.findUnique.load(params?.id as string) + }, []) + + const handleHapus = () => { + if (selectedId) { + penangananDaruratState.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + router.push("/admin/kesehatan/penanganan-darurat") + } + } + + if (!penangananDaruratState.findUnique.data) { + return ( + + + + ) + } + + return ( + + + + + + + Detail Penanganan Darurat + {penangananDaruratState.findUnique.data ? ( + + + + Nama Penanganan Darurat + {penangananDaruratState.findUnique.data.name} + + + Deskripsi + + + + Gambar + gambar + + + + + + + + + + ) : null} + + + + {/* Modal Hapus */} + setModalHapus(false)} + onConfirm={handleHapus} + text="Apakah anda yakin ingin menghapus penanganan darurat ini?" + /> + + ); +} + +export default DetailPenangananDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/create/page.tsx b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/create/page.tsx index 8397049b..2c972d9b 100644 --- a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/create/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/create/page.tsx @@ -1,14 +1,56 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; -import { IconArrowBack } from '@tabler/icons-react'; +import ApiFetch from '@/lib/api-fetch'; +import { Box, Button, Center, FileInput, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; -import { KesehatanEditor } from '../../_com/kesehatanEditor'; +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; +import CreateEditor from '../../../_com/createEditor'; +import penangananDarurat from '../../../_state/kesehatan/penanganan-darurat/penangananDarurat'; + function CreatePenangananDarurat() { const router = useRouter(); + const penangananDaruratState = useProxy(penangananDarurat) + const [previewImage, setPreviewImage] = useState(null); + const [file, setFile] = useState(null); + + const resetForm = () => { + penangananDaruratState.create.form = { + name: "", + deskripsi: "", + imageId: "", + }; + setPreviewImage(null); + setFile(null); + }; + + const handleSubmit = async () => { + if (!file) { + return toast.warn("Pilih file gambar terlebih dahulu"); + } + + const res = await ApiFetch.api.fileStorage.create.post({ + file, + name: file.name, + }); + + const uploaded = res.data?.data; + if (!uploaded?.id) { + return toast.error("Gagal upload gambar"); + } + + penangananDaruratState.create.form.imageId = uploaded.id; + + await penangananDaruratState.create.create(); + + resetForm(); + router.push("/admin/kesehatan/penanganan-darurat") + } return ( - + + Upload Gambar} + value={file} + onChange={async (e) => { + if (!e) return; + setFile(e); + const base64 = await e.arrayBuffer().then((buf) => + 'data:image/png;base64,' + Buffer.from(buf).toString('base64') + ); + setPreviewImage(base64); + }} + /> + + {previewImage ? ( + + ) : ( +
+ +
+ )} + +
diff --git a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/detail/page.tsx b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/detail/page.tsx deleted file mode 100644 index 847728db..00000000 --- a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/detail/page.tsx +++ /dev/null @@ -1,70 +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 DetailPenangananDarurat() { - const router = useRouter(); - return ( - - - - - - - Detail Penanganan Darurat - - - - - Nama Penanganan Darurat - Test Judul - - - Deskripsi Penanganan Darurat - Test Kategori - - - Deskripsi - Test Deskripsi - - - Gambar - gambar - - - Konten - Test Konten - - - - - - - - - - - - - {/* Modal Hapus - setModalHapus(false)} - onConfirm={handleHapus} - text="Apakah anda yakin ingin menghapus penanganan darurat ini?" - /> */} - - ); -} - -export default DetailPenangananDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/edit/page.tsx b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/edit/page.tsx deleted file mode 100644 index 68539b65..00000000 --- a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/edit/page.tsx +++ /dev/null @@ -1,62 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Stack, SimpleGrid, Paper, Title, TextInput, Text, Button, Image } from '@mantine/core'; -import { KesehatanEditor } from '../../_com/kesehatanEditor'; -import { IconArrowBack } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; - - -function EditPenangananDarurat() { - const router = useRouter(); - return ( - - - - - - - - - - Edit Penanganan Darurat - Nama Penanganan Darurat} - placeholder='Masukkan nama Penanganan Darurat' - /> - Deskripsi Penanganan Darurat} - placeholder='Masukkan deskripsi Penanganan Darurat' - /> - - Deskripsi - - - - Gambar - gambar - - - - - - - - Preview Data Penanganan Darurat - Nama Penanganan Darurat - No Telp Penanganan Darurat - Deskripsi - Pelayanan Posyandu - - - - - - - ); -} - -export default EditPenangananDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/page.tsx b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/page.tsx index 714ac745..4468840c 100644 --- a/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/penanganan-darurat/page.tsx @@ -1,10 +1,14 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Image, Paper, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; +import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react'; import JudulList from '../../_com/judulList'; import HeaderSearch from '../../_com/header'; import { useRouter } from 'next/navigation'; +import { useProxy } from 'valtio/utils'; +import { useShallowEffect } from '@mantine/hooks'; +import penangananDarurat from '../../_state/kesehatan/penanganan-darurat/penangananDarurat'; + function PenangananDarurat() { return ( @@ -20,7 +24,21 @@ function PenangananDarurat() { } function ListPenangananDarurat() { + const penangananDaruratState = useProxy(penangananDarurat) const router = useRouter(); + + useShallowEffect(() => { + penangananDaruratState.findMany.load() + }, []) + + if (!penangananDaruratState.findMany.data) { + return ( + + + + ) + } + return ( @@ -34,27 +52,31 @@ function ListPenangananDarurat() { Judul - Kategori + Deskripsi Image Detail - + {penangananDaruratState.findMany.data?.map((item) => ( + - Test + {item.name} - Test - image + - + ))} diff --git a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/edit/page.tsx b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/edit/page.tsx new file mode 100644 index 00000000..4f4e527e --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/edit/page.tsx @@ -0,0 +1,150 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' +import EditEditor from '@/app/admin/(dashboard)/_com/editEditor'; +import programKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan'; +import colors from '@/con/colors'; +import ApiFetch from '@/lib/api-fetch'; +import { Box, Button, Center, FileInput, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; + + +function EditProgramKesehatan() { + const programKesehatanState = useProxy(programKesehatan) + const router = useRouter(); + const params = useParams() + + const [previewImage, setPreviewImage] = useState(null); + const [file, setFile] = useState(null); + const [formData, setFormData] = useState({ + name: programKesehatanState.edit.form.name || '', + deskripsiSingkat: programKesehatanState.edit.form.deskripsiSingkat || '', + deskripsi: programKesehatanState.edit.form.deskripsi || '', + imageId: programKesehatanState.edit.form.imageId || '', + }) + + useEffect(() => { + const loadProgramKesehatan = async () => { + const id = params?.id as string; + if (!id) return; + + try { + const data = await programKesehatanState.edit.load(id); + if (data) { + setFormData({ + name: data.name || '', + deskripsiSingkat: data.deskripsiSingkat || '', + deskripsi: data.deskripsi || '', + imageId: data.imageId || '', + }); + + if (data?.image?.link) { + setPreviewImage(data.image.link); + } + } + } catch (error) { + console.error("Error loading program kesehatan:", error); + toast.error("Gagal memuat data program kesehatan"); + } + }; + + loadProgramKesehatan(); + }, [params?.id]); + + const handleSubmit = async () => { + try { + programKesehatanState.edit.form = { + ...programKesehatanState.edit.form, + name: formData.name, + deskripsiSingkat: formData.deskripsiSingkat, + deskripsi: formData.deskripsi, + imageId: formData.imageId, + }; + + if (file) { + const res = await ApiFetch.api.fileStorage.create.post({ file, name: file.name }); + const uploaded = res.data?.data; + + if (!uploaded?.id) { + return toast.error("Gagal upload gambar"); + } + + programKesehatanState.edit.form.imageId = uploaded.id; + } + + await programKesehatanState.edit.update(); + toast.success("Program kesehatan berhasil diperbarui!"); + router.push("/admin/kesehatan/program-kesehatan"); + } catch (error) { + console.error("Error updating program kesehatan:", error); + toast.error("Gagal memuat data program kesehatan"); + } + } + return ( + + + + + + + + Edit Program Kesehatan + setFormData({ ...formData, name: e.target.value })} + label={Judul} + placeholder="masukkan judul" + /> + + setFormData({ ...formData, deskripsiSingkat: e.target.value })} + label={Deskripsi Singkat} + placeholder="masukkan deskripsi" + /> + + + Deskripsi + setFormData({ ...formData, deskripsi: val })} + /> + + + Upload Gambar} + value={file} + onChange={async (e) => { + if (!e) return; + setFile(e); + const base64 = await e.arrayBuffer().then((buf) => + 'data:image/png;base64,' + Buffer.from(buf).toString('base64') + ); + setPreviewImage(base64); + }} + /> + + {previewImage ? ( + + ) : ( +
+ +
+ )} + + +
+
+
+
+ ); +} + +export default EditProgramKesehatan; diff --git a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/page.tsx b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/page.tsx new file mode 100644 index 00000000..89f2f148 --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/page.tsx @@ -0,0 +1,103 @@ +'use client' +import colors from '@/con/colors'; +import { Box, Button, Paper, Stack, Flex, Text, Image, Skeleton } from '@mantine/core'; +import { IconArrowBack, IconX, IconEdit } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import React, { useState } from 'react'; +import programKesehatan from '../../../_state/kesehatan/program-kesehatan/programKesehatan'; +import { useProxy } from 'valtio/utils'; +import { useShallowEffect } from '@mantine/hooks'; +import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; + +function DetailProgramKesehatan() { + const programKesehatanState = useProxy(programKesehatan) + const [modalHapus, setModalHapus] = useState(false) + const [selectedId, setSelectedId] = useState(null) + const router = useRouter(); + const params = useParams() + + useShallowEffect(() => { + programKesehatanState.findUnique.load(params?.id as string) + }, []) + + const handleHapus = () => { + if (selectedId) { + programKesehatanState.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + router.push("/admin/kesehatan/program-kesehatan") + } + } + + if (!programKesehatanState.findUnique.data) { + return ( + + + + ) + } + + return ( + + + + + + + Detail Potensi + {programKesehatanState.findUnique.data ? ( + + + + Judul + {programKesehatanState.findUnique.data.name} + + + Deskripsi Singkat + {programKesehatanState.findUnique.data.deskripsiSingkat} + + + Deskripsi + + + + Gambar + gambar + + + + + + + + + + ) : null} + + + + {/* Modal Hapus */} + setModalHapus(false)} + onConfirm={handleHapus} + text="Apakah anda yakin ingin menghapus program kesehatan ini?" + /> + + ); +} + +export default DetailProgramKesehatan; diff --git a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/create/page.tsx b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/create/page.tsx index fb9d57ba..1bd5f486 100644 --- a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/create/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/create/page.tsx @@ -1,43 +1,101 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; -import { IconArrowBack } from '@tabler/icons-react'; +import ApiFetch from '@/lib/api-fetch'; +import { Box, Button, Center, FileInput, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; -import { KesehatanEditor } from '../../_com/kesehatanEditor'; +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; +import CreateEditor from '../../../_com/createEditor'; +import programKesehatan from '../../../_state/kesehatan/program-kesehatan/programKesehatan'; function CreateProgramKesehatan() { const router = useRouter(); + const programKesehatanState = useProxy(programKesehatan) + const [previewImage, setPreviewImage] = useState(null); + const [file, setFile] = useState(null); + + const resetForm = () => { + // Reset state di valtio + programKesehatanState.create.form = { + name: "", + deskripsiSingkat: "", + deskripsi: "", + imageId: "", + }; + + // Reset state lokal + setPreviewImage(null); + setFile(null); + }; + + const handleSubmit = async () => { + if (!file) { + return toast.warn("Pilih file gambar terlebih dahulu"); + } + + // Upload gambar dulu + const res = await ApiFetch.api.fileStorage.create.post({ + file, + name: file.name, + }); + + const uploaded = res.data?.data; + if (!uploaded?.id) { + return toast.error("Gagal upload gambar"); + } + + // Simpan ID gambar ke form + programKesehatanState.create.form.imageId = uploaded.id; + + // Submit data berita + await programKesehatanState.create.create(); + + // Reset form setelah submit + resetForm(); + router.push("/admin/kesehatan/program-kesehatan") + }; + return ( - + - Create Program Kesehatan - { + programKesehatanState.create.form.name = val.target.value; + }} label={Judul} placeholder="masukkan judul" /> Deskripsi} + value={programKesehatanState.create.form.deskripsiSingkat} + onChange={(val) => { + programKesehatanState.create.form.deskripsiSingkat = val.target.value; + }} + label={Deskripsi Singkat} placeholder="masukkan deskripsi" /> - Kategori} - placeholder="masukkan kategori" - /> + + Deskripsi + { + programKesehatanState.create.form.deskripsi = val; + }} + /> + - {/* Upload Gambar} value={file} onChange={async (e) => { @@ -48,25 +106,18 @@ function CreateProgramKesehatan() { ); setPreviewImage(base64); }} - /> */} + /> - {/* {previewImage ? ( + {previewImage ? ( ) : (
- )} */} + )} - - Konten - - - -
diff --git a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/detail/page.tsx b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/detail/page.tsx deleted file mode 100644 index 193f9366..00000000 --- a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/detail/page.tsx +++ /dev/null @@ -1,70 +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 DetailProgramKesehatan() { - const router = useRouter(); - return ( - - - - - - - Detail Potensi - - - - - Judul - Test Judul - - - Kategori - Test Kategori - - - Deskripsi - Test Deskripsi - - - Gambar - gambar - - - Konten - Test Konten - - - - - - - - - - - - - {/* Modal Hapus - setModalHapus(false)} - onConfirm={handleHapus} - text="Apakah anda yakin ingin menghapus potensi ini?" - /> */} - - ); -} - -export default DetailProgramKesehatan; diff --git a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/edit/page.tsx b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/edit/page.tsx deleted file mode 100644 index d6e72783..00000000 --- a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/edit/page.tsx +++ /dev/null @@ -1,64 +0,0 @@ -'use client' -import colors from '@/con/colors'; -import { Box, Stack, SimpleGrid, Paper, Title, TextInput, Text, Button } from '@mantine/core'; -import { KesehatanEditor } from '../../_com/kesehatanEditor'; -import { IconArrowBack } from '@tabler/icons-react'; -import { useRouter } from 'next/navigation'; - - -function EditProgramKesehatan() { - const router = useRouter(); - return ( - - - - - - - - - - Edit Program Kesehatan - Nama Program Kesehatan} - placeholder='Masukkan nama Program Kesehatan' - /> - No Telp Program Kesehatan} - placeholder='Masukkan no telp Program Kesehatan' - /> - - Deskripsi - - - - Pelayanan Posyandu - - - - - - - - - Preview Data Program Kesehatan - Nama Program Kesehatan - No Telp Program Kesehatan - Deskripsi - Pelayanan Posyandu - - - - - - - ); -} - -export default EditProgramKesehatan; diff --git a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/page.tsx b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/page.tsx index 8461d09c..2dc2b67c 100644 --- a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/page.tsx @@ -1,10 +1,13 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Image, Paper, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; +import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react'; import JudulList from '../../_com/judulList'; import HeaderSearch from '../../_com/header'; import { useRouter } from 'next/navigation'; +import programKesehatan from '../../_state/kesehatan/program-kesehatan/programKesehatan'; +import { useProxy } from 'valtio/utils'; +import { useShallowEffect } from '@mantine/hooks'; function ProgramKesehatan() { return ( @@ -14,53 +17,70 @@ function ProgramKesehatan() { placeholder='pencarian' searchIcon={} /> - +
); } function ListProgramKesehatan() { + const programKesehatanState = useProxy(programKesehatan) const router = useRouter() + + useShallowEffect(() => { + programKesehatanState.findMany.load() + }, []) + + if (!programKesehatanState.findMany.data) { + return ( + + + + ) + } + return ( - - - - - - - - Judul - Kategori - Image - Detail - - - - - - - Test - - Test - - - - - - - - -
-
-
-
-
+ + + + + + + + Judul + Deskripsi Singkat + Image + Detail + + + + {programKesehatanState.findMany.data?.map((item) => ( + + + + {item.name} + + + {item.deskripsiSingkat} + + + + + + + + ))} + +
+
+
+
+
) } diff --git a/src/app/admin/_com/list_PageAdmin.tsx b/src/app/admin/_com/list_PageAdmin.tsx index d5d9606c..392c7d56 100644 --- a/src/app/admin/_com/list_PageAdmin.tsx +++ b/src/app/admin/_com/list_PageAdmin.tsx @@ -11,41 +11,26 @@ export const navBar = [ }, { id: "Landing_Page_2", - name: "Penghargaan", - path: "/admin/landing-page/penghargaan" - }, - { - id: "Landing_Page_3", - name: "Layanan", - path: "/admin/landing-page/layanan" - }, - { - id: "Landing_Page_4", - name: "Potensi", - path: "/admin/landing-page/potensi" - }, - { - id: "Landing_Page_5", name: "Desa Anti Korupsi", path: "/admin/landing-page/desa-anti-korupsi" }, { - id: "Landing_Page_6", + id: "Landing_Page_3", name: "Indeks Kepuasan Masyarakat", path: "/admin/landing-page/indeks-kepuasan-masyarakat" }, { - id: "Landing_Page_7", + id: "Landing_Page_4", name: "SDGs Desa", path: "/admin/landing-page/sdgs-desa" }, { - id: "Landing_Page_8", + id: "Landing_Page_5", name: "APBDes", path: "/admin/landing-page/apbdes" }, { - id: "Landing_Page_9", + id: "Landing_Page_6", name: "Prestasi Desa", path: "/admin/landing-page/prestasi-desa" } diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/penanganan-darurat/del.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/penanganan-darurat/del.ts index a7db6633..50089f9a 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/penanganan-darurat/del.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/penanganan-darurat/del.ts @@ -4,44 +4,51 @@ import { Context } from "elysia"; import path from "path"; const penangananDaruratDelete = async (context: Context) => { - const id = context.params?.id as string; - - if (!id) { - return { - status: 400, - body: "ID tidak diberikan", - }; - } - - const penangananDarurat = await prisma.penangananDarurat.findUnique({ - where: { id }, - include: { image: true }, - }); - if (!penangananDarurat) { - return { - status: 404, - body: "Penanganan darurat tidak ditemukan", - }; - } - - // Hapus file gambar dari filesystem jika ada - if (penangananDarurat.image) { - try { - const filePath = path.join(penangananDarurat.image.path, penangananDarurat.image.name); - await fs.unlink(filePath); - } catch (error) { - console.error("Error deleting image file:", error); - } - } - - // Hapus data dari database - await prisma.penangananDarurat.delete({ - where: { id }, - }); + const id = context.params?.id as string; + if (!id) { return { - status: 200, - body: "Penanganan darurat berhasil dihapus", + status: 400, + body: "ID tidak diberikan", }; + } + + const penangananDarurat = await prisma.penangananDarurat.findUnique({ + where: { id }, + include: { image: true }, + }); + if (!penangananDarurat) { + return { + status: 404, + body: "Penanganan darurat tidak ditemukan", + }; + } + + // Hapus file gambar dari filesystem jika ada + if (penangananDarurat.image) { + try { + const filePath = path.join( + penangananDarurat.image.path, + penangananDarurat.image.name + ); + await fs.unlink(filePath); + await prisma.fileStorage.delete({ + where: { id: penangananDarurat.image.id }, + }); + } catch (error) { + console.error("Error deleting image file:", error); + } + } + + // Hapus data dari database + await prisma.penangananDarurat.delete({ + where: { id }, + }); + + return { + status: 200, + success: true, + message: "Penanganan darurat dan file terkait berhasil dihapus", + }; }; -export default penangananDaruratDelete; \ No newline at end of file +export default penangananDaruratDelete; diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/penanganan-darurat/index.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/penanganan-darurat/index.ts index 6b6ac237..6f8eaebe 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/penanganan-darurat/index.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/penanganan-darurat/index.ts @@ -6,7 +6,7 @@ import penangananDaruratFindUnique from "./findUnique"; import penangananDaruratUpdate from "./updt"; const PenangananDarurat = new Elysia({ - prefix: "/penanganan-darurat", + prefix: "/penanganandarurat", tags: ["Kesehatan/Penanganan Darurat"] }) .post("/create", penangananDaruratCreate, {