From fc08b2e790d7e042074827f8adf20f8c5a5d92e4 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 20 Jun 2025 08:11:31 +0800 Subject: [PATCH] UI & API Admin Kesehatan Done --- .../info-wabah-penyakit/infoWabahPenyakit.ts | 214 ++++++++++++++++++ .../kesehatan/kontak-darurat/kontakDarurat.ts | 208 +++++++++++++++++ .../info-wabah-penyakit/[id]/edit/page.tsx | 150 ++++++++++++ .../info-wabah-penyakit/[id]/page.tsx | 103 +++++++++ .../info-wabah-penyakit/create/page.tsx | 105 ++++++--- .../info-wabah-penyakit/detail/page.tsx | 70 ------ .../info-wabah-penyakit/edit/page.tsx | 62 ----- .../kesehatan/info-wabah-penyakit/page.tsx | 55 +++-- .../kontak-darurat/[id]/edit/page.tsx | 140 ++++++++++++ .../kesehatan/kontak-darurat/[id]/page.tsx | 99 ++++++++ .../kesehatan/kontak-darurat/create/page.tsx | 172 ++++++++------ .../kesehatan/kontak-darurat/detail/page.tsx | 70 ------ .../kesehatan/kontak-darurat/edit/page.tsx | 62 ----- .../kesehatan/kontak-darurat/page.tsx | 104 +++++---- .../kesehatan/program-kesehatan/[id]/page.tsx | 2 +- .../kesehatan/program-kesehatan/page.tsx | 2 +- .../_lib/kesehatan/info-wabah-penyakit/del.ts | 6 +- .../_lib/kesehatan/kontak-darurat/del.ts | 6 +- .../_lib/kesehatan/kontak-darurat/index.ts | 2 - 19 files changed, 1209 insertions(+), 423 deletions(-) create mode 100644 src/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit.ts create mode 100644 src/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat.ts create mode 100644 src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/[id]/edit/page.tsx create mode 100644 src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/[id]/page.tsx delete mode 100644 src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/detail/page.tsx delete mode 100644 src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/edit/page.tsx create mode 100644 src/app/admin/(dashboard)/kesehatan/kontak-darurat/[id]/edit/page.tsx create mode 100644 src/app/admin/(dashboard)/kesehatan/kontak-darurat/[id]/page.tsx delete mode 100644 src/app/admin/(dashboard)/kesehatan/kontak-darurat/detail/page.tsx delete mode 100644 src/app/admin/(dashboard)/kesehatan/kontak-darurat/edit/page.tsx diff --git a/src/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit.ts b/src/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit.ts new file mode 100644 index 00000000..e53417bd --- /dev/null +++ b/src/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit.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"), + deskripsiLengkap: z.string().min(3, "Deskripsi lengkap minimal 3 karakter"), + imageId: z.string().nonempty(), +}); + +const defaultForm = { + name: "", + deskripsiSingkat: "", + deskripsiLengkap: "", + imageId: "", +}; + +const infoWabahPenyakit = proxy({ + findMany: { + data: [] as Prisma.InfoWabahPenyakitGetPayload<{ + include: { + image: true; + }; + }>[], + async load() { + const res = await ApiFetch.api.kesehatan.infowabahpenyakit[ + "find-many" + ].get(); + if (res.status === 200) { + infoWabahPenyakit.findMany.data = res.data?.data ?? []; + } + }, + }, + create: { + form: { ...defaultForm }, + loading: false, + async create() { + const cek = templateForm.safeParse(infoWabahPenyakit.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + infoWabahPenyakit.create.loading = true; + const res = await ApiFetch.api.kesehatan.infowabahpenyakit[ + "create" + ].post(infoWabahPenyakit.create.form); + if (res.status === 200) { + infoWabahPenyakit.findMany.load(); + return toast.success("Info wabah penyakit berhasil disimpan!"); + } + + return toast.error("Gagal menyimpan info wabah penyakit"); + } catch (error) { + console.log((error as Error).message); + } finally { + infoWabahPenyakit.create.loading = false; + } + }, + resetForm() { + infoWabahPenyakit.create.form = { ...defaultForm }; + }, + }, + findUnique: { + data: null as Prisma.InfoWabahPenyakitGetPayload<{ + include: { + image: true; + }; + }> | null, + async load(id: string) { + try { + const res = await fetch(`/api/kesehatan/infowabahpenyakit/${id}`); + if (res.ok) { + const data = await res.json(); + infoWabahPenyakit.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch info wabah penyakit:", res.statusText); + infoWabahPenyakit.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching info wabah penyakit:", error); + infoWabahPenyakit.findUnique.data = null; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + if (!id) return toast.warn("ID tidak valid"); + + try { + infoWabahPenyakit.delete.loading = true; + + const response = await fetch(`/api/kesehatan/infowabahpenyakit/del/${id}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + }); + + const result = await response.json(); + if (response.ok && result?.success) { + toast.success(result.message || "Info wabah penyakit berhasil dihapus"); + await infoWabahPenyakit.findMany.load(); // refresh list + } else { + toast.error(result?.message || "Gagal menghapus info wabah penyakit"); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus info wabah penyakit"); + } finally { + infoWabahPenyakit.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/infowabahpenyakit/${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, + deskripsiLengkap: data.deskripsiLengkap, + imageId: data.imageId, + }; + return data; // Return the loaded data + } else { + throw new Error(result?.message || "Gagal memuat data"); + } + } catch (error) { + console.error("Error fetching info wabah penyakit:", error); + toast.error(error instanceof Error ? error.message : "Gagal memuat data"); + return null; + } + }, + + async update() { + const cek = templateForm.safeParse(infoWabahPenyakit.edit.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + infoWabahPenyakit.edit.loading = true; + const response = await fetch(`/api/kesehatan/infowabahpenyakit/${this.id}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: this.form.name, + deskripsiSingkat: this.form.deskripsiSingkat, + deskripsiLengkap: this.form.deskripsiLengkap, + 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 || "Info wabah penyakit berhasil diupdate"); + await infoWabahPenyakit.findMany.load(); + return true; + } else { + throw new Error(result.message || "Gagal update info wabah penyakit"); + } + } catch (error) { + console.error("Gagal update:", error); + toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat mengupdate info wabah penyakit"); + return false; + } finally { + infoWabahPenyakit.edit.loading = false; + } + }, + reset() { + infoWabahPenyakit.edit.id = ""; + infoWabahPenyakit.edit.form = { ...defaultForm }; + }, + }, +}); + +export default infoWabahPenyakit; diff --git a/src/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat.ts b/src/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat.ts new file mode 100644 index 00000000..cfd2c18f --- /dev/null +++ b/src/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat.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 kontakDarurat = proxy({ + findMany: { + data: [] as Prisma.KontakDaruratGetPayload<{ + include: { + image: true; + }; + }>[], + async load() { + const res = await ApiFetch.api.kesehatan.kontakdarurat[ + "find-many" + ].get(); + if (res.status === 200) { + kontakDarurat.findMany.data = res.data?.data ?? []; + } + }, + }, + create:{ + form: {...defaultForm}, + loading: false, + async create() { + const cek = templateForm.safeParse(kontakDarurat.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + kontakDarurat.create.loading = true; + const res = await ApiFetch.api.kesehatan.kontakdarurat[ + "create" + ].post(kontakDarurat.create.form); + if (res.status === 200) { + kontakDarurat.findMany.load(); + return toast.success("Kontak Darurat berhasil disimpan!"); + } + + return toast.error("Gagal menyimpan kontak darurat"); + } catch (error) { + console.log((error as Error).message); + } finally { + kontakDarurat.create.loading = false; + } + }, + resetForm() { + kontakDarurat.create.form = {...defaultForm}; + } + }, + findUnique: { + data: null as Prisma.KontakDaruratGetPayload<{ + include: { + image: true; + }; + }> | null, + async load(id: string) { + try { + const res = await fetch(`/api/kesehatan/kontakdarurat/${id}`); + if (res.ok) { + const data = await res.json(); + kontakDarurat.findUnique.data = data.data ?? null; + } else { + console.error("Failed to fetch data", res.status, res.statusText); + kontakDarurat.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching data:", error); + kontakDarurat.findUnique.data = null; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + try { + kontakDarurat.delete.loading = true; + const response = await fetch(`/api/kesehatan/kontakdarurat/del/${id}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + }); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success(result.message || "Kontak darurat berhasil dihapus"); + await kontakDarurat.findMany.load(); // refresh list + } else { + toast.error(result?.message || "Gagal menghapus kontak darurat"); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus kontak darurat"); + } finally { + kontakDarurat.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/kontakdarurat/${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 kontak darurat:", error); + toast.error(error instanceof Error ? error.message : "Gagal memuat data"); + return null; + } + }, + + async update() { + const cek = templateForm.safeParse(kontakDarurat.edit.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + + try { + kontakDarurat.edit.loading = true; + const response = await fetch(`/api/kesehatan/kontakdarurat/${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 || "Kontak darurat berhasil diupdate"); + await kontakDarurat.findMany.load(); + return true; + } else { + throw new Error(result.message || "Gagal update kontak darurat"); + } + } catch (error) { + console.error("Gagal update:", error); + toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat mengupdate kontak darurat"); + return false; + } finally { + kontakDarurat.edit.loading = false; + } + }, + reset() { + kontakDarurat.edit.id = ""; + kontakDarurat.edit.form = { ...defaultForm }; + }, + }, +}); + +export default kontakDarurat diff --git a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/[id]/edit/page.tsx b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/[id]/edit/page.tsx new file mode 100644 index 00000000..a69c05fc --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/[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 infoWabahPenyakit from '@/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit'; +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 EditInfoWabahPenyakit() { + const infoWabahPenyakitState = useProxy(infoWabahPenyakit) + const router = useRouter(); + const params = useParams() + + const [previewImage, setPreviewImage] = useState(null); + const [file, setFile] = useState(null); + const [formData, setFormData] = useState({ + name: infoWabahPenyakitState.edit.form.name || '', + deskripsiSingkat: infoWabahPenyakitState.edit.form.deskripsiSingkat || '', + deskripsi: infoWabahPenyakitState.edit.form.deskripsiLengkap || '', + imageId: infoWabahPenyakitState.edit.form.imageId || '', + }) + + useEffect(() => { + const loadInfoWabahPenyakit = async () => { + const id = params?.id as string; + if (!id) return; + + try { + const data = await infoWabahPenyakitState.edit.load(id); + if (data) { + setFormData({ + name: data.name || '', + deskripsiSingkat: data.deskripsiSingkat || '', + deskripsi: data.deskripsiLengkap || '', + 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"); + } + }; + + loadInfoWabahPenyakit(); + }, [params?.id]); + + const handleSubmit = async () => { + try { + infoWabahPenyakitState.edit.form = { + ...infoWabahPenyakitState.edit.form, + name: formData.name, + deskripsiSingkat: formData.deskripsiSingkat, + deskripsiLengkap: 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"); + } + + infoWabahPenyakitState.edit.form.imageId = uploaded.id; + } + + await infoWabahPenyakitState.edit.update(); + toast.success("Info wabah penyakit berhasil diperbarui!"); + router.push("/admin/kesehatan/info-wabah-penyakit"); + } catch (error) { + console.error("Error updating info wabah penyakit:", error); + toast.error("Gagal memuat data info wabah penyakit"); + } + } + return ( + + + + + + + + Edit Info Wabah Penyakit + 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 EditInfoWabahPenyakit; diff --git a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/[id]/page.tsx b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/[id]/page.tsx new file mode 100644 index 00000000..fc86ef6b --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/[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 infoWabahPenyakit from '../../../_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit'; +import { useProxy } from 'valtio/utils'; +import { useShallowEffect } from '@mantine/hooks'; +import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; + +function DetailInfoWabahPenyakit() { + const infoWabahPenyakitState = useProxy(infoWabahPenyakit) + const [modalHapus, setModalHapus] = useState(false) + const [selectedId, setSelectedId] = useState(null) + const router = useRouter(); + const params = useParams() + + useShallowEffect(() => { + infoWabahPenyakitState.findUnique.load(params?.id as string) + }, []) + + const handleHapus = () => { + if (selectedId) { + infoWabahPenyakitState.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + router.push("/admin/kesehatan/info-wabah-penyakit") + } + } + + if (!infoWabahPenyakitState.findUnique.data) { + return ( + + + + ) + } + + return ( + + + + + + + Detail Info Wabah Penyakit + {infoWabahPenyakitState.findUnique.data ? ( + + + + Judul + {infoWabahPenyakitState.findUnique.data.name} + + + Deskripsi Singkat + {infoWabahPenyakitState.findUnique.data.deskripsiSingkat} + + + Deskripsi + + + + Gambar + gambar + + + + + + + + + + ) : null} + + + + {/* Modal Hapus */} + setModalHapus(false)} + onConfirm={handleHapus} + text="Apakah anda yakin ingin menghapus info wabah penyakit ini?" + /> + + ); +} + +export default DetailInfoWabahPenyakit; diff --git a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/create/page.tsx b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/create/page.tsx index 56b212be..4fb3f039 100644 --- a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/create/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/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 infoWabahPenyakit from '../../../_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit'; function CreateInfoWabahPenyakit() { const router = useRouter(); + const infoWabahPenyakitState = useProxy(infoWabahPenyakit) + const [previewImage, setPreviewImage] = useState(null); + const [file, setFile] = useState(null); + + const resetForm = () => { + // Reset state di valtio + infoWabahPenyakitState.create.form = { + name: "", + deskripsiSingkat: "", + deskripsiLengkap: "", + 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 + infoWabahPenyakitState.create.form.imageId = uploaded.id; + + // Submit data berita + await infoWabahPenyakitState.create.create(); + + // Reset form setelah submit + resetForm(); + router.push("/admin/kesehatan/info-wabah-penyakit") + }; + return ( - + - Create Info Wabah Penyakit - { + infoWabahPenyakitState.create.form.name = val.target.value; + }} label={Judul} placeholder="masukkan judul" /> Deskripsi} + value={infoWabahPenyakitState.create.form.deskripsiSingkat} + onChange={(val) => { + infoWabahPenyakitState.create.form.deskripsiSingkat = val.target.value; + }} + label={Deskripsi Singkat} placeholder="masukkan deskripsi" /> - Kategori} - placeholder="masukkan kategori" - /> + + Deskripsi + { + infoWabahPenyakitState.create.form.deskripsiLengkap = val; + }} + /> + - {/* Upload Gambar} value={file} onChange={async (e) => { @@ -48,25 +106,18 @@ function CreateInfoWabahPenyakit() { ); setPreviewImage(base64); }} - /> */} + /> - {/* {previewImage ? ( + {previewImage ? ( ) : (
- )} */} + )} - - Konten - - - -
diff --git a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/detail/page.tsx b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/detail/page.tsx deleted file mode 100644 index 2b9163d5..00000000 --- a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/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 DetailInfoWabahPenyakit() { - const router = useRouter(); - return ( - - - - - - - Detail Info Wabah/Penyakit - - - - - Nama Info Wabah/Penyakit - Test Judul - - - Deskripsi Info Wabah/Penyakit - 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 DetailInfoWabahPenyakit; diff --git a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/edit/page.tsx b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/edit/page.tsx deleted file mode 100644 index 885ce912..00000000 --- a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/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 EditInfoWabahPenyakit() { - const router = useRouter(); - return ( - - - - - - - - - - Edit Info Wabah/Penyakit - Nama Info Wabah/Penyakit} - placeholder='Masukkan nama Info Wabah/Penyakit' - /> - Deskripsi Info Wabah/Penyakit} - placeholder='Masukkan deskripsi Info Wabah/Penyakit' - /> - - Deskripsi - - - - Gambar - gambar - - - - - - - - Preview Data Info Wabah/Penyakit - Nama Info Wabah/Penyakit - Deskripsi Info Wabah/Penyakit - Deskripsi - Gambar - - - - - - - ); -} - -export default EditInfoWabahPenyakit; diff --git a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/page.tsx b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/page.tsx index 9ce24e0f..92bc2ac6 100644 --- a/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/info-wabah-penyakit/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 { useProxy } from 'valtio/utils'; +import infoWabahPenyakit from '../../_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit'; +import { useShallowEffect } from '@mantine/hooks'; function InfoWabahPenyakit() { return ( @@ -20,7 +23,20 @@ function InfoWabahPenyakit() { } function ListInfoWabahPenyakit() { + const infoWabahPenyakitState = useProxy(infoWabahPenyakit) const router = useRouter() + + useShallowEffect(() => { + infoWabahPenyakitState.findMany.load() + }, []) + + if (!infoWabahPenyakitState.findMany.data) { + return ( + + + + ) + } return ( @@ -34,27 +50,32 @@ function ListInfoWabahPenyakit() { Judul - Kategori + Deskripsi Singkat Image Detail - - - - Test - - Test - - image - - - - - + {infoWabahPenyakitState.findMany.data?.map((item) => ( + + + + {item.name} + + + + {item.deskripsiSingkat} + + + image + + + + + + ))} diff --git a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/[id]/edit/page.tsx b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/[id]/edit/page.tsx new file mode 100644 index 00000000..dea08402 --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/kontak-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 kontakDarurat from '@/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat'; +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 EditKontakDarurat() { + const kontakDaruratState = useProxy(kontakDarurat) + const router = useRouter(); + const params = useParams() + + const [previewImage, setPreviewImage] = useState(null); + const [file, setFile] = useState(null); + const [formData, setFormData] = useState({ + name: kontakDaruratState.edit.form.name || '', + deskripsi: kontakDaruratState.edit.form.deskripsi || '', + imageId: kontakDaruratState.edit.form.imageId || '', + }) + + useEffect(() => { + const loadProgramKesehatan = async () => { + const id = params?.id as string; + if (!id) return; + + try { + const data = await kontakDaruratState.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 program kesehatan:", error); + toast.error("Gagal memuat data program kesehatan"); + } + }; + + loadProgramKesehatan(); + }, [params?.id]); + + const handleSubmit = async () => { + try { + kontakDaruratState.edit.form = { + ...kontakDaruratState.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"); + } + + kontakDaruratState.edit.form.imageId = uploaded.id; + } + + await kontakDaruratState.edit.update(); + toast.success("Kontak darurat berhasil diperbarui!"); + router.push("/admin/kesehatan/kontak-darurat"); + } catch (error) { + console.error("Error updating kontak darurat:", error); + toast.error("Gagal memuat data kontak darurat"); + } + } + return ( + + + + + + + + Edit Kontak 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 EditKontakDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/[id]/page.tsx b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/[id]/page.tsx new file mode 100644 index 00000000..cec338fa --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/[id]/page.tsx @@ -0,0 +1,99 @@ +'use client' +import colors from '@/con/colors'; +import { Box, Button, Flex, Image, Paper, Skeleton, Stack, Text } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useProxy } from 'valtio/utils'; +import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; +import kontakDarurat from '../../../_state/kesehatan/kontak-darurat/kontakDarurat'; + +function DetailKontakDarurat() { + const kontakDaruratState = useProxy(kontakDarurat) + const [modalHapus, setModalHapus] = useState(false) + const [selectedId, setSelectedId] = useState(null) + const router = useRouter(); + const params = useParams() + + useShallowEffect(() => { + kontakDaruratState.findUnique.load(params?.id as string) + }, []) + + const handleHapus = () => { + if (selectedId) { + kontakDaruratState.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + router.push("/admin/kesehatan/kontak-darurat") + } + } + + if (!kontakDaruratState.findUnique.data) { + return ( + + + + ) + } + + return ( + + + + + + + Detail Kontak Darurat + {kontakDaruratState.findUnique.data ? ( + + + + Judul + {kontakDaruratState.findUnique.data.name} + + + Deskripsi + + + + Gambar + gambar + + + + + + + + + + ) : null} + + + + {/* Modal Hapus */} + setModalHapus(false)} + onConfirm={handleHapus} + text="Apakah anda yakin ingin menghapus kontak darurat ini?" + /> + + ); +} + +export default DetailKontakDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/create/page.tsx b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/create/page.tsx index c9a9f0f3..ac55207c 100644 --- a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/create/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/create/page.tsx @@ -1,77 +1,113 @@ '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 { 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 { useProxy } from 'valtio/utils'; +import kontakDarurat from '../../../_state/kesehatan/kontak-darurat/kontakDarurat'; +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import ApiFetch from '@/lib/api-fetch'; +import CreateEditor from '../../../_com/createEditor'; + function CreateKontakDarurat() { - const router = useRouter(); - return ( - - - - - - - - Create Kontak Darurat - - Judul} - placeholder="masukkan judul" - /> - - Deskripsi} - placeholder="masukkan deskripsi" - /> - - Kategori} - placeholder="masukkan kategori" - /> - - {/* 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 ? ( - - ) : ( -
- -
- )} */} - - - Konten - - - - -
-
-
- ); +
+ + + + Create Kontak Darurat + + { + kontakDaruratState.create.form.name = val.target.value; + }} + label={Judul} + placeholder="masukkan judul" + /> + + + Deskripsi + { + kontakDaruratState.create.form.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 CreateKontakDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/detail/page.tsx b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/detail/page.tsx deleted file mode 100644 index 7ed97108..00000000 --- a/src/app/admin/(dashboard)/kesehatan/kontak-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 DetailKontakDarurat() { - const router = useRouter(); - return ( - - - - - - - Detail Kontak Darurat - - - - - Nama Kontak Darurat - Test Judul - - - Deskripsi Kontak 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 DetailKontakDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/edit/page.tsx b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/edit/page.tsx deleted file mode 100644 index e7338470..00000000 --- a/src/app/admin/(dashboard)/kesehatan/kontak-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 EditKontakDarurat() { - const router = useRouter(); - return ( - - - - - - - - - - Edit Kontak Darurat - Nama Kontak Darurat} - placeholder='Masukkan nama Kontak Darurat' - /> - Deskripsi Kontak Darurat} - placeholder='Masukkan deskripsi Kontak Darurat' - /> - - Deskripsi - - - - Gambar - gambar - - - - - - - - Preview Data Kontak Darurat - Nama Kontak Darurat - Deskripsi Kontak Darurat - Deskripsi - Gambar - - - - - - - ); -} - -export default EditKontakDarurat; diff --git a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/page.tsx b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/page.tsx index 52168304..dae268f9 100644 --- a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/page.tsx @@ -1,66 +1,88 @@ '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 kontakDarurat from '../../_state/kesehatan/kontak-darurat/kontakDarurat'; +import { useShallowEffect } from '@mantine/hooks'; function KontakDarurat() { return ( } /> - + ); } function ListKontakDarurat() { + const kontakDaruratState = useProxy(kontakDarurat) const router = useRouter(); + + useShallowEffect(() => { + kontakDaruratState.findMany.load() + }, []) + + if (!kontakDaruratState.findMany.data) { + return ( + + + + ) + } + return ( - - - - - - - - Judul - Kategori - Image - Detail - - - - - - - Test - - Test - - - - - - - - -
-
-
-
-
+ + + + + + + + Judul + Deskripsi + Image + Detail + + + + {kontakDaruratState.findMany.data?.map((item) => ( + + + + {item.name} + + + + + + + + + + + + + ))} + +
+
+
+
+ ) } diff --git a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/page.tsx b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/page.tsx index 89f2f148..51452e18 100644 --- a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/[id]/page.tsx @@ -46,7 +46,7 @@ function DetailProgramKesehatan() { - Detail Potensi + Detail Program Kesehatan {programKesehatanState.findUnique.data ? ( diff --git a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/page.tsx b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/page.tsx index 2dc2b67c..c7c6206e 100644 --- a/src/app/admin/(dashboard)/kesehatan/program-kesehatan/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/program-kesehatan/page.tsx @@ -13,7 +13,7 @@ function ProgramKesehatan() { return ( } /> diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/info-wabah-penyakit/del.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/info-wabah-penyakit/del.ts index 7d0877d2..79f87a1c 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/info-wabah-penyakit/del.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/info-wabah-penyakit/del.ts @@ -30,6 +30,9 @@ const infoWabahPenyakitDelete = async (context: Context) => { try { const filePath = path.join(infoWabahPenyakit.image.path, infoWabahPenyakit.image.name); await fs.unlink(filePath); + await prisma.fileStorage.delete({ + where: { id: infoWabahPenyakit.image.id }, + }); } catch (err) { console.error("Gagal hapus gambar:", err); } @@ -41,7 +44,8 @@ const infoWabahPenyakitDelete = async (context: Context) => { return { status: 200, - body: "Info wabah penyakit berhasil dihapus", + success: true, + message: "Penanganan darurat dan file terkait berhasil dihapus", }; }; export default infoWabahPenyakitDelete; \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/kontak-darurat/del.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/kontak-darurat/del.ts index e04d827c..c878ffa5 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/kontak-darurat/del.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/kontak-darurat/del.ts @@ -30,6 +30,9 @@ const kontakDaruratDelete = async (context: Context) => { try { const filePath = path.join(kontakDarurat.image.path, kontakDarurat.image.name); await fs.unlink(filePath); + await prisma.fileStorage.delete({ + where: { id: kontakDarurat.image.id }, + }); } catch (error) { console.error("Error deleting image file:", error); } @@ -41,7 +44,8 @@ const kontakDaruratDelete = async (context: Context) => { return { status: 200, - body: "Kontak darurat berhasil dihapus", + success: true, + message: "Kontak darurat dan file terkait berhasil dihapus", }; }; export default kontakDaruratDelete; diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/kontak-darurat/index.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/kontak-darurat/index.ts index 478b2161..a5162b83 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/kontak-darurat/index.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/kontak-darurat/index.ts @@ -12,7 +12,6 @@ const KontakDarurat = new Elysia({ .post("/create", kontakDaruratCreate, { body: t.Object({ name: t.String(), - nomor: t.String(), deskripsi: t.String(), imageId: t.String(), }) @@ -32,7 +31,6 @@ const KontakDarurat = new Elysia({ { body: t.Object({ name: t.String(), - nomor: t.String(), deskripsi: t.String(), imageId: t.String(), })