From 7bb17ddf2299235aba699067f01c3c319b9f1704 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 3 Dec 2025 17:24:03 +0800 Subject: [PATCH] Menambahkan menu dokter dan tenaga medis, admin bisa create, edit, delet dokter Menambahkan menu tarif dan layanan, admin bisa create, edit, delete tarif dan layanan Dibagian fasilitas kesehatan admin bisa multiselect bagian dokter dan tarif layanan Di tampilan user juga sudah disesuaikan dengan datanya bisa muncul lebih dari 1 dokter dan 1 tarif layanan --- prisma/schema.prisma | 59 +-- .../fasilitasKesehatan.ts | 366 +++++++++++++++--- .../desa/berita/kategori-berita/[id]/page.tsx | 2 +- .../fasilitas_kesehatan/[id]/edit/page.tsx | 309 +++++++-------- .../fasilitas_kesehatan/[id]/page.tsx | 90 ++++- .../fasilitas_kesehatan/create/page.tsx | 99 +++-- .../dokter-tenaga-medis/[id]/edit/page.tsx | 242 +++++++++++- .../dokter-tenaga-medis/[id]/page.tsx | 166 +++++++- .../dokter-tenaga-medis/create/page.tsx | 189 +++++++-- .../dokter-tenaga-medis/page.tsx | 117 ++++-- .../fasilitas_kesehatan/page.tsx | 64 ++- .../tarif-layanan/[id]/page.tsx | 173 +++++++++ .../tarif-layanan/create/page.tsx | 119 ++++++ .../tarif-layanan/page.tsx | 147 +++++-- .../fasilitas_kesehatan/create.ts | 51 +-- .../fasilitas_kesehatan/del.ts | 42 +- .../dokter-tenaga-medis/create.ts | 15 + .../dokter-tenaga-medis/findMany.ts | 1 + .../dokter-tenaga-medis/index.ts | 10 + .../dokter-tenaga-medis/updt.ts | 11 + .../fasilitas_kesehatan/index.ts | 60 ++- .../tarif-layanan/create.ts | 28 ++ .../fasilitas_kesehatan/tarif-layanan/del.ts | 37 ++ .../tarif-layanan/findMany.ts | 54 +++ .../tarif-layanan/findUnique.ts | 47 +++ .../tarif-layanan/index.ts | 30 ++ .../fasilitas_kesehatan/tarif-layanan/updt.ts | 32 ++ .../fasilitas_kesehatan/updt.ts | 54 +-- .../api/[[...slugs]]/_lib/kesehatan/index.ts | 2 + .../api/[[...slugs]]/_lib/search/findMany.ts | 72 ++-- .../fasilitas-kesehatan-page/[id]/page.tsx | 131 ++++--- .../main-page/landing-page/SosmedView.tsx | 4 +- src/app/darmasaba/_com/searchUrl.tsx | 6 +- 33 files changed, 2177 insertions(+), 652 deletions(-) create mode 100644 src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/[id]/page.tsx create mode 100644 src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/create/page.tsx create mode 100644 src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/del.ts create mode 100644 src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/findMany.ts create mode 100644 src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/findUnique.ts create mode 100644 src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/updt.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index cce83ef8..5d8b95af 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -783,24 +783,22 @@ model Penghargaan { // ========================================= FASILITAS KESEHATAN ========================================= // model FasilitasKesehatan { - id String @id @default(cuid()) - name String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - deletedAt DateTime @default(now()) - isActive Boolean @default(true) - informasiumum InformasiUmum @relation(fields: [informasiUmumId], references: [id]) - informasiUmumId String - layananunggulan LayananUnggulan @relation(fields: [layananUnggulanId], references: [id]) - layananUnggulanId String - dokterdantenagamedis DokterdanTenagaMedis @relation(fields: [dokterdanTenagaMedisId], references: [id]) - dokterdanTenagaMedisId String - fasilitaspendukung FasilitasPendukung @relation(fields: [fasilitasPendukungId], references: [id]) - fasilitasPendukungId String - prosedurpendaftaran ProsedurPendaftaran @relation(fields: [prosedurPendaftaranId], references: [id]) - prosedurPendaftaranId String - tarifdanlayanan TarifDanLayanan @relation(fields: [tarifDanLayananId], references: [id]) - tarifDanLayananId String + id String @id @default(cuid()) + name String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) + informasiumum InformasiUmum @relation(fields: [informasiUmumId], references: [id]) + informasiUmumId String + layananunggulan LayananUnggulan @relation(fields: [layananUnggulanId], references: [id]) + layananUnggulanId String + dokterdantenagamedis DokterdanTenagaMedis[] @relation("Dokter") + fasilitaspendukung FasilitasPendukung @relation(fields: [fasilitasPendukungId], references: [id]) + fasilitasPendukungId String + prosedurpendaftaran ProsedurPendaftaran @relation(fields: [prosedurPendaftaranId], references: [id]) + prosedurPendaftaranId String + tarifdanlayanan TarifDanLayanan[] @relation("Tarif") } model InformasiUmum { @@ -826,15 +824,20 @@ model LayananUnggulan { } model DokterdanTenagaMedis { - id String @id @default(cuid()) - name String - specialist String - jadwal String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - deletedAt DateTime @default(now()) - isActive Boolean @default(true) - FasilitasKesehatan FasilitasKesehatan[] + id String @id @default(cuid()) + name String + specialist String + jadwal String + jadwalLibur String + jamBukaOperasional String + jamTutupOperasional String + jamBukaLibur String + jamTutupLibur String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) + FasilitasKesehatan FasilitasKesehatan[] @relation("Dokter") } model FasilitasPendukung { @@ -865,7 +868,7 @@ model TarifDanLayanan { updatedAt DateTime @updatedAt deletedAt DateTime @default(now()) isActive Boolean @default(true) - FasilitasKesehatan FasilitasKesehatan[] + FasilitasKesehatan FasilitasKesehatan[] @relation("Tarif") } // ========================================= JADWAL KEGIATAN ========================================= // diff --git a/src/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan.ts b/src/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan.ts index 016f6b28..3aa3224e 100644 --- a/src/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan.ts +++ b/src/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan.ts @@ -9,29 +9,30 @@ import { z } from "zod"; // Validasi form const templateForm = z.object({ name: z.string().min(1, "Nama harus diisi"), + informasiUmum: z.object({ - fasilitas: z.string().min(1, "Fasilitas harus diisi"), - alamat: z.string().min(1, "Alamat harus diisi"), - jamOperasional: z.string().min(1, "Jam operasional harus diisi"), + fasilitas: z.string().min(1), + alamat: z.string().min(1), + jamOperasional: z.string().min(1), }), + layananUnggulan: z.object({ - content: z.string().min(1, "Layanan unggulan harus diisi"), - }), - dokterdanTenagaMedis: z.object({ - name: z.string().min(1, "Nama dokter harus diisi"), - specialist: z.string().min(1, "Spesialis harus diisi"), - jadwal: z.string().min(1, "Jadwal harus diisi"), + content: z.string().min(1), }), + + // NOW ARRAY OF STRING (ID) + dokterdanTenagaMedis: z.array(z.string()).min(1, "Minimal pilih 1 dokter"), + fasilitasPendukung: z.object({ - content: z.string().min(1, "Fasilitas pendukung harus diisi"), + content: z.string().min(1), }), + prosedurPendaftaran: z.object({ - content: z.string().min(1, "Prosedur pendaftaran harus diisi"), - }), - tarifDanLayanan: z.object({ - layanan: z.string().min(1, "Layanan harus diisi"), - tarif: z.string().min(1, "Tarif harus diisi"), + content: z.string().min(1), }), + + // NOW ARRAY OF STRING (ID) + tarifDanLayanan: z.array(z.string()).min(1, "Minimal pilih 1 tarif"), }); // Default form kosong @@ -45,21 +46,34 @@ const defaultForm = { layananUnggulan: { content: "", }, - dokterdanTenagaMedis: { - name: "", - specialist: "", - jadwal: "", - }, + + dokterdanTenagaMedis: [] as string[], // ← array kosong + tarifDanLayanan: [] as string[], // ← array kosong + fasilitasPendukung: { content: "", }, prosedurPendaftaran: { content: "", }, - tarifDanLayanan: { - layanan: "", - tarif: "", - }, +}; + +type DokterItem = { + id: string; + name: string; + specialist: string; + jadwal: string; + jadwalLibur: string; + jamBukaOperasional: string; + jamTutupOperasional: string; + jamBukaLibur: string; + jamTutupLibur: string; +}; + +type TarifItem = { + id: string; + layanan: string; + tarif: string; }; const fasilitasKesehatan = proxy({ @@ -186,33 +200,26 @@ const fasilitasKesehatan = proxy({ const result = await res.json(); const data = result.data; - - fasilitasKesehatan.edit.id = data.id; - fasilitasKesehatan.edit.form = { + this.id = data.id; + this.form = { name: data.name, informasiUmum: { fasilitas: data.informasiumum.fasilitas, alamat: data.informasiumum.alamat, jamOperasional: data.informasiumum.jamOperasional, }, - layananUnggulan: { - content: data.layananunggulan.content, - }, - dokterdanTenagaMedis: { - name: data.dokterdantenagamedis.name, - specialist: data.dokterdantenagamedis.specialist, - jadwal: data.dokterdantenagamedis.jadwal, - }, fasilitasPendukung: { content: data.fasilitaspendukung.content, }, prosedurPendaftaran: { content: data.prosedurpendaftaran.content, }, - tarifDanLayanan: { - layanan: data.tarifdanlayanan.layanan, - tarif: data.tarifdanlayanan.tarif, + // map relasi -> array of IDs + layananUnggulan: { + content: data.layananunggulan.content, }, + dokterdanTenagaMedis: data.dokterdantenagamedis?.map((v: DokterItem) => v.id) ?? [], + tarifDanLayanan: data.tarifdanlayanan?.map((v: TarifItem) => v.id) ?? [], }; }, async submit() { @@ -238,22 +245,15 @@ const fasilitasKesehatan = proxy({ layananUnggulan: { content: fasilitasKesehatan.edit.form.layananUnggulan.content, }, - dokterdanTenagaMedis: { - name: fasilitasKesehatan.edit.form.dokterdanTenagaMedis.name, - specialist: - fasilitasKesehatan.edit.form.dokterdanTenagaMedis.specialist, - jadwal: fasilitasKesehatan.edit.form.dokterdanTenagaMedis.jadwal, - }, + dokterdanTenagaMedis: + fasilitasKesehatan.edit.form.dokterdanTenagaMedis, fasilitasPendukung: { content: fasilitasKesehatan.edit.form.fasilitasPendukung.content, }, prosedurPendaftaran: { content: fasilitasKesehatan.edit.form.prosedurPendaftaran.content, }, - tarifDanLayanan: { - layanan: fasilitasKesehatan.edit.form.tarifDanLayanan.layanan, - tarif: fasilitasKesehatan.edit.form.tarifDanLayanan.tarif, - }, + tarifDanLayanan: fasilitasKesehatan.edit.form.tarifDanLayanan, }; const res = await fetch( @@ -320,12 +320,26 @@ const templateDokterForm = z.object({ name: z.string().min(1, "Nama tidak boleh kosong"), specialist: z.string().min(1, "Spesialis tidak boleh kosong"), jadwal: z.string().min(1, "Jadwal tidak boleh kosong"), + jadwalLibur: z.string().min(1, "Jadwal libur tidak boleh kosong"), + jamBukaOperasional: z + .string() + .min(1, "Jam buka operasional tidak boleh kosong"), + jamTutupOperasional: z + .string() + .min(1, "Jam tutup operasional tidak boleh kosong"), + jamBukaLibur: z.string().min(1, "Jam buka libur tidak boleh kosong"), + jamTutupLibur: z.string().min(1, "Jam tutup libur tidak boleh kosong"), }); const defaultDokterForm = { name: "", specialist: "", jadwal: "", + jadwalLibur: "", + jamBukaOperasional: "", + jamTutupOperasional: "", + jamBukaLibur: "", + jamTutupLibur: "", }; const dokter = proxy({ @@ -463,6 +477,11 @@ const dokter = proxy({ name: data.name, specialist: data.specialist, jadwal: data.jadwal, + jadwalLibur: data.jadwalLibur, + jamBukaOperasional: data.jamBukaOperasional, + jamTutupOperasional: data.jamTutupOperasional, + jamBukaLibur: data.jamBukaLibur, + jamTutupLibur: data.jamTutupLibur, }; return data; // Return the loaded data } else { @@ -487,6 +506,11 @@ const dokter = proxy({ name: this.form.name, specialist: this.form.specialist, jadwal: this.form.jadwal, + jadwalLibur: this.form.jadwalLibur, + jamBukaOperasional: this.form.jamBukaOperasional, + jamTutupOperasional: this.form.jamTutupOperasional, + jamBukaLibur: this.form.jamBukaLibur, + jamTutupLibur: this.form.jamTutupLibur, }; const cek = templateDokterForm.safeParse(formData); @@ -567,9 +591,255 @@ const dokter = proxy({ }, }); +const templateTarifForm = z.object({ + tarif: z.string().min(1, "Tarif tidak boleh kosong"), + layanan: z.string().min(1, "Layanan tidak boleh kosong"), +}); + +const defaultTarifForm = { + tarif: "", + layanan: "", +}; + +const tarif = proxy({ + create: { + form: defaultTarifForm, + loading: false, + async create() { + const cek = templateTarifForm.safeParse(tarif.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + try { + tarif.create.loading = true; + const res = await ApiFetch.api.kesehatan.tarifdanlayanan["create"].post( + tarif.create.form + ); + + if (res.status === 200) { + const id = res.data?.data; + if (id) { + toast.success("Sukses menambahkan"); + tarif.create.form = { ...defaultTarifForm }; + tarif.findMany.load(); + return id; + } + } + toast.error("failed create"); + return null; + } catch (error) { + console.log((error as Error).message); + return null; + } finally { + tarif.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.TarifDanLayananGetPayload<{ + omit: { + isActive: true; + }; + }>[] + | null, + page: 1, + totalPages: 1, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + tarif.findMany.loading = true; // ✅ Akses langsung via nama path + tarif.findMany.page = page; + tarif.findMany.search = search; + + try { + const query: any = { page, limit }; + if (search) query.search = search; + + const res = await ApiFetch.api.kesehatan.tarifdanlayanan[ + "findMany" + ].get({ query }); + + if (res.status === 200 && res.data?.success) { + tarif.findMany.data = res.data.data ?? []; + tarif.findMany.totalPages = res.data.totalPages ?? 1; + } else { + tarif.findMany.data = []; + tarif.findMany.totalPages = 1; + } + } catch (err) { + console.error("Gagal fetch tarif dan layanan paginated:", err); + tarif.findMany.data = []; + tarif.findMany.totalPages = 1; + } finally { + tarif.findMany.loading = false; + } + }, + }, + findUnique: { + data: null as Prisma.TarifDanLayananGetPayload<{ + omit: { isActive: true }; + }> | null, + async load(id: string) { + try { + const res = await fetch(`/api/kesehatan/tarifdanlayanan/${id}`); + if (res.ok) { + const data = await res.json(); + tarif.findUnique.data = data.data ?? null; + } else { + console.error( + "Failed to fetch tarif dan layanan", + res.statusText + ); + tarif.findUnique.data = null; + } + } catch (error) { + console.error("Error fetching tarif dan layanan", error); + tarif.findUnique.data = null; + } + }, + }, + update: { + id: "", + form: { ...defaultTarifForm }, + loading: false, + async load(id: string) { + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + try { + const response = await fetch(`/api/kesehatan/tarifdanlayanan/${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 = { + tarif: data.tarif, + layanan: data.layanan + }; + return data; // Return the loaded data + } else { + throw new Error(result?.message || "Gagal memuat data"); + } + } catch (error) { + console.error("Error loading tarif dan layanan:", error); + toast.error( + error instanceof Error ? error.message : "Gagal memuat data" + ); + return null; + } + }, + async submit() { + const id = this.id; + if (!id) { + toast.warn("ID tidak valid"); + return null; + } + + const formData = { + tarif: this.form.tarif, + layanan: this.form.layanan + }; + + const cek = templateTarifForm.safeParse(formData); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v: any) => `${v.path.join(".")}`) + .join("\n")}] required`; + toast.error(err); + return null; + } + + try { + this.loading = true; + const res = await fetch(`/api/kesehatan/tarifdanlayanan/${id}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + }); + + const result = await res.json(); + + if (!res.ok || !result?.success) { + throw new Error(result?.message || "Gagal update data"); + } + + toast.success("Berhasil update data!"); + await tarif.findMany.load(); + return result.data; + } catch (error) { + console.error("Update error:", error); + toast.error("Gagal update data tarif dan layanan"); + throw error; + } finally { + this.loading = false; + } + }, + }, + delete: { + loading: false, + async byId(id: string) { + if (!id) { + return toast.warn("ID tidak valid"); + } + try { + tarif.delete.loading = true; + + const response = await fetch( + `/api/kesehatan/tarifdanlayanan/del/${id}`, + { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + } + ); + + const result = await response.json(); + + if (response.ok && result?.success) { + toast.success( + result.message || "tarif dan layanan berhasil dihapus" + ); + await tarif.findMany.load(); // refresh list + } else { + toast.error( + result?.message || "Gagal menghapus tarif dan layanan" + ); + } + } catch (error) { + console.error("Gagal delete:", error); + toast.error("Terjadi kesalahan saat menghapus tarif dan layanan"); + } finally { + tarif.delete.loading = false; + } + }, + }, +}); + const fasilitasKesehatanState = proxy({ fasilitasKesehatan, dokter, + tarif }); export default fasilitasKesehatanState; diff --git a/src/app/admin/(dashboard)/desa/berita/kategori-berita/[id]/page.tsx b/src/app/admin/(dashboard)/desa/berita/kategori-berita/[id]/page.tsx index 2e86057b..4924f9e6 100644 --- a/src/app/admin/(dashboard)/desa/berita/kategori-berita/[id]/page.tsx +++ b/src/app/admin/(dashboard)/desa/berita/kategori-berita/[id]/page.tsx @@ -111,7 +111,7 @@ function EditKategoriBerita() { {/* Form Wrapper */} (); const [isSubmitting, setIsSubmitting] = useState(false); - const [formData, setFormData] = useState({ + const [formData, setFormData] = useState({ name: '', informasiUmum: { fasilitas: '', alamat: '', jamOperasional: '' }, layananUnggulan: { content: '' }, - dokterdanTenagaMedis: { name: '', specialist: '', jadwal: '' }, + dokterdanTenagaMedis: [], fasilitasPendukung: { content: '' }, prosedurPendaftaran: { content: '' }, - tarifDanLayanan: { layanan: '', tarif: '' }, + tarifDanLayanan: [], }); - const [originalData, setOriginalData] = useState({ - name: '', - informasiUmum: { fasilitas: '', alamat: '', jamOperasional: '' }, - layananUnggulan: { content: '' }, - dokterdanTenagaMedis: { name: '', specialist: '', jadwal: '' }, - fasilitasPendukung: { content: '' }, - prosedurPendaftaran: { content: '' }, - tarifDanLayanan: { layanan: '', tarif: '' }, - }); + // Load data fasilitas & daftar dokter/tarif + useShallowEffect(() => { + const loadAll = async () => { + const id = params?.id; + if (!id) return; - // Helper untuk update nested state - const updateForm = ( - key: K, - value: FasilitasKesehatanFormBase[K] - ) => setFormData(prev => ({ ...prev, [key]: value })); + // Load dokter & tarif (untuk opsi MultiSelect) + await Promise.all([ + dokterState.findMany.load(), + tarifState.findMany.load(), + ]); - const updateNested = < - K extends keyof FasilitasKesehatanFormBase, - N extends keyof FasilitasKesehatanFormBase[K] - >(key: K, nestedKey: N, value: FasilitasKesehatanFormBase[K][N]) => - setFormData(prev => ({ - ...prev, - [key]: { ...prev[key] as object, [nestedKey]: value }, - })); + // Load data fasilitas + await state.edit.load(id); + const loaded = state.edit.form; + if (loaded) { + setFormData({ + name: loaded.name, + informasiUmum: loaded.informasiUmum, + layananUnggulan: loaded.layananUnggulan, + dokterdanTenagaMedis: loaded.dokterdanTenagaMedis || [], + fasilitasPendukung: loaded.fasilitasPendukung, + prosedurPendaftaran: loaded.prosedurPendaftaran, + tarifDanLayanan: loaded.tarifDanLayanan || [], + }); + } + }; - const deepClone = (obj: any): any => { - try { - return JSON.parse(JSON.stringify(obj)); - } catch (error) { - console.warn('Gagal deep clone dengan JSON fallback:', error); - return obj; // fallback (berisiko shared reference) + loadAll(); + }, [params?.id]); + + const updateForm = ( + field: K, + value: EditFasilitasKesehatanForm[K] + ) => { + setFormData(prev => ({ ...prev, [field]: value })); + }; + + const handleReset = () => { + const loaded = state.edit.form; + if (loaded) { + setFormData({ + name: loaded.name, + informasiUmum: loaded.informasiUmum, + layananUnggulan: loaded.layananUnggulan, + dokterdanTenagaMedis: loaded.dokterdanTenagaMedis || [], + fasilitasPendukung: loaded.fasilitasPendukung, + prosedurPendaftaran: loaded.prosedurPendaftaran, + tarifDanLayanan: loaded.tarifDanLayanan || [], + }); + toast.info('Form dikembalikan ke data awal'); } }; - // Load data - useEffect(() => { - const load = async () => { - const id = params?.id as string; - if (!id) return; - - try { - await state.edit.load(id); - const loadedData = state.edit.form; - - if (!loadedData) { - toast.error('Data tidak ditemukan'); - return; - } - - // Gunakan JSON fallback untuk deep clone - const clonedData = deepClone(loadedData) as FasilitasKesehatanFormBase; - - setFormData(clonedData); - setOriginalData(clonedData); - } catch (err) { - console.error(err); - toast.error('Gagal memuat data fasilitas kesehatan'); - } - }; - - load(); - }, [params?.id]); - - const handleResetForm = () => { - setFormData({ - name: originalData.name, - informasiUmum: - { - fasilitas: originalData.informasiUmum.fasilitas, - alamat: originalData.informasiUmum.alamat, - jamOperasional: originalData.informasiUmum.jamOperasional - }, - layananUnggulan: { content: originalData.layananUnggulan.content }, - dokterdanTenagaMedis: { - name: originalData.dokterdanTenagaMedis.name, - specialist: originalData.dokterdanTenagaMedis.specialist, - jadwal: originalData.dokterdanTenagaMedis.jadwal - }, - fasilitasPendukung: { content: originalData.fasilitasPendukung.content }, - prosedurPendaftaran: { content: originalData.prosedurPendaftaran.content }, - tarifDanLayanan: { - layanan: originalData.tarifDanLayanan.layanan, - tarif: originalData.tarifDanLayanan.tarif - }, - }); - toast.info("Form dikembalikan ke data awal"); - }; - - // Submit - const handleSubmit = async () => { + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); try { setIsSubmitting(true); - state.edit.form = { ...state.edit.form, ...formData }; + + // Update state Valtio + state.edit.form = { ...formData }; + const success = await state.edit.submit(); if (success) { toast.success('Fasilitas kesehatan berhasil diperbarui!'); @@ -159,14 +124,14 @@ function EditFasilitasKesehatan() { } } catch (err) { console.error(err); - toast.error('Terjadi kesalahan saat memperbarui data fasilitas kesehatan'); + toast.error('Gagal memperbarui data'); } finally { setIsSubmitting(false); } }; return ( - + {/* Header */} - - {/* Tombol Simpan */} + + Edit Fasilitas Kesehatan + + + + {/* Form */} + + + handleChange("name", e.target.value)} + required + /> + + handleChange("jadwal", e.target.value)} + required + /> + + handleChange("jadwalLibur", e.target.value)} + required + /> + + handleChange("jamBukaOperasional", e.target.value)} + required + /> + + handleChange("jamTutupOperasional", e.target.value)} + required + /> + + handleChange("jamBukaLibur", e.target.value)} + required + /> + + handleChange("jamTutupLibur", e.target.value)} + required + /> + {/* Tombol Simpan */} + + {/* Tombol Batal */} + + + {/* Tombol Simpan */} + + + + + ); } -export default Page; +export default EditDokterTenagaMedis; diff --git a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/[id]/page.tsx b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/[id]/page.tsx index 69da2f21..8add7c1c 100644 --- a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/[id]/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/[id]/page.tsx @@ -1,11 +1,165 @@ -import React from 'react'; +'use client' +import { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus'; +import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan'; +import colors from '@/con/colors'; +import { + Box, + Button, + Group, + Paper, + Skeleton, + Stack, + Text +} from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { IconArrowBack, IconEdit, IconTrash } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useProxy } from 'valtio/utils'; + +function DetailDokterTenagaMedis() { + const params = useParams(); + const router = useRouter(); + const state = useProxy(fasilitasKesehatanState.dokter); + const [modalHapus, setModalHapus] = useState(false); + const [selectedId, setSelectedId] = useState(null); + + useShallowEffect(() => { + state.findUnique.load(params?.id as string); + }, []); + + const handleHapus = () => { + if (selectedId) { + state.delete.byId(selectedId); + setModalHapus(false); + setSelectedId(null); + router.push( + '/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis' + ); + } + }; + + if (!state.findUnique.data) { + return ( + + + + ); + } + + const data = state.findUnique.data; -function Page() { return ( -
- Page -
+ + {/* Tombol Back */} + + + {/* Wrapper Detail */} + + + + Detail Dokter & Tenaga Medis + + + + + + Nama Dokter + {data.name || '-'} + + + + Specialist + {data.specialist || '-'} + + + + Jadwal + + + + + Jadwal Libur + + + + + Jam Buka Operasional + + + + + Jam Tutup Operasional + + + + + Jam Buka Libur + + + + + Jam Tutup Libur + + + + {/* Aksi */} + + + + + + + + + + + {/* Modal Konfirmasi Hapus */} + setModalHapus(false)} + onConfirm={handleHapus} + text="Apakah anda yakin ingin menghapus dokter & tenaga medis ini?" + /> + ); } -export default Page; +export default DetailDokterTenagaMedis; diff --git a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/create/page.tsx b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/create/page.tsx index 3e33d305..ed4a1081 100644 --- a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/create/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/create/page.tsx @@ -1,71 +1,184 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' -import CreateEditor from '@/app/admin/(dashboard)/_com/createEditor'; import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan'; import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; -import { IconArrowBack } from '@tabler/icons-react'; -import { useParams, useRouter } from 'next/navigation'; +import { ActionIcon, Box, Button, Group, Loader, Paper, Stack, TextInput, Title } from '@mantine/core'; +import { TimeInput } from '@mantine/dates'; +import { IconArrowBack, IconClock } from '@tabler/icons-react'; +import { useRouter } from 'next/navigation'; +import { useRef, useState } from 'react'; +import { toast } from 'react-toastify'; import { useProxy } from 'valtio/utils'; function CreateDokter() { - const params = useParams() const createState = useProxy(fasilitasKesehatanState.dokter) const router = useRouter(); + const [isSubmitting, setIsSubmitting] = useState(false); const resetForm = () => { createState.create.create.form = { name: "", specialist: "", jadwal: "", + jadwalLibur: "", + jamBukaOperasional: "", + jamTutupOperasional: "", + jamBukaLibur: "", + jamTutupLibur: "", }; }; + const refBuka = useRef(null); + const refTutup = useRef(null); + const refBukaLibur = useRef(null); + const refTutupLibur = useRef(null); + + const picker = (ref: any) => ( + ref.current?.showPicker()}> + + + ); + + const handleSubmit = async () => { - await createState.create.create.create(); - resetForm(); - router.push(`/admin/kesehatan/fasilitas-kesehatan/${params?.id}/dokter-tenaga-medis`) + try { + setIsSubmitting(true); + await createState.create.create.create(); + toast.success('Data berhasil disimpan'); + resetForm(); + router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis`) + } catch (error) { + console.error(error); + toast.error('Gagal menyimpan data'); + } finally { + setIsSubmitting(false); + } }; return ( - - - - + + Tambah Data Dokter & Tenaga Medis + + - - - Create Dokter + {/* Form */} + + Nama Dokter} - placeholder="masukkan nama dokter" + label={"Nama Dokter"} + placeholder="Masukkan nama dokter" value={createState.create.create.form.name} - onChange={(e) => { - createState.create.create.form.name = e.target.value; - }} + onChange={(e) => (createState.create.create.form.name = e.target.value)} + required /> - Specialist + + {/* Informasi Umum */} + Specialist} - placeholder="masukkan specialist" + label="Specialist" + placeholder="Masukkan specialist" value={createState.create.create.form.specialist} - onChange={(e) => { - createState.create.create.form.specialist = e.target.value; - }} + onChange={(e) => (createState.create.create.form.specialist = e.target.value)} + required /> - - Jadwal - { - createState.create.create.form.jadwal = htmlContent; + + (createState.create.create.form.jadwal = e.target.value)} + required + /> + + (createState.create.create.form.jadwalLibur = e.target.value)} + required + /> + + (createState.create.create.form.jamBukaOperasional = e.target.value)} + required + /> + + (createState.create.create.form.jamTutupOperasional = e.target.value)} + required + /> + + (createState.create.create.form.jamBukaLibur = e.target.value)} + required + /> + + (createState.create.create.form.jamTutupLibur = e.target.value)} + required + /> + + {/* Submit */} + + {/* Tombol Batal */} + + + {/* Tombol Simpan */} + + > + {isSubmitting ? : 'Simpan'} + + diff --git a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/page.tsx b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/page.tsx index 94a1ad90..87957722 100644 --- a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/page.tsx @@ -1,13 +1,12 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; +import { Box, Button, Center, Group, Pagination, Paper, Skeleton, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconArrowBack, IconDeviceImacCog, IconSearch } from '@tabler/icons-react'; +import { IconArrowBack, IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '@/app/admin/(dashboard)/_com/header'; -import JudulList from '@/app/admin/(dashboard)/_com/judulList'; import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan'; import { useState } from 'react'; @@ -18,7 +17,7 @@ function DokterTenagaMedis() { return ( - @@ -60,49 +59,101 @@ function ListDokterTenagaMedis({ search }: { search: string }) { } return ( - - - - - - - - Fasilitas Kesehatan - Alamat - Jam Operasional - Detail - - - - {filteredData.map((item) => ( + + {/* Judul + Tombol Tambah */} + + Daftar Dokter dan Tenaga Medis + + + + {/* Tabel */} + +
+ + + Nama Dokter + Spesialis + Jadwal + Aksi + + + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( - {item.name} - {item.specialist} - + + + {item.name} + + - - ))} - -
-
-
+ )) + ) : ( + + +
+ + Tidak ada fasilitas kesehatan yang cocok + +
+
+
+ )} + + +
+ + {/* Pagination */}
load(newPage)} // ini penting! + onChange={(newPage) => { + load(newPage, 10, search); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} total={totalPages} mt="md" mb="md" + color="blue" + radius="md" />
diff --git a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/page.tsx b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/page.tsx index be757981..5943590e 100644 --- a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/page.tsx @@ -1,9 +1,12 @@ 'use client' import colors from '@/con/colors'; import { + ActionIcon, Box, Button, Center, + Grid, + GridCol, Group, Pagination, Paper, @@ -16,30 +19,52 @@ import { TableThead, TableTr, Text, - Title + TextInput, + Title, + Tooltip } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react'; +import { IconCoin, IconDeviceImacCog, IconPlus, IconReportMedical, IconSearch } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { useProxy } from 'valtio/utils'; -import HeaderSearch from '../../../_com/header'; import fasilitasKesehatanState from '../../../_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan'; function FasilitasKesehatan() { const [search, setSearch] = useState(""); - + const router = useRouter() return ( - {/* Header Search */} - } - value={search} - onChange={(e) => setSearch(e.currentTarget.value)} - /> + + + Fasilitas Kesehatan + + + + + router.push('/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis')} size="lg" radius="xl" color="green.6"> + + + + + router.push('/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan')} size="lg" radius="xl" color="blue.6"> + + + + + } + w="133%" + value={search} + onChange={(e) => setSearch(e.currentTarget.value)} + /> + + + + @@ -54,6 +79,7 @@ function ListFasilitasKesehatan({ search }: { search: string }) { const { data, page, totalPages, loading, load } = stateFasilitasKesehatan.findMany; useShallowEffect(() => { + load(page, 10, search); }, [page, search]); @@ -93,8 +119,8 @@ function ListFasilitasKesehatan({ search }: { search: string }) { Fasilitas Kesehatan - Dokter - Layanan + Jumlah Dokter + Jumlah Layanan Aksi @@ -111,13 +137,17 @@ function ListFasilitasKesehatan({ search }: { search: string }) { - {item.dokterdantenagamedis?.name || '-'} + {item.dokterdantenagamedis?.length + ? `${item.dokterdantenagamedis.length} dokter` + : '-'} - {item.tarifdanlayanan?.layanan || '-'} + {item.tarifdanlayanan?.length + ? `${item.tarifdanlayanan.length} layanan` + : '-'} @@ -141,7 +171,7 @@ function ListFasilitasKesehatan({ search }: { search: string }) {
- + Tidak ada fasilitas kesehatan yang cocok
diff --git a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/[id]/page.tsx b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/[id]/page.tsx new file mode 100644 index 00000000..7ff34a37 --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/[id]/page.tsx @@ -0,0 +1,173 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' + +import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan'; +import colors from '@/con/colors'; +import { + Box, + Button, + Group, + Loader, + Paper, + Stack, + TextInput, + Title +} from '@mantine/core'; +import { IconArrowBack } from '@tabler/icons-react'; +import { useParams, useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; + +function EditTarifLayanan() { + const editState = useProxy(fasilitasKesehatanState.tarif); + const router = useRouter(); + const params = useParams(); + const [isSubmitting, setIsSubmitting] = useState(false); + + const [originalData, setOriginalData] = useState({ + tarif: '', + layanan: '' + }); + + const [formData, setFormData] = useState({ + tarif: '', + layanan: '' + }); + + useEffect(() => { + const loadTarifLayanan = async () => { + const id = params?.id as string; + if (!id) return; + + try { + const data = await editState.update.load(id); + if (data) { + setFormData({ + tarif: data.tarif || '', + layanan: data.layanan || '', + }); + setOriginalData({ + tarif: data.tarif || '', + layanan: data.layanan || '', + }); + } + } catch (error) { + console.error('Error loading tarif layanan:', error); + toast.error('Gagal memuat data tarif layanan'); + } + }; + + loadTarifLayanan(); + }, [params?.id]); + + const handleChange = (field: string, value: string) => { + setFormData((prev) => ({ ...prev, [field]: value })); + }; + + const handleResetForm = () => { + setFormData({ + tarif: originalData.tarif, + layanan: originalData.layanan, + }); + toast.info('Form dikembalikan ke data awal'); + }; + + const handleSubmit = async () => { + try { + setIsSubmitting(true); + // update global state hanya saat submit + editState.update.form = { + ...editState.update.form, + tarif: formData.tarif, + layanan: formData.layanan, + }; + + await editState.update.submit(); + toast.success('Tarif Layanan berhasil diperbarui!'); + router.push('/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan'); + } catch (error) { + console.error('Error updating tarif layanan:', error); + toast.error('Terjadi kesalahan saat memperbarui tarif layanan'); + } finally { + setIsSubmitting(false); + } + }; + + return ( + + {/* Back Button + Title */} + + + + Edit Tarif Layanan + + + + {/* Form Wrapper */} + + + handleChange('layanan', e.target.value)} + required + /> + + handleChange('tarif', e.target.value)} + required + /> + + + + + {/* Tombol Simpan */} + + + + + + ); +} + +export default EditTarifLayanan; diff --git a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/create/page.tsx b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/create/page.tsx new file mode 100644 index 00000000..60d23e1f --- /dev/null +++ b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/create/page.tsx @@ -0,0 +1,119 @@ +'use client'; +import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan'; +import colors from '@/con/colors'; +import { + Box, + Button, + Group, + Loader, + Paper, + Stack, + TextInput, + Title +} from '@mantine/core'; +import { IconArrowBack } from '@tabler/icons-react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; + +function CreateTarifLayanan() { + const createState = useProxy(fasilitasKesehatanState.tarif); + const router = useRouter(); + const [isSubmitting, setIsSubmitting] = useState(false); + + const resetForm = () => { + createState.create.form = { + tarif: '', + layanan: '', + }; + }; + + const handleSubmit = async () => { + setIsSubmitting(true); + try { + await createState.create.create(); + resetForm(); + router.push('/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan'); + } catch (error) { + console.error('Error creating tarif layanan:', error); + toast.error('Gagal menambahkan tarif layanan'); + } finally { + setIsSubmitting(false); + } + }; + + return ( + + {/* Header dengan back button */} + + + + Tambah Tarif Layanan + + + + {/* Form utama */} + + + (createState.create.form.layanan = e.target.value)} + required + /> + (createState.create.form.tarif = e.target.value)} + required + /> + + + + + {/* Tombol Simpan */} + + + + + + ); +} + +export default CreateTarifLayanan; diff --git a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/page.tsx b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/page.tsx index eb82a5f9..844dc2c2 100644 --- a/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan/page.tsx @@ -1,13 +1,13 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; +import { Box, Button, Center, Group, Pagination, Paper, Skeleton, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconArrowBack, IconDeviceImacCog, IconSearch } from '@tabler/icons-react'; +import { IconArrowBack, IconEdit, IconPlus, IconSearch, IconTrash } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '@/app/admin/(dashboard)/_com/header'; -import JudulList from '@/app/admin/(dashboard)/_com/judulList'; +import { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus'; import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan'; import { useState } from 'react'; @@ -18,12 +18,12 @@ function TarifLayanan() { return ( - } value={search} @@ -35,8 +35,11 @@ function TarifLayanan() { } function ListTarifLayanan({ search }: { search: string }) { - const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState.dokter) + const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState.tarif); const router = useRouter(); + const [modalHapus, setModalHapus] = useState(false); + const [selectedId, setSelectedId] = useState(null); + const { data, loading, @@ -49,6 +52,15 @@ function ListTarifLayanan({ search }: { search: string }) { load(page, 10, search) }, [page, search]) + const handleDelete = () => { + if (selectedId) { + stateFasilitasKesehatan.delete.byId(selectedId); + setModalHapus(false); + setSelectedId(null); + load(page, 10, search); + } + }; + const filteredData = data || [] if (loading || !data) { @@ -60,51 +72,116 @@ function ListTarifLayanan({ search }: { search: string }) { } return ( - - - - - - - - Fasilitas Kesehatan - Alamat - Jam Operasional - Detail - - - - {filteredData.map((item) => ( + + {/* Judul + Tombol Tambah */} + + Daftar Tarif dan Layanan + + + + {/* Tabel */} + +
+ + + Layanan + Tarif + Edit + Hapus + + + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( - {item.name} - {item.specialist} - + + {item.layanan || '-'} + - + + + - ))} - -
-
-
+ )) + ) : ( + + +
+ + Tidak ada fasilitas kesehatan yang cocok + +
+
+
+ )} + + +
+ + {/* Pagination */}
load(newPage)} // ini penting! + onChange={(newPage) => { + load(newPage, 10, search); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} total={totalPages} mt="md" mb="md" + color="blue" + radius="md" />
+ setModalHapus(false)} + onConfirm={handleDelete} + text="Apakah anda yakin ingin menghapus tarif layanan ini?" + />
) } diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/create.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/create.ts index 479a61cf..820771ce 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/create.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/create.ts @@ -1,18 +1,16 @@ import prisma from "@/lib/prisma"; import { Context } from "elysia"; -type FasilitasKesehatanInput = { - name: string; - informasiUmum: { fasilitas: string; alamat: string; jamOperasional: string }; - layananUnggulan: { content: string }; - dokterdanTenagaMedis: { name: string; specialist: string; jadwal: string }; - fasilitasPendukung: { content: string }; - prosedurPendaftaran: { content: string }; - tarifDanLayanan: { layanan: string; tarif: string }; -}; - const fasilitasKesehatanCreate = async (context: Context) => { - const body = await context.body as FasilitasKesehatanInput; + const body = (await context.body) as { + name: string; + informasiUmum: { fasilitas: string; alamat: string; jamOperasional: string }; + layananUnggulan: { content: string }; + dokterdanTenagaMedis: string[]; // ← ARRAY OF ID + fasilitasPendukung: { content: string }; + prosedurPendaftaran: { content: string }; + tarifDanLayanan: string[]; // ← ARRAY OF ID + }; const { name, @@ -24,25 +22,30 @@ const fasilitasKesehatanCreate = async (context: Context) => { tarifDanLayanan, } = body; - // Buat masing-masing relasi terlebih dahulu - const [createdInformasiUmum, createdLayananUnggulan, createdDokter, createdPendukung, createdProsedur, createdTarif] = await Promise.all([ - prisma.informasiUmum.create({ data: informasiUmum }), - prisma.layananUnggulan.create({ data: layananUnggulan }), - prisma.dokterdanTenagaMedis.create({ data: dokterdanTenagaMedis }), - prisma.fasilitasPendukung.create({ data: fasilitasPendukung }), - prisma.prosedurPendaftaran.create({ data: prosedurPendaftaran }), - prisma.tarifDanLayanan.create({ data: tarifDanLayanan }), - ]); + // CREATE SINGLE DATA + const [createdInformasi, createdUnggulan, createdPendukung, createdProsedur] = + await Promise.all([ + prisma.informasiUmum.create({ data: informasiUmum }), + prisma.layananUnggulan.create({ data: layananUnggulan }), + prisma.fasilitasPendukung.create({ data: fasilitasPendukung }), + prisma.prosedurPendaftaran.create({ data: prosedurPendaftaran }), + ]); + // ✅ CUKUP CONNECT KE ID YANG SUDAH ADA const fasilitas = await prisma.fasilitasKesehatan.create({ data: { name, - informasiUmumId: createdInformasiUmum.id, - layananUnggulanId: createdLayananUnggulan.id, - dokterdanTenagaMedisId: createdDokter.id, + informasiUmumId: createdInformasi.id, + layananUnggulanId: createdUnggulan.id, fasilitasPendukungId: createdPendukung.id, prosedurPendaftaranId: createdProsedur.id, - tarifDanLayananId: createdTarif.id, + + dokterdantenagamedis: { + connect: dokterdanTenagaMedis.map(id => ({ id })), // ← langsung dari input + }, + tarifdanlayanan: { + connect: tarifDanLayanan.map(id => ({ id })), // ← langsung dari input + }, }, include: { informasiumum: true, diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/del.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/del.ts index 349c46ce..4096558b 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/del.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/del.ts @@ -2,42 +2,14 @@ import prisma from "@/lib/prisma"; import { Context } from "elysia"; const fasilitasKesehatanDelete = async (context: Context) => { - const id = context.params?.id as string; + const id = context.params?.id as string; - if (!id) { - return { - status: 400, - message: "ID tidak ditemukan", - } - } + const data = await prisma.fasilitasKesehatan.findUnique({ where: { id } }); + if (!data) return { status: 404, message: "Data tidak ditemukan" }; - const fasilitasKesehatan = await prisma.fasilitasKesehatan.findUnique({ - where: { id }, - include: { - informasiumum: true, - layananunggulan: true, - dokterdantenagamedis: true, - fasilitaspendukung: true, - prosedurpendaftaran: true, - tarifdanlayanan: true, - } - }) + await prisma.fasilitasKesehatan.delete({ where: { id } }); - if (!fasilitasKesehatan) { - return { - status: 404, - message: "Fasilitas kesehatan tidak ditemukan", - } - } + return { success: true, message: "Berhasil dihapus" }; +}; - await prisma.fasilitasKesehatan.delete({ - where: { id }, - }) - - return { - status: 200, - success: true, - message: "Fasilitas kesehatan berhasil dihapus", - } -} -export default fasilitasKesehatanDelete \ No newline at end of file +export default fasilitasKesehatanDelete; diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/create.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/create.ts index 4852439d..19cf9c05 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/create.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/create.ts @@ -5,6 +5,11 @@ type FormCreate = { name: string; specialist: string; jadwal: string; + jadwalLibur: string; + jamBukaOperasional: string; + jamTutupOperasional: string; + jamBukaLibur: string; + jamTutupLibur: string; }; export default async function dokterTenagaMedisCreate(context: Context) { @@ -15,11 +20,21 @@ export default async function dokterTenagaMedisCreate(context: Context) { name: body.name, specialist: body.specialist, jadwal: body.jadwal, + jadwalLibur: body.jadwalLibur, + jamBukaOperasional: body.jamBukaOperasional, + jamTutupOperasional: body.jamTutupOperasional, + jamBukaLibur: body.jamBukaLibur, + jamTutupLibur: body.jamTutupLibur, }, select: { name: true, specialist: true, jadwal: true, + jadwalLibur: true, + jamBukaOperasional: true, + jamTutupOperasional: true, + jamBukaLibur: true, + jamTutupLibur: true, } }); diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/findMany.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/findMany.ts index 0e9ce6dd..ad250062 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/findMany.ts @@ -19,6 +19,7 @@ async function dokterTenagaMedisFindMany(context: Context) { { name: { contains: search, mode: 'insensitive' } }, { specialist: { contains: search, mode: 'insensitive' } }, { jadwal: { contains: search, mode: 'insensitive' } }, + { jadwalLibur: { contains: search, mode: 'insensitive' } }, ]; } diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/index.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/index.ts index b0c4760a..58817969 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/index.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/index.ts @@ -19,6 +19,11 @@ const DokterTenagaMedis = new Elysia({ name: t.String(), specialist: t.String(), jadwal: t.String(), + jadwalLibur: t.String(), + jamBukaOperasional: t.String(), + jamTutupOperasional: t.String(), + jamBukaLibur: t.String(), + jamTutupLibur: t.String(), }), }) .put("/:id", dokterTenagaMedisUpdate, { @@ -26,6 +31,11 @@ const DokterTenagaMedis = new Elysia({ name: t.String(), specialist: t.String(), jadwal: t.String(), + jadwalLibur: t.String(), + jamBukaOperasional: t.String(), + jamTutupOperasional: t.String(), + jamBukaLibur: t.String(), + jamTutupLibur: t.String(), }), }) .delete("/del/:id", dokterTenagaMedisDelete) diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/updt.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/updt.ts index 6db6b37d..68422677 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/updt.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis/updt.ts @@ -5,6 +5,11 @@ type FormUpdate = { name: string; specialist: string; jadwal: string; + jadwalLibur: string; + jamBukaOperasional: string; + jamTutupOperasional: string; + jamBukaLibur: string; + jamTutupLibur: string; } export default async function dokterTenagaMedisUpdate(context: Context) { @@ -18,6 +23,12 @@ export default async function dokterTenagaMedisUpdate(context: Context) { name: body.name, specialist: body.specialist, jadwal: body.jadwal, + jadwalLibur: body.jadwalLibur, + jamBukaOperasional: body.jamBukaOperasional, + jamTutupOperasional: body.jamTutupOperasional, + jamBukaLibur: body.jamBukaLibur, + jamTutupLibur: body.jamTutupLibur, + }, }); return { diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/index.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/index.ts index 1eb5badd..e49ce73c 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/index.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/index.ts @@ -1,6 +1,6 @@ import { Elysia, t } from "elysia"; import fasilitasKesehatanCreate from "./create"; -import findManyFasilitasKesehatan from "./findMany"; +import fasilitasKesehatanFindMany from "./findMany"; import findUniqueFasilitasKesehatan from "./findUnique"; import fasilitasKesehatanUpdate from "./updt"; import fasilitasKesehatanDelete from "./del"; @@ -9,42 +9,61 @@ const FasilitasKesehatan = new Elysia({ prefix: "fasilitas-kesehatan", tags: ["Kesehatan/Fasilitas Kesehatan"], }) + + // ========================== + // CREATE + // ========================== .post("/create", fasilitasKesehatanCreate, { body: t.Object({ name: t.String(), + informasiUmum: t.Object({ fasilitas: t.String(), alamat: t.String(), jamOperasional: t.String(), }), + layananUnggulan: t.Object({ content: t.String(), }), - dokterdanTenagaMedis: t.Object({ - name: t.String(), - specialist: t.String(), - jadwal: t.String(), - }), + + dokterdanTenagaMedis: t.Array(t.String()), // FIX karena create pakai array of string + fasilitasPendukung: t.Object({ content: t.String(), }), + prosedurPendaftaran: t.Object({ content: t.String(), }), - tarifDanLayanan: t.Object({ - layanan: t.String(), - tarif: t.String(), - }), + + tarifDanLayanan: t.Array(t.String()), // FIX karena create pakai array of string }), }) - .get("/find-many", findManyFasilitasKesehatan) + + // ========================== + // FIND MANY + // ========================== + .get("/find-many", fasilitasKesehatanFindMany) + + // ========================== + // DELETE + // ========================== .delete("/del/:id", fasilitasKesehatanDelete) + + // ========================== + // FIND UNIQUE + // ========================== .get("/:id", async (context) => { const response = await findUniqueFasilitasKesehatan( new Request(context.request) ); return response; }) + + // ========================== + // UPDATE + // ========================== .put( "/:id", async (context) => { @@ -54,29 +73,30 @@ const FasilitasKesehatan = new Elysia({ { body: t.Object({ name: t.String(), + informasiUmum: t.Object({ fasilitas: t.String(), alamat: t.String(), jamOperasional: t.String(), }), + layananUnggulan: t.Object({ content: t.String(), }), - dokterdanTenagaMedis: t.Object({ - name: t.String(), - specialist: t.String(), - jadwal: t.String(), - }), + + // FIX → harus array of string (ID dokter) + dokterdanTenagaMedis: t.Array(t.String()), + fasilitasPendukung: t.Object({ content: t.String(), }), + prosedurPendaftaran: t.Object({ content: t.String(), }), - tarifDanLayanan: t.Object({ - layanan: t.String(), - tarif: t.String(), - }), + + // FIX → harus array of string (ID tarif) + tarifDanLayanan: t.Array(t.String()), }), } ); diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/create.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/create.ts new file mode 100644 index 00000000..6df9c882 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/create.ts @@ -0,0 +1,28 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +type FormCreate = { + layanan: string; + tarif: string; +}; + +export default async function tarifLayananCreate(context: Context) { + const body = context.body as FormCreate; + + const created = await prisma.tarifDanLayanan.create({ + data: { + layanan: body.layanan, + tarif: body.tarif, + }, + select: { + layanan: true, + tarif: true, + } + }); + + return { + success: true, + message: "Sukses menambahkan dokter tenaga medis", + data: created, + }; +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/del.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/del.ts new file mode 100644 index 00000000..0b911c51 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/del.ts @@ -0,0 +1,37 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function tarifLayananDelete(context: Context) { + + const id = context.params?.id; + + if (!id) { + return { + success: false, + message: "ID tidak ditemukan", + }; + } + + const existing = await prisma.tarifDanLayanan.findUnique({ + where: { + id: id, + }, + }); + + if (!existing) { + return { + success: false, + message: "Data tidak ditemukan", + }; + } + + const deleted = await prisma.tarifDanLayanan.delete({ + where: { id }, + }); + + return { + success: true, + message: "Data berhasil dihapus", + data: deleted, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/findMany.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/findMany.ts new file mode 100644 index 00000000..d1ff935b --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/findMany.ts @@ -0,0 +1,54 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +// /api/berita/findManyPaginated.ts +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +async function tarifLayananFindMany(context: Context) { + // Ambil parameter dari query + const page = Number(context.query.page) || 1; + const limit = Number(context.query.limit) || 10; + const search = (context.query.search as string) || ''; + const skip = (page - 1) * limit; + + // Buat where clause + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [ + { layanan: { contains: search, mode: 'insensitive' } }, + { tarif: { contains: search, mode: 'insensitive' } }, + ]; + } + + try { + // Ambil data dan total count secara paralel + const [data, total] = await Promise.all([ + prisma.tarifDanLayanan.findMany({ + where, + skip, + take: limit, + orderBy: { layanan: 'asc' }, + }), + prisma.tarifDanLayanan.count({ where }), + ]); + + return { + success: true, + message: "Berhasil ambil data tarif layanan dengan pagination", + data, + page, + limit, + total, + totalPages: Math.ceil(total / limit), + }; + } catch (e) { + console.error("Error di findMany paginated:", e); + return { + success: false, + message: "Gagal mengambil data tarif layanan", + }; + } +} + +export default tarifLayananFindMany; \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/findUnique.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/findUnique.ts new file mode 100644 index 00000000..89d9c0f8 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/findUnique.ts @@ -0,0 +1,47 @@ +import prisma from "@/lib/prisma"; + +export default async function tarifLayananFindUnique(request: Request) { + const url = new URL(request.url); + const pathSegments = url.pathname.split('/'); + + const id = pathSegments[pathSegments.length - 1]; + + if (!id) { + return Response.json({ + success: false, + message: 'ID tidak boleh kosong', + }, {status: 400}) + } + + try { + if (typeof id !== 'string') { + return Response.json({ + success: false, + message: "ID tidak valid", + }, { status: 400 }); + } + + const data = await prisma.tarifDanLayanan.findUnique({ + where: { id }, + }); + + if (!data) { + return Response.json({ + success: false, + message: "Data tidak ditemukan", + }, { status: 404 }); + } + + return Response.json({ + success: true, + message: "Berhasil mengambil data berdasarkan ID", + data, + }, { status: 200 }); + } catch (error) { + console.error("Error fetching data:", error); + return Response.json({ + success: false, + message: "Terjadi kesalahan saat mengambil data", + }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/index.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/index.ts new file mode 100644 index 00000000..bbd68317 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/index.ts @@ -0,0 +1,30 @@ +import Elysia, { t } from "elysia"; +import tarifLayananCreate from "./create"; +import tarifLayananFindMany from "./findMany"; +import tarifLayananFindUnique from "./findUnique"; +import tarifLayananDelete from "./del"; +import tarifLayananUpdate from "./updt"; + +const TarifLayanan = new Elysia({ + prefix: "/tarifdanlayanan", + tags: ["Data Kesehatan/Fasilitas Kesehatan/Tarif Layanan"] +}) + .get("/:id", async (context) => { + const response = await tarifLayananFindUnique(new Request(context.request)); + return response; + }) + .get("/findMany", tarifLayananFindMany) + .post("/create", tarifLayananCreate, { + body: t.Object({ + tarif: t.String(), + layanan: t.String() + }), + }) + .put("/:id", tarifLayananUpdate, { + body: t.Object({ + tarif: t.String(), + layanan: t.String(), + }), + }) + .delete("/del/:id", tarifLayananDelete) +export default TarifLayanan \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/updt.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/updt.ts new file mode 100644 index 00000000..2638207d --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan/updt.ts @@ -0,0 +1,32 @@ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +type FormUpdate = { + layanan: string; + tarif: string; +}; + +export default async function tarifLayananUpdate(context: Context) { + const body = (await context.body) as FormUpdate; + const id = context.params.id as string; + + try { + const result = await prisma.tarifDanLayanan.update({ + where: { id }, + data: { + layanan: body.layanan, + tarif: body.tarif, + }, + }); + return { + success: true, + message: "Berhasil mengupdate data tarif layanan", + data: result, + }; + } catch (error) { + console.error("Error updating data tarif layanan:", error); + throw new Error( + "Gagal mengupdate data tarif layanan: " + (error as Error).message + ); + } +} diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/updt.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/updt.ts index d0061150..db66ae74 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/updt.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/data_kesehatan_warga/fasilitas_kesehatan/updt.ts @@ -5,32 +5,26 @@ type FasilitasKesehatanInput = { name: string; informasiUmum: { fasilitas: string; alamat: string; jamOperasional: string }; layananUnggulan: { content: string }; - dokterdanTenagaMedis: { name: string; specialist: string; jadwal: string }; + dokterdanTenagaMedis: string[]; // ← ID saja fasilitasPendukung: { content: string }; prosedurPendaftaran: { content: string }; - tarifDanLayanan: { layanan: string; tarif: string }; + tarifDanLayanan: string[]; // ← ID saja }; const fasilitasKesehatanUpdate = async (context: Context) => { const id = context.params?.id as string; - const body = await context.body as FasilitasKesehatanInput; - - if (!id) { - return new Response( - JSON.stringify({ success: false, message: "ID is required" }), - { status: 400, headers: { "Content-Type": "application/json" } } - ); - } + const body = (await context.body) as FasilitasKesehatanInput; const existing = await prisma.fasilitasKesehatan.findUnique({ where: { id }, + include: { + dokterdantenagamedis: true, + tarifdanlayanan: true, + }, }); if (!existing) { - return new Response( - JSON.stringify({ success: false, message: "Data not found" }), - { status: 404, headers: { "Content-Type": "application/json" } } - ); + return { success: false, message: "Data tidak ditemukan" }; } const { @@ -43,38 +37,46 @@ const fasilitasKesehatanUpdate = async (context: Context) => { tarifDanLayanan, } = body; - // Update data masing-masing relasi + // update relasi 1-1 await Promise.all([ prisma.informasiUmum.update({ where: { id: existing.informasiUmumId }, data: informasiUmum, }), + prisma.layananUnggulan.update({ where: { id: existing.layananUnggulanId }, data: layananUnggulan, }), - prisma.dokterdanTenagaMedis.update({ - where: { id: existing.dokterdanTenagaMedisId }, - data: dokterdanTenagaMedis, - }), + prisma.fasilitasPendukung.update({ where: { id: existing.fasilitasPendukungId }, data: fasilitasPendukung, }), + prisma.prosedurPendaftaran.update({ where: { id: existing.prosedurPendaftaranId }, data: prosedurPendaftaran, }), - prisma.tarifDanLayanan.update({ - where: { id: existing.tarifDanLayananId }, - data: tarifDanLayanan, - }), ]); - // Update main record + // update m2m const updated = await prisma.fasilitasKesehatan.update({ where: { id }, - data: { name }, + + data: { + name, + + // reset dokter lama → ganti baru + dokterdantenagamedis: { + set: dokterdanTenagaMedis.map((id) => ({ id })), + }, + + tarifdanlayanan: { + set: tarifDanLayanan.map((id) => ({ id })), + }, + }, + include: { informasiumum: true, layananunggulan: true, @@ -87,7 +89,7 @@ const fasilitasKesehatanUpdate = async (context: Context) => { return { success: true, - message: "Fasilitas berhasil diupdate", + message: "Fasilitas diupdate", data: updated, }; }; diff --git a/src/app/api/[[...slugs]]/_lib/kesehatan/index.ts b/src/app/api/[[...slugs]]/_lib/kesehatan/index.ts index 8c38fcfb..19f978d7 100644 --- a/src/app/api/[[...slugs]]/_lib/kesehatan/index.ts +++ b/src/app/api/[[...slugs]]/_lib/kesehatan/index.ts @@ -20,6 +20,7 @@ import Kelahiran from "./data_kesehatan_warga/persentase_kelahiran_kematian/kela import Kematian from "./data_kesehatan_warga/persentase_kelahiran_kematian/kematian"; import DokterTenagaMedis from "./data_kesehatan_warga/fasilitas_kesehatan/dokter-tenaga-medis"; import PendaftaranJadwalKegiatan from "./data_kesehatan_warga/jadwal_kegiatan/pendaftaran"; +import TarifLayanan from "./data_kesehatan_warga/fasilitas_kesehatan/tarif-layanan"; const Kesehatan = new Elysia({ @@ -46,5 +47,6 @@ const Kesehatan = new Elysia({ .use(Kelahiran) .use(Kematian) .use(DokterTenagaMedis) +.use(TarifLayanan) .use(PendaftaranJadwalKegiatan) export default Kesehatan; diff --git a/src/app/api/[[...slugs]]/_lib/search/findMany.ts b/src/app/api/[[...slugs]]/_lib/search/findMany.ts index 5e6eab4e..7aae7328 100644 --- a/src/app/api/[[...slugs]]/_lib/search/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/search/findMany.ts @@ -557,25 +557,37 @@ export default async function searchFindMany(context: Context) { ], }, layananunggulan: { content: { contains: query, mode: "insensitive" } }, - dokterdantenagamedis: { - OR: [ - { name: { contains: query, mode: "insensitive" } }, - { specialist: { contains: query, mode: "insensitive" } }, - { jadwal: { contains: query, mode: "insensitive" } }, - ], - }, + fasilitaspendukung: { content: { contains: query, mode: "insensitive" }, }, prosedurpendaftaran: { content: { contains: query, mode: "insensitive" }, }, - tarifdanlayanan: { - OR: [ - { layanan: { contains: query, mode: "insensitive" } }, - { tarif: { contains: query, mode: "insensitive" } }, - ], - }, + }, + skip, + take: limitNum, + }); + return { data, nextPage: data.length < limitNum ? null : pageNum + 1 }; + } + + if (type === "doktertenagamedis") { + const data = await prisma.dokterdanTenagaMedis.findMany({ + where: { + name: { contains: query, mode: "insensitive" }, + specialist: { contains: query, mode: "insensitive" }, + }, + skip, + take: limitNum, + }); + return { data, nextPage: data.length < limitNum ? null : pageNum + 1 }; + } + + if (type === "tarifdanlayanan") { + const data = await prisma.tarifDanLayanan.findMany({ + where: { + layanan: { contains: query, mode: "insensitive" }, + tarif: { contains: query, mode: "insensitive" }, }, skip, take: limitNum, @@ -1567,6 +1579,8 @@ export default async function searchFindMany(context: Context) { jenisProgramYangDiselenggarakan, dataPerpustakaan, dataPendidikan, + dokterDanTenagaMedis, + tarifDanLayanan ] = await Promise.all([ prisma.pejabatDesa.findMany({ where: { name: { contains: query, mode: "insensitive" } }, @@ -1894,25 +1908,27 @@ export default async function searchFindMany(context: Context) { ], }, layananunggulan: { content: { contains: query, mode: "insensitive" } }, - dokterdantenagamedis: { - OR: [ - { name: { contains: query, mode: "insensitive" } }, - { specialist: { contains: query, mode: "insensitive" } }, - { jadwal: { contains: query, mode: "insensitive" } }, - ], - }, + fasilitaspendukung: { content: { contains: query, mode: "insensitive" }, }, prosedurpendaftaran: { content: { contains: query, mode: "insensitive" }, }, - tarifdanlayanan: { - OR: [ - { layanan: { contains: query, mode: "insensitive" } }, - { tarif: { contains: query, mode: "insensitive" } }, - ], - }, + }, + take: limitNum, + }), + prisma.dokterdanTenagaMedis.findMany({ + where: { + name: { contains: query, mode: "insensitive" }, + specialist: { contains: query, mode: "insensitive" }, + }, + take: limitNum, + }), + prisma.tarifDanLayanan.findMany({ + where: { + tarif: { contains: query, mode: "insensitive" }, + layanan: { contains: query, mode: "insensitive" }, }, take: limitNum, }), @@ -2316,7 +2332,7 @@ export default async function searchFindMany(context: Context) { { judul: { contains: query, mode: "insensitive" } }, { deskripsiSingkat: { contains: query, mode: "insensitive" } }, { deskripsiLengkap: { contains: query, mode: "insensitive" } }, - { lokasi: { contains: query, mode: "insensitive" } }, + { lokasi: { contains: query, mode: "insensitive" } }, { kategoriKegiatan: { nama: { contains: query, mode: "insensitive" }, @@ -2559,6 +2575,8 @@ export default async function searchFindMany(context: Context) { ...penghargaan.map((b) => ({ type: "penghargaan", ...b })), ...posyandu.map((b) => ({ type: "posyandu", ...b })), ...fasilitasKesehatan.map((b) => ({ type: "fasilitasKesehatan", ...b })), + ...dokterDanTenagaMedis.map((b) => ({ type: "dokterdanTenagaMedis", ...b })), + ...tarifDanLayanan.map((b) => ({ type: "tarifDanLayanan", ...b })), ...jadwalKegiatan.map((b) => ({ type: "jadwalKegiatan", ...b })), ...artikelKesehatan.map((b) => ({ type: "artikelKesehatan", ...b })), ...puskesmas.map((b) => ({ type: "puskesmas", ...b })), diff --git a/src/app/darmasaba/(pages)/kesehatan/data-kesehatan-warga/fasilitas-kesehatan-page/[id]/page.tsx b/src/app/darmasaba/(pages)/kesehatan/data-kesehatan-warga/fasilitas-kesehatan-page/[id]/page.tsx index 6aa24dfd..d8d02e6e 100644 --- a/src/app/darmasaba/(pages)/kesehatan/data-kesehatan-warga/fasilitas-kesehatan-page/[id]/page.tsx +++ b/src/app/darmasaba/(pages)/kesehatan/data-kesehatan-warga/fasilitas-kesehatan-page/[id]/page.tsx @@ -42,9 +42,7 @@ function Page() { const alamat = data?.informasiumum?.alamat || '-'; const jam = data?.informasiumum?.jamOperasional || '-'; const layananUnggulan = data?.layananunggulan?.content || ''; - const tenaga = data?.dokterdantenagamedis || null; const fasilitasPendukungHtml = data?.fasilitaspendukung?.content || ''; - const tarif = (data?.tarifdanlayanan as TarifDanLayanan) || null; const kontak = (data?.kontak as Kontak) || { telepon: '(0361) 123456', whatsapp: '6289647037426', @@ -211,7 +209,7 @@ function Page() { Dokter & Tenaga Medis - +
Nama @@ -220,12 +218,19 @@ function Page() { - {tenaga ? ( - - {tenaga?.name || '-'} - {tenaga?.specialist || '-'} - {tenaga?.jadwal || '-'} - + {Array.isArray(data?.dokterdantenagamedis) && data.dokterdantenagamedis.length > 0 ? ( + data.dokterdantenagamedis.map((dokter: any) => ( + + + + + {dokter.name || '-'} + + + {dokter.specialist || '-'} + {dokter.jadwal || '-'} + + )) ) : ( @@ -241,72 +246,74 @@ function Page() { - - - Fasilitas Pendukung - - {fasilitasPendukungHtml ? ( - - ) : ( - - - - Belum ada informasi fasilitas pendukung. - - - )} - - + + + Fasilitas Pendukung + + {fasilitasPendukungHtml ? ( + + ) : ( + + + + Belum ada informasi fasilitas pendukung. + + + )} + + - - - Layanan & Tarif - -
- - - Layanan - Tarif - - - - {tarif ? ( + + + Layanan & Tarif + +
+ - {tarif?.layanan || '-'} - {formatRupiah(tarif?.tarif)} + Layanan + Tarif - ) : ( - - - - - Tidak ada data tarif. - - - - )} - -
- {gratisBpjs && ( - - - Gratis dengan BPJS Kesehatan - - )} -
-
+ + + {Array.isArray(data?.tarifdanlayanan) && data.tarifdanlayanan.length > 0 ? ( + data.tarifdanlayanan.map((item: any) => ( + + {item.layanan || '-'} + {formatRupiah(item.tarif)} + + )) + ) : ( + + + + + Tidak ada data tarif. + + + + )} + + + {gratisBpjs && ( + + + Gratis dengan BPJS Kesehatan + + )} + + - + Prosedur Pendaftaran {prosedur ? ( - + ) : ( Belum ada prosedur pendaftaran )} diff --git a/src/app/darmasaba/_com/main-page/landing-page/SosmedView.tsx b/src/app/darmasaba/_com/main-page/landing-page/SosmedView.tsx index 3279e2ef..773b906f 100644 --- a/src/app/darmasaba/_com/main-page/landing-page/SosmedView.tsx +++ b/src/app/darmasaba/_com/main-page/landing-page/SosmedView.tsx @@ -50,7 +50,9 @@ function SosmedView({ loading="lazy" src={src} alt={item.name} - fit={item.image?.link ? "cover" : "contain"} + w={24} + h={24} + fit="contain" /> ); } diff --git a/src/app/darmasaba/_com/searchUrl.tsx b/src/app/darmasaba/_com/searchUrl.tsx index 6350b8dc..4ce896b9 100644 --- a/src/app/darmasaba/_com/searchUrl.tsx +++ b/src/app/darmasaba/_com/searchUrl.tsx @@ -1,4 +1,4 @@ -const getDetailUrl = (item: { type?: string; id: string | number; [key: string]: unknown }) => { +const getDetailUrl = (item: { type?: string; id: string | number;[key: string]: unknown }) => { const { type, id, kategori } = item; const map: Record string> = { programinovasi: (id) => `/darmasaba/program-inovasi/${id}`, @@ -30,6 +30,8 @@ const getDetailUrl = (item: { type?: string; id: string | number; [key: string]: penghargaan: () => '/darmasaba/desa/penghargaan', posyandu: (id) => `/darmasaba/kesehatan/posyandu/${id}`, fasilitasKesehatan: () => '/darmasaba/kesehatan/data-kesehatan-warga', + dokterDanTenagaMedis: () => '/darmasaba/kesehatan/data-kesehatan-warga', + tarifDanLayanan: () => '/darmasaba/kesehatan/data-kesehatan-warga', jadwalKegiatan: () => '/darmasaba/kesehatan/data-kesehatan-warga', artikelKesehatan: () => '/darmasaba/kesehatan/data-kesehatan-warga', puskesmas: () => '/darmasaba/kesehatan/puskesmas', @@ -82,7 +84,7 @@ const getDetailUrl = (item: { type?: string; id: string | number; [key: string]: jenisProgramYangDiselenggarakan: () => '/darmasaba/pendidikan/pendidikan-non-formal', dataPerpustakaan: () => '/darmasaba/pendidikan/perpustakaan-digital/semua', dataPendidikan: () => '/darmasaba/pendidikan/data-pendidikan', - + }; if (type && map[type]) return map[type](id, kategori as string | undefined);