Compare commits
18 Commits
nico/14-au
...
nico/23-au
| Author | SHA1 | Date | |
|---|---|---|---|
| bb8dab05ba | |||
| 3081e426bd | |||
| 8a275c2a32 | |||
| 8469ebd2e1 | |||
| 760ba4b6d2 | |||
| 20d4c90e60 | |||
| fafbb12a08 | |||
| 01aa0da5cc | |||
| b580978f8e | |||
| 1c01397c0d | |||
| 90a6605efd | |||
| c22d865283 | |||
| 49067f0218 | |||
| d79425d529 | |||
| 4491d23bea | |||
| 1e154ced86 | |||
| bcc51aec12 | |||
| 8d15563f15 |
@@ -3,126 +3,108 @@
|
||||
"id": "cmds9h9ko000pvnberdjnx64b",
|
||||
"name": "1.1 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmds9sjmz000svnbesv2133of",
|
||||
"name": "1.2 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmds9tcpi000vvnbev3ebtlnt",
|
||||
"name": "1.3 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmds9twvj000yvnbep0pq8dzf",
|
||||
"name": "1.4 PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA",
|
||||
"deskripsi": "<p>PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmds9ugap0011vnbe118yv871",
|
||||
"name": "1.5 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa35310014vnbe6qy6l1rz",
|
||||
"name": "2.1 ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA",
|
||||
"deskripsi": "<p>ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa46590017vnbepp3noso1",
|
||||
"name": "2.2 ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH",
|
||||
"deskripsi": "<p>ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa5m7z001avnbe4cvfrcz0",
|
||||
"name": "2.3 TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI",
|
||||
"deskripsi": "<p>TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa8q5q001dvnbemch8j24x",
|
||||
"name": "3.1 ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT",
|
||||
"deskripsi": "<p>ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa9lbi001gvnbequn2ba7m",
|
||||
"name": "3.2 ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA",
|
||||
"deskripsi": "<p>ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsaa7aq001jvnbeizh04e67",
|
||||
"name": "3.3 ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA",
|
||||
"deskripsi": "<p>ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsaaw8d001mvnbek3tfefrk",
|
||||
"name": "3.4 ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT",
|
||||
"deskripsi": "<p>ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsabhif001pvnbepm06hry6",
|
||||
"name": "3.5 ADANYA MAKLUMAT PELAYANAN",
|
||||
"deskripsi": "<p>ADANYA MAKLUMAT PELAYANAN</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsag40b001svnbe7krq9khc",
|
||||
"name": "4.1 ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA",
|
||||
"deskripsi": "<p>ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||
},
|
||||
{
|
||||
"id": "cmdsagkaf001vvnbejo26w8sa",
|
||||
"name": "4.2 ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
"deskripsi": "<p>ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||
},
|
||||
{
|
||||
"id": "cmdsah4qe001yvnbeiy3mwrvb",
|
||||
"name": "4.3 ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA",
|
||||
"deskripsi": "<p>ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||
},
|
||||
{
|
||||
"id": "cmdsak5vn0021vnbemg86aab4",
|
||||
"name": "5.1 ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||
"deskripsi": "<p>ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99"
|
||||
},
|
||||
{
|
||||
"id": "cmdsalc800024vnbezgulhgrb",
|
||||
"name": "5.2 ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||
"deskripsi": "<p>ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99"
|
||||
}
|
||||
]
|
||||
@@ -1,8 +1,14 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"jenisInformasi": "Peraturan Desa",
|
||||
"deskripsi": "Dokumen yang berisi kebijakan dan regulasi desa",
|
||||
"tanggal": "15 Januari 2024"
|
||||
"id": "cmeppcwzk0000vn5exmudcipd",
|
||||
"jenisInformasi": "Potensi Desa",
|
||||
"deskripsi": "<p>“Potensi desa adalah segenap sumber daya alam dan sumber daya manusia yang dimiliki desa sebagai modal dasar yang perlu dikelola dan dikembangkan bagi kelangsungan dan perkembangan desa. Adapun potensi yang dimiliki Desa Darmasaba yaitu:</p><ol><li><p>TPS3R Pudak Mesari</p></li><li><p>Bumdes Pudak Mesari</p></li><li><p>Pertanian</p></li><li><p>Jogging Track Tegeh Aban, Karang Gadon dan Munduk Uma Desa</p></li><li><p>Taman Beji Cengana</p></li><li><p>Dam Tanah Putih</p></li><li><p>Gumuh Sari Water Park</p></li><li><p>UMKM</p></li><li><p>Kawasan Kuliner</p></li><li><p>IKM berbasis Pengolahan Pangan</p></li><li><p>Genteng</p></li><li><p>Peternakan Ikan Lele</p></li><li><p>Pemotongan Daging”</p></li></ol>",
|
||||
"tanggal": "2021-05-25"
|
||||
},
|
||||
{
|
||||
"id": "cmeppieay0001vn5e8qe658ub",
|
||||
"jenisInformasi": "Layanan Surat Keterangan Desa",
|
||||
"deskripsi": "<p>“Desa Darmasaba menyediakan berbagai jenis layanan surat keterangan untuk kebutuhan administratif, antara lain:</p><ul><li><p>Surat Keterangan Domisili Organisasi</p></li><li><p>Surat Keterangan Penghasilan</p></li><li><p>Surat Keterangan Tidak Mampu</p></li><li><p>Surat Keterangan Kelahiran</p></li><li><p>Surat Keterangan Usaha</p></li><li><p>Surat Keterangan Tempat Usaha</p></li><li><p>Surat Keterangan Belum Kawin</p></li><li><p>Surat Keterangan Kelakuan Baik (Pengantar SKCK)</p></li><li><p>Surat Keterangan Kematian</p></li><li><p>Surat Keterangan Perbedaan Biodata Diri</p></li><li><p>Surat Keterangan Yatim/Piatu/Yatim Piatu<br>Untuk surat keterangan lainnya, masyarakat dapat berkonsultasi langsung ke kantor Perbekel Darmasaba.”<br><em>(Sumber: Laman Layanan Desa Darmasaba)</em></p></li></ul>",
|
||||
"tanggal": "2025-02-21"
|
||||
}
|
||||
]
|
||||
@@ -201,8 +201,8 @@ model PrestasiDesa {
|
||||
deskripsi String @db.Text
|
||||
kategori KategoriPrestasiDesa @relation(fields: [kategoriId], references: [id])
|
||||
kategoriId String
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
@@ -223,7 +223,7 @@ model KategoriPrestasiDesa {
|
||||
model Responden {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
tanggal DateTime // misal: 2025-05-01
|
||||
tanggal DateTime @db.Date // misal: 2025-05-01
|
||||
jenisKelamin JenisKelaminResponden @relation(fields: [jenisKelaminId], references: [id])
|
||||
jenisKelaminId String
|
||||
rating PilihanRatingResponden @relation(fields: [ratingId], references: [id])
|
||||
@@ -292,6 +292,9 @@ model PosisiOrganisasiPPID {
|
||||
pegawai PegawaiPPID[]
|
||||
strukturOrganisasi StrukturPPID[] // Relasi balik
|
||||
parentId String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
||||
children PosisiOrganisasiPPID[] @relation("Parent")
|
||||
}
|
||||
@@ -951,13 +954,16 @@ model Kematian {
|
||||
|
||||
// ========================================= GRAFIK KEPUASAN ========================================= //
|
||||
model GrafikKepuasan {
|
||||
id String @id @default(cuid())
|
||||
label String
|
||||
jumlah String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
id String @id @default(cuid())
|
||||
nama String
|
||||
tanggal DateTime
|
||||
jenisKelamin String
|
||||
alamat String
|
||||
penyakit String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
// ========================================= ARTIKEL KESEHATAN ========================================= //
|
||||
@@ -1544,7 +1550,7 @@ model DataDemografiPekerjaan {
|
||||
model DetailDataPengangguran {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
month String @db.VarChar(20)
|
||||
year Int
|
||||
year DateTime
|
||||
totalUnemployment Int
|
||||
educatedUnemployment Int
|
||||
uneducatedUnemployment Int
|
||||
|
||||
332
prisma/seed.ts
332
prisma/seed.ts
@@ -1,57 +1,62 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import profilePejabatDesa from "./data/landing-page/profile/profile.json";
|
||||
import penghargaan from "./data/landing-page/penghargaan/penghargaan.json";
|
||||
import programInovasi from "./data/landing-page/profile/programInovasi.json";
|
||||
import mediaSosial from "./data/landing-page/profile/mediaSosial.json";
|
||||
import desaAntiKorupsi from "./data/landing-page/desa-anti-korupsi/desaantiKorpusi.json";
|
||||
import kategoriDesaAntiKorupsi from "./data/landing-page/desa-anti-korupsi/kategoriDesaAntiKorupsi.json";
|
||||
import sdgsDesa from "./data/landing-page/sdgs-desa/sdgs-desa.json";
|
||||
import apbdes from "./data/landing-page/apbdes/apbdes.json";
|
||||
import pelayananSuratKeterangan from "./data/desa/layanan/pelayananSuratKeterangan.json";
|
||||
import categoryPengumuman from "./data/category-pengumuman.json";
|
||||
import kategoriBerita from "./data/kategori-berita.json";
|
||||
import caraMemperolehInformasi from "./data/list-caraMemperolehInformasi.json";
|
||||
import caraMemperolehSalinanInformasi from "./data/list-caraMemperolehSalinanInformasi.json";
|
||||
import jenisInformasiDiminta from "./data/list-jenisInfromasi.json";
|
||||
import layanan from "./data/list-layanan.json";
|
||||
import potensi from "./data/list-potensi.json";
|
||||
import dasarHukumPPID from "./data/ppid/dasar-hukum-ppid/dasarhukumPPID.json";
|
||||
import kategoriPrestasiDesa from "./data/landing-page/prestasi-desa/kategori-prestasi.json";
|
||||
import prestasiDesa from "./data/landing-page/prestasi-desa/prestasi-desa.json";
|
||||
import penghargaan from "./data/landing-page/penghargaan/penghargaan.json";
|
||||
import profilePPID from "./data/ppid/profile-ppid/profilePPid.json";
|
||||
import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
import posisiOrganisasiPPID from "./data/ppid/struktur-ppid/posisi-organisasi-PPID.json";
|
||||
import visiMisiPPID from "./data/ppid/visi-misi-ppid/visimisiPPID.json";
|
||||
import dasarHukumPPID from "./data/ppid/dasar-hukum-ppid/dasarhukumPPID.json";
|
||||
import jenisKelamin from "./data/ppid/ikm/jenis-kelamin/jenis-kelamin.json";
|
||||
import daftarInformasiPublik from "./data/ppid/daftar-informasi-publik-desa-darmasaba/daftarInformasi.json"
|
||||
import pilihanRatingResponden from "./data/ppid/ikm/pilihan-rating-responden/rating-responden.json";
|
||||
import umurResponden from "./data/ppid/ikm/umur-responden/umur-responden.json";
|
||||
import categoryPengumuman from "./data/category-pengumuman.json";
|
||||
import pelayananPerizinanBerusaha from "./data/desa/layanan/pelayananPerizinanBerusaha.json";
|
||||
import pelayananSuratKeterangan from "./data/desa/layanan/pelayananSuratKeterangan.json";
|
||||
import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSaktiDesa.json";
|
||||
import pelayananPendudukNonPermanen from "./data/desa/layanan/pelayanaPendudukNonPermanen.json";
|
||||
import sejarahDesa from "./data/desa/profile/sejarah_desa.json";
|
||||
import visiMisiDesa from "./data/desa/profile/visi_misi_desa.json";
|
||||
import lambangDesa from "./data/desa/profile/lambang_desa.json";
|
||||
import maskotDesa from "./data/desa/profile/maskot_desa.json";
|
||||
import profilPerbekel from "./data/desa/profile/profil_perbekel.json";
|
||||
import sejarahDesa from "./data/desa/profile/sejarah_desa.json";
|
||||
import visiMisiDesa from "./data/desa/profile/visi_misi_desa.json";
|
||||
import detailDataPengangguran from "./data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json";
|
||||
import kategoriProduk from "./data/ekonomi/pasar-desa/kategori-produk.json";
|
||||
import hubunganOrganisasi from "./data/ekonomi/struktur-organisasi/hubungan-organisasi.json";
|
||||
import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json";
|
||||
import pegawai from "./data/ekonomi/struktur-organisasi/pegawai.json";
|
||||
import detailDataPengangguran from "./data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json";
|
||||
import tujuanEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
|
||||
import materiEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
|
||||
import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json";
|
||||
import kategoriBerita from "./data/kategori-berita.json";
|
||||
import contohEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/contoh-kegiatan-di-desa-darmasaba.json";
|
||||
import nilaiKonservasiAdat from "./data/lingkungan/konservasi-adat-bali/nilai-konservasi-adat.json";
|
||||
import materiEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
|
||||
import tujuanEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
|
||||
import bentukKonservasiBerdasarkanAdat from "./data/lingkungan/konservasi-adat-bali/bentuk-konservasi.json";
|
||||
import filosofiTriHita from "./data/lingkungan/konservasi-adat-bali/filosofi-tri-hita.json";
|
||||
import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
||||
import nilaiKonservasiAdat from "./data/lingkungan/konservasi-adat-bali/nilai-konservasi-adat.json";
|
||||
import caraMemperolehInformasi from "./data/list-caraMemperolehInformasi.json";
|
||||
import caraMemperolehSalinanInformasi from "./data/list-caraMemperolehSalinanInformasi.json";
|
||||
import jenisInformasiDiminta from "./data/list-jenisInfromasi.json";
|
||||
import potensi from "./data/list-potensi.json";
|
||||
import fasilitasBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json";
|
||||
import lokasiJadwalBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json";
|
||||
import tujuanBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json";
|
||||
import jenisProgramYangDiselenggarakan from "./data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json";
|
||||
import tempatKegiatan from "./data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json";
|
||||
import tujuanProgram2 from "./data/pendidikan/pendidikan-non-formal/tujuan-program2.json";
|
||||
import programUnggulan from "./data/pendidikan/program-pendidikan-anak/program-unggulan.json";
|
||||
import tujuanBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json";
|
||||
import lokasiJadwalBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json";
|
||||
import fasilitasBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json";
|
||||
import tempatKegiatan from "./data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json";
|
||||
import jenisProgramYangDiselenggarakan from "./data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json";
|
||||
import posisiOrganisasiPPID from "./data/ppid/struktur-ppid/posisi-organisasi-PPID.json";
|
||||
import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSaktiDesa.json";
|
||||
import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
||||
|
||||
(async () => {
|
||||
// =========== LANDING PAGE ===========
|
||||
// =========== PROFILE ===========
|
||||
// =========== SUBMENU PROFILE ===========
|
||||
// =========== PROFILE PEJABAT DESA ===========
|
||||
for (const p of profilePejabatDesa) {
|
||||
await prisma.pejabatDesa.upsert({
|
||||
where: { id: p.id },
|
||||
@@ -106,6 +111,90 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
}
|
||||
console.log("media sosial success ...");
|
||||
|
||||
// =========== SUBMENU DESA ANTI KORUPSI ===========
|
||||
// =========== KATEGORI DESA ANTI KORUPSI ===========
|
||||
for (const k of kategoriDesaAntiKorupsi) {
|
||||
await prisma.kategoriDesaAntiKorupsi.upsert({
|
||||
where: { id: k.id },
|
||||
update: {
|
||||
name: k.name,
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
name: k.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("kategori desa anti korupsi success ...");
|
||||
|
||||
// =========== DESA ANTI KORUPSI ===========
|
||||
for (const p of desaAntiKorupsi) {
|
||||
await prisma.desaAntiKorupsi.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
deskripsi: p.deskripsi,
|
||||
kategoriId: p.kategoriId,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
deskripsi: p.deskripsi,
|
||||
kategoriId: p.kategoriId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("desa anti korupsi success ...");
|
||||
|
||||
// =========== KATEGORI DESA ANTI KORUPSI ===========
|
||||
for (const p of kategoriDesaAntiKorupsi) {
|
||||
await prisma.kategoriDesaAntiKorupsi.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("desa anti korupsi success ...");
|
||||
|
||||
// =========== KATEGORI PRESTASI DESA===========
|
||||
for (const c of kategoriPrestasiDesa) {
|
||||
await prisma.kategoriPrestasiDesa.upsert({
|
||||
where: { id: c.id },
|
||||
update: {
|
||||
name: c.name,
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("kategori prestasi desa success ...");
|
||||
|
||||
// =========== PRESTASI DESA===========
|
||||
for (const p of prestasiDesa) {
|
||||
await prisma.prestasiDesa.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
deskripsi: p.deskripsi,
|
||||
kategoriId: p.kategoriId,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
deskripsi: p.deskripsi,
|
||||
kategoriId: p.kategoriId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("prestasi desa success ...");
|
||||
|
||||
// =========== PENGHARGAAN ===========
|
||||
for (const p of penghargaan) {
|
||||
await prisma.penghargaan.upsert({
|
||||
@@ -160,23 +249,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
}
|
||||
console.log("pelayanan surat keterangan success ...");
|
||||
|
||||
// =========== LAYANAN ===========
|
||||
for (const l of layanan) {
|
||||
await prisma.layanan.upsert({
|
||||
where: {
|
||||
name: l.name,
|
||||
},
|
||||
update: {
|
||||
name: l.name,
|
||||
},
|
||||
create: {
|
||||
name: l.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("layanan success ...");
|
||||
|
||||
// =========== SDGSDesa ===========
|
||||
for (const l of sdgsDesa) {
|
||||
await prisma.sDGSDesa.upsert({
|
||||
@@ -217,6 +289,9 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("sdgs desa success ...");
|
||||
|
||||
// =========== MENU DESA ===========
|
||||
// =========== SUBMENU PROFILE ===========
|
||||
// =========== SEJARAH DESA ===========
|
||||
for (const l of sejarahDesa) {
|
||||
await prisma.sejarahDesa.upsert({
|
||||
where: {
|
||||
@@ -236,6 +311,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("sejarah desa success ...");
|
||||
|
||||
// =========== MASKOT DESA ===========
|
||||
for (const l of maskotDesa) {
|
||||
await prisma.maskotDesa.upsert({
|
||||
where: {
|
||||
@@ -255,6 +331,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("maskot desa success ...");
|
||||
|
||||
// =========== LAMBANG DESA ===========
|
||||
for (const l of lambangDesa) {
|
||||
await prisma.lambangDesa.upsert({
|
||||
where: {
|
||||
@@ -274,6 +351,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("lambang desa success ...");
|
||||
|
||||
// =========== PROFIL PERBEKEL ===========
|
||||
for (const c of profilPerbekel) {
|
||||
await prisma.profilPerbekel.upsert({
|
||||
where: { id: c.id },
|
||||
@@ -298,6 +376,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
"✅ profilePerbekel seeded without imageId (editable later via UI)"
|
||||
);
|
||||
|
||||
// =========== VISI MISI DESA ===========
|
||||
for (const l of visiMisiDesa) {
|
||||
await prisma.visiMisiDesa.upsert({
|
||||
where: {
|
||||
@@ -317,6 +396,35 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("visi misi desa success ...");
|
||||
|
||||
// =========== MENU PPID ===========
|
||||
// =========== SUBMENU PROFILE PPID ===========
|
||||
for (const c of profilePPID) {
|
||||
await prisma.profilePPID.upsert({
|
||||
where: { id: c.id },
|
||||
update: {
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
// imageId tidak di-update
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
// imageId tidak di-create
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ profilePPID seeded without imageId (editable later via UI)");
|
||||
|
||||
// =========== SUBMENU STRUKTUR PPID ===========
|
||||
// =========== POSISI ORGANISASI PPID ===========
|
||||
|
||||
const flattenedPosisi = posisiOrganisasiPPID.flat();
|
||||
|
||||
// ✅ Urutkan berdasarkan hierarki
|
||||
@@ -341,9 +449,9 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
create: p,
|
||||
});
|
||||
}
|
||||
console.log("✅ Posisi organisasi berhasil");
|
||||
console.log("posisi organisasi berhasil");
|
||||
|
||||
// 2. Seed Pegawai
|
||||
// =========== PEGAWAI PPID ===========
|
||||
const flattenedPegawai = pegawaiPPID.flat();
|
||||
for (const p of flattenedPegawai) {
|
||||
await prisma.pegawaiPPID.upsert({
|
||||
@@ -352,7 +460,70 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
create: p,
|
||||
});
|
||||
}
|
||||
console.log("✅ Pegawai berhasil");
|
||||
console.log("pegawai berhasil");
|
||||
|
||||
// =========== SUBMENU VISI MISI PPID ===========
|
||||
|
||||
for (const v of visiMisiPPID) {
|
||||
await prisma.visiMisiPPID.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
misi: v.misi,
|
||||
visi: v.visi,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
misi: v.misi,
|
||||
visi: v.visi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("visi misi PPID success ...");
|
||||
|
||||
// =========== SUBMENU DASAR HUKUM PPID ===========
|
||||
for (const v of dasarHukumPPID) {
|
||||
await prisma.dasarHukumPPID.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
judul: v.judul,
|
||||
content: v.content,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
judul: v.judul,
|
||||
content: v.content,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("dasar hukum PPID success ...");
|
||||
|
||||
// =========== SUBMENU DAFTAR INFORMASI PUBLIK PPID ===========
|
||||
for (const v of daftarInformasiPublik) {
|
||||
// Convert string date to Date object
|
||||
const tanggal = new Date(v.tanggal);
|
||||
|
||||
await prisma.daftarInformasiPublik.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
jenisInformasi: v.jenisInformasi,
|
||||
deskripsi: v.deskripsi,
|
||||
tanggal: tanggal,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
jenisInformasi: v.jenisInformasi,
|
||||
deskripsi: v.deskripsi,
|
||||
tanggal: tanggal,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("daftar informasi publik PPID success ...");
|
||||
|
||||
for (const l of pelayananPerizinanBerusaha) {
|
||||
await prisma.pelayananPerizinanBerusaha.upsert({
|
||||
@@ -486,48 +657,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
}
|
||||
console.log("cara memperoleh salinan informasi success ...");
|
||||
|
||||
for (const c of profilePPID) {
|
||||
await prisma.profilePPID.upsert({
|
||||
where: { id: c.id },
|
||||
update: {
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
// imageId tidak di-update
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
// imageId tidak di-create
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ profilePPID seeded without imageId (editable later via UI)");
|
||||
|
||||
for (const v of visiMisiPPID) {
|
||||
await prisma.visiMisiPPID.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
misi: v.misi,
|
||||
visi: v.visi,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
misi: v.misi,
|
||||
visi: v.visi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("visi misi PPID success ...");
|
||||
|
||||
for (const j of jenisKelamin) {
|
||||
await prisma.jenisKelaminResponden.upsert({
|
||||
where: {
|
||||
@@ -576,24 +705,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
}
|
||||
console.log("umur responden success ...");
|
||||
|
||||
for (const v of dasarHukumPPID) {
|
||||
await prisma.dasarHukumPPID.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
judul: v.judul,
|
||||
content: v.content,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
judul: v.judul,
|
||||
content: v.content,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("dasar hukum PPID success ...");
|
||||
|
||||
for (const k of kategoriProduk) {
|
||||
await prisma.kategoriProduk.upsert({
|
||||
where: {
|
||||
@@ -681,9 +792,12 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
console.log("hubungan organisasi success ...");
|
||||
|
||||
for (const d of detailDataPengangguran) {
|
||||
// Convert the year to a Date object (using January 1st of the year as the date)
|
||||
const yearAsDate = new Date(d.year, 0, 1);
|
||||
|
||||
await prisma.detailDataPengangguran.upsert({
|
||||
where: {
|
||||
month_year: { month: d.month, year: d.year },
|
||||
month_year: { month: d.month, year: yearAsDate },
|
||||
},
|
||||
update: {
|
||||
totalUnemployment: d.totalUnemployment,
|
||||
@@ -693,7 +807,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
},
|
||||
create: {
|
||||
month: d.month,
|
||||
year: d.year,
|
||||
year: yearAsDate,
|
||||
totalUnemployment: d.totalUnemployment,
|
||||
educatedUnemployment: d.educatedUnemployment,
|
||||
uneducatedUnemployment: d.uneducatedUnemployment,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -61,13 +62,39 @@ const lowonganKerjaState = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.LowonganPekerjaanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.lowongankerja["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
lowonganKerjaState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
lowonganKerjaState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
lowonganKerjaState.findMany.page = page;
|
||||
lowonganKerjaState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.lowongankerja["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
lowonganKerjaState.findMany.data = res.data.data ?? [];
|
||||
lowonganKerjaState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
lowonganKerjaState.findMany.data = [];
|
||||
lowonganKerjaState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch lowongan kerja paginated:", err);
|
||||
lowonganKerjaState.findMany.data = [];
|
||||
lowonganKerjaState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
lowonganKerjaState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -53,22 +54,47 @@ const pasarDesa = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.PasarDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
KategoriToPasar: {
|
||||
include: {
|
||||
kategori: true;
|
||||
data: null as
|
||||
| Prisma.PasarDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
KategoriToPasar: {
|
||||
include: {
|
||||
kategori: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.pasardesa["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
pasarDesa.findMany.data = res.data?.data ?? [];
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "", categoryId?: string) => {
|
||||
pasarDesa.findMany.loading = true;
|
||||
pasarDesa.findMany.page = page;
|
||||
pasarDesa.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
if (categoryId) query.categoryId = categoryId;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.pasardesa["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pasarDesa.findMany.data = res.data.data ?? [];
|
||||
pasarDesa.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
pasarDesa.findMany.data = [];
|
||||
pasarDesa.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch keamanan lingkungan paginated:", err);
|
||||
pasarDesa.findMany.data = [];
|
||||
pasarDesa.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pasarDesa.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -272,14 +298,41 @@ const kategoriProduk = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
nama: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
kategoriProduk.findMany.data = res.data?.data ?? [];
|
||||
data: null as
|
||||
| Prisma.KategoriProdukGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search2: "",
|
||||
load: async (page = 1, limit = 10, search2 = "") => {
|
||||
kategoriProduk.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kategoriProduk.findMany.page = page;
|
||||
kategoriProduk.findMany.search2 = search2;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search2) query.search2 = search2;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriProduk.findMany.data = res.data.data ?? [];
|
||||
kategoriProduk.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kategoriProduk.findMany.data = [];
|
||||
kategoriProduk.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kategori produk paginated:", err);
|
||||
kategoriProduk.findMany.data = [];
|
||||
kategoriProduk.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriProduk.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -11,8 +12,7 @@ const templateForm = z.object({
|
||||
statistik: z.object({
|
||||
tahun: z.string().min(1, "Tahun minimal 1 karakter"),
|
||||
jumlah: z.string().min(1, "Jumlah minimal 1 karakter"),
|
||||
})
|
||||
|
||||
}),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
@@ -21,8 +21,8 @@ const defaultForm = {
|
||||
ikonUrl: "",
|
||||
statistik: {
|
||||
tahun: "",
|
||||
jumlah: ""
|
||||
}
|
||||
jumlah: "",
|
||||
},
|
||||
};
|
||||
|
||||
const programKemiskinanState = proxy({
|
||||
@@ -64,12 +64,35 @@ const programKemiskinanState = proxy({
|
||||
};
|
||||
}>[],
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.programkemiskinan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
programKemiskinanState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
programKemiskinanState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
programKemiskinanState.findMany.page = page;
|
||||
programKemiskinanState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.programkemiskinan[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
programKemiskinanState.findMany.data = res.data.data ?? [];
|
||||
programKemiskinanState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
programKemiskinanState.findMany.data = [];
|
||||
programKemiskinanState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch program kemiskinan paginated:", err);
|
||||
programKemiskinanState.findMany.data = [];
|
||||
programKemiskinanState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
programKemiskinanState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -53,15 +54,39 @@ const keamananLingkunganState = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.KeamananLingkunganGetPayload<{
|
||||
include: { image: true };
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.keamananlingkungan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
keamananLingkunganState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
keamananLingkunganState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
keamananLingkunganState.findMany.page = page;
|
||||
keamananLingkunganState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.keamananlingkungan["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
keamananLingkunganState.findMany.data = res.data.data ?? [];
|
||||
keamananLingkunganState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
keamananLingkunganState.findMany.data = [];
|
||||
keamananLingkunganState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch keamanan lingkungan paginated:", err);
|
||||
keamananLingkunganState.findMany.data = [];
|
||||
keamananLingkunganState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
keamananLingkunganState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -63,13 +64,41 @@ const polsekTerdekatState = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PolsekTerdekatGetPayload<{
|
||||
include: { layananPolsek: true };
|
||||
include: {
|
||||
layananPolsek: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.polsekterdekat["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
polsekTerdekatState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
polsekTerdekatState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
polsekTerdekatState.findMany.page = page;
|
||||
polsekTerdekatState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.polsekterdekat["find-many"].get(
|
||||
{ query }
|
||||
);
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
polsekTerdekatState.findMany.data = res.data.data ?? [];
|
||||
polsekTerdekatState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
polsekTerdekatState.findMany.data = [];
|
||||
polsekTerdekatState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch polsek terdekat paginated:", err);
|
||||
polsekTerdekatState.findMany.data = [];
|
||||
polsekTerdekatState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
polsekTerdekatState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -237,6 +266,29 @@ const polsekTerdekatState = proxy({
|
||||
polsekTerdekatState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findFirst: {
|
||||
data: null as Prisma.PolsekTerdekatGetPayload<{
|
||||
include: {
|
||||
layananPolsek: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
load: async () => { // Changed to arrow function
|
||||
polsekTerdekatState.findFirst.loading = true;
|
||||
try {
|
||||
const res = await ApiFetch.api.keamanan.polsekterdekat["find-first"].get();
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
polsekTerdekatState.findFirst.data = res.data.data || null;
|
||||
} else {
|
||||
polsekTerdekatState.findFirst.data = null;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch polsek terdekat terbaru:", err);
|
||||
} finally {
|
||||
polsekTerdekatState.findFirst.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default polsekTerdekatState;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -53,15 +54,39 @@ const tipsKeamananState = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.MenuTipsKeamananGetPayload<{
|
||||
include: { image: true };
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.menutipskeamanan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
tipsKeamananState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
tipsKeamananState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
tipsKeamananState.findMany.page = page;
|
||||
tipsKeamananState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.menutipskeamanan["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
tipsKeamananState.findMany.data = res.data.data ?? [];
|
||||
tipsKeamananState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
tipsKeamananState.findMany.data = [];
|
||||
tipsKeamananState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch menu tips keamanan paginated:", err);
|
||||
tipsKeamananState.findMany.data = [];
|
||||
tipsKeamananState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
tipsKeamananState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@ import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
//fasilitas kesehatan aja
|
||||
// Validasi form
|
||||
const templateForm = z.object({
|
||||
name: z.string().min(1, "Nama harus diisi"),
|
||||
@@ -61,7 +62,7 @@ const defaultForm = {
|
||||
},
|
||||
};
|
||||
|
||||
const fasilitasKesehatanState = proxy({
|
||||
const fasilitasKesehatan = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
@@ -86,7 +87,7 @@ const fasilitasKesehatanState = proxy({
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil menambahkan fasilitas kesehatan");
|
||||
this.resetForm();
|
||||
await fasilitasKesehatanState.findMany.load();
|
||||
await fasilitasKesehatan.findMany.load();
|
||||
return res.data;
|
||||
}
|
||||
} catch (err: any) {
|
||||
@@ -102,7 +103,6 @@ const fasilitasKesehatanState = proxy({
|
||||
this.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.FasilitasKesehatanGetPayload<{
|
||||
@@ -156,7 +156,7 @@ const fasilitasKesehatanState = proxy({
|
||||
const res = await fetch(`/api/kesehatan/fasilitas-kesehatan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
fasilitasKesehatanState.findUnique.data = data.data ?? null;
|
||||
fasilitasKesehatan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal load data fasilitas kesehatan");
|
||||
}
|
||||
@@ -176,8 +176,8 @@ const fasilitasKesehatanState = proxy({
|
||||
const result = await res.json();
|
||||
const data = result.data;
|
||||
|
||||
fasilitasKesehatanState.edit.id = data.id;
|
||||
fasilitasKesehatanState.edit.form = {
|
||||
fasilitasKesehatan.edit.id = data.id;
|
||||
fasilitasKesehatan.edit.form = {
|
||||
name: data.name,
|
||||
informasiUmum: {
|
||||
fasilitas: data.informasiumum.fasilitas,
|
||||
@@ -205,7 +205,7 @@ const fasilitasKesehatanState = proxy({
|
||||
};
|
||||
},
|
||||
async submit() {
|
||||
const cek = templateForm.safeParse(fasilitasKesehatanState.edit.form);
|
||||
const cek = templateForm.safeParse(fasilitasKesehatan.edit.form);
|
||||
if (!cek.success) {
|
||||
const errMsg = cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
@@ -215,42 +215,38 @@ const fasilitasKesehatanState = proxy({
|
||||
}
|
||||
|
||||
try {
|
||||
fasilitasKesehatanState.edit.loading = true;
|
||||
fasilitasKesehatan.edit.loading = true;
|
||||
const payload = {
|
||||
name: fasilitasKesehatanState.edit.form.name,
|
||||
name: fasilitasKesehatan.edit.form.name,
|
||||
informasiUmum: {
|
||||
fasilitas:
|
||||
fasilitasKesehatanState.edit.form.informasiUmum.fasilitas,
|
||||
alamat: fasilitasKesehatanState.edit.form.informasiUmum.alamat,
|
||||
fasilitas: fasilitasKesehatan.edit.form.informasiUmum.fasilitas,
|
||||
alamat: fasilitasKesehatan.edit.form.informasiUmum.alamat,
|
||||
jamOperasional:
|
||||
fasilitasKesehatanState.edit.form.informasiUmum.jamOperasional,
|
||||
fasilitasKesehatan.edit.form.informasiUmum.jamOperasional,
|
||||
},
|
||||
layananUnggulan: {
|
||||
content: fasilitasKesehatanState.edit.form.layananUnggulan.content,
|
||||
content: fasilitasKesehatan.edit.form.layananUnggulan.content,
|
||||
},
|
||||
dokterdanTenagaMedis: {
|
||||
name: fasilitasKesehatanState.edit.form.dokterdanTenagaMedis.name,
|
||||
name: fasilitasKesehatan.edit.form.dokterdanTenagaMedis.name,
|
||||
specialist:
|
||||
fasilitasKesehatanState.edit.form.dokterdanTenagaMedis.specialist,
|
||||
jadwal:
|
||||
fasilitasKesehatanState.edit.form.dokterdanTenagaMedis.jadwal,
|
||||
fasilitasKesehatan.edit.form.dokterdanTenagaMedis.specialist,
|
||||
jadwal: fasilitasKesehatan.edit.form.dokterdanTenagaMedis.jadwal,
|
||||
},
|
||||
fasilitasPendukung: {
|
||||
content:
|
||||
fasilitasKesehatanState.edit.form.fasilitasPendukung.content,
|
||||
content: fasilitasKesehatan.edit.form.fasilitasPendukung.content,
|
||||
},
|
||||
prosedurPendaftaran: {
|
||||
content:
|
||||
fasilitasKesehatanState.edit.form.prosedurPendaftaran.content,
|
||||
content: fasilitasKesehatan.edit.form.prosedurPendaftaran.content,
|
||||
},
|
||||
tarifDanLayanan: {
|
||||
layanan: fasilitasKesehatanState.edit.form.tarifDanLayanan.layanan,
|
||||
tarif: fasilitasKesehatanState.edit.form.tarifDanLayanan.tarif,
|
||||
layanan: fasilitasKesehatan.edit.form.tarifDanLayanan.layanan,
|
||||
tarif: fasilitasKesehatan.edit.form.tarifDanLayanan.tarif,
|
||||
},
|
||||
};
|
||||
|
||||
const res = await fetch(
|
||||
`/api/kesehatan/fasilitas-kesehatan/${fasilitasKesehatanState.edit.id}`,
|
||||
`/api/kesehatan/fasilitas-kesehatan/${fasilitasKesehatan.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -264,7 +260,7 @@ const fasilitasKesehatanState = proxy({
|
||||
}
|
||||
|
||||
toast.success("Berhasil update fasilitas kesehatan");
|
||||
await fasilitasKesehatanState.findMany.load();
|
||||
await fasilitasKesehatan.findMany.load();
|
||||
return true;
|
||||
} catch (err) {
|
||||
toast.error(
|
||||
@@ -272,37 +268,297 @@ const fasilitasKesehatanState = proxy({
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
fasilitasKesehatanState.edit.loading = false;
|
||||
fasilitasKesehatan.edit.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
fasilitasKesehatanState.edit.id = "";
|
||||
fasilitasKesehatanState.edit.form = { ...defaultForm };
|
||||
fasilitasKesehatan.edit.id = "";
|
||||
fasilitasKesehatan.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string){
|
||||
async byId(id: string) {
|
||||
try {
|
||||
fasilitasKesehatanState.delete.loading = true;
|
||||
const res = await fetch(`/api/kesehatan/fasilitas-kesehatan/del/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
fasilitasKesehatan.delete.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/kesehatan/fasilitas-kesehatan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
|
||||
const result = await res.json();
|
||||
if (res.ok && result.success) {
|
||||
toast.success("Fasilitas kesehatan berhasil dihapus");
|
||||
await fasilitasKesehatanState.findMany.load();
|
||||
await fasilitasKesehatan.findMany.load();
|
||||
} else {
|
||||
toast.error(result.message || "Gagal menghapus");
|
||||
}
|
||||
} catch {
|
||||
toast.error("Terjadi kesalahan saat menghapus");
|
||||
} finally {
|
||||
fasilitasKesehatanState.delete.loading = false;
|
||||
fasilitasKesehatan.delete.loading = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
//dokter & tenaga medis
|
||||
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"),
|
||||
});
|
||||
|
||||
const defaultDokterForm = {
|
||||
name: "",
|
||||
specialist: "",
|
||||
jadwal: "",
|
||||
};
|
||||
|
||||
const dokter = proxy({
|
||||
create: {
|
||||
create: {
|
||||
form: defaultDokterForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDokterForm.safeParse(dokter.create.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
dokter.create.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.doktertenagamedis[
|
||||
"create"
|
||||
].post(dokter.create.create.form);
|
||||
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
dokter.create.create.form = { ...defaultDokterForm };
|
||||
dokter.findMany.load();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
toast.error("failed create");
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
return null;
|
||||
} finally {
|
||||
dokter.create.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DokterdanTenagaMedisGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
dokter.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
dokter.findMany.page = page;
|
||||
dokter.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.doktertenagamedis[
|
||||
"findMany"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
dokter.findMany.data = res.data.data ?? [];
|
||||
dokter.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
dokter.findMany.data = [];
|
||||
dokter.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch dokter tenaga medis paginated:", err);
|
||||
dokter.findMany.data = [];
|
||||
dokter.findMany.totalPages = 1;
|
||||
} finally {
|
||||
dokter.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.DokterdanTenagaMedisGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/kesehatan/doktertenagamedis/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
dokter.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to fetch dokter dan tenaga medis",
|
||||
res.statusText
|
||||
);
|
||||
dokter.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching dokter dan tenaga medis", error);
|
||||
dokter.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultDokterForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/kesehatan/doktertenagamedis/${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,
|
||||
specialist: data.specialist,
|
||||
jadwal: data.jadwal,
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading dokter dan tenaga medis:", 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 = {
|
||||
name: this.form.name,
|
||||
specialist: this.form.specialist,
|
||||
jadwal: this.form.jadwal,
|
||||
};
|
||||
|
||||
const cek = templateDokterForm.safeParse(formData);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await fetch(`/api/kesehatan/doktertenagamedis/${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 dokter.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Update error:", error);
|
||||
toast.error("Gagal update data dokter dan tenaga medis");
|
||||
throw error;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) {
|
||||
return toast.warn("ID tidak valid");
|
||||
}
|
||||
try {
|
||||
dokter.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/kesehatan/doktertenagamedis/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Dokter dan tenaga medis berhasil dihapus"
|
||||
);
|
||||
await dokter.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(
|
||||
result?.message || "Gagal menghapus dokter dan tenaga medis"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus dokter dan tenaga medis");
|
||||
} finally {
|
||||
dokter.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const fasilitasKesehatanState = proxy({
|
||||
fasilitasKesehatan,
|
||||
dokter
|
||||
});
|
||||
|
||||
export default fasilitasKesehatanState;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -5,20 +6,19 @@ import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
const templateGrafikKepuasan = z.object({
|
||||
label: z.string().min(2, "Label harus diisi"),
|
||||
jumlah: z.string().min(1, "Jumlah harus diisi"),
|
||||
nama: z.string().min(2, "Nama harus diisi"),
|
||||
tanggal: z.string().min(1, "Tanggal harus diisi"),
|
||||
jenisKelamin: z.string().min(1, "Jenis kelamin harus diisi"),
|
||||
alamat: z.string().min(1, "Alamat harus diisi"),
|
||||
penyakit: z.string().min(1, "Penyakit harus diisi"),
|
||||
});
|
||||
|
||||
type GrafikKepuasan = Prisma.GrafikKepuasanGetPayload<{
|
||||
select: {
|
||||
label: true;
|
||||
jumlah: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const defaultForm: GrafikKepuasan = {
|
||||
label: "",
|
||||
jumlah: ""
|
||||
const defaultForm = {
|
||||
nama: "",
|
||||
tanggal: "",
|
||||
jenisKelamin: "",
|
||||
alamat: "",
|
||||
penyakit: "",
|
||||
};
|
||||
|
||||
const grafikkepuasan = proxy({
|
||||
@@ -36,16 +36,15 @@ const grafikkepuasan = proxy({
|
||||
}
|
||||
try {
|
||||
grafikkepuasan.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.grafikkepuasan["create"].post(grafikkepuasan.create.form);
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.grafikkepuasan["create"].post(
|
||||
grafikkepuasan.create.form
|
||||
);
|
||||
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
const id = res.data?.data;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
grafikkepuasan.create.form = {
|
||||
label: "",
|
||||
jumlah: "",
|
||||
};
|
||||
grafikkepuasan.create.form = { ...defaultForm };
|
||||
grafikkepuasan.findMany.load();
|
||||
return id;
|
||||
}
|
||||
@@ -62,21 +61,49 @@ const grafikkepuasan = proxy({
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.GrafikKepuasanGetPayload<{ omit: { isActive: true } }>[]
|
||||
| Prisma.GrafikKepuasanGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.grafikkepuasan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
grafikkepuasan.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
grafikkepuasan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
grafikkepuasan.findMany.page = page;
|
||||
grafikkepuasan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.grafikkepuasan[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
grafikkepuasan.findMany.data = res.data.data ?? [];
|
||||
grafikkepuasan.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
grafikkepuasan.findMany.data = [];
|
||||
grafikkepuasan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch berita paginated:", err);
|
||||
grafikkepuasan.findMany.data = [];
|
||||
grafikkepuasan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
grafikkepuasan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.GrafikKepuasanGetPayload<{
|
||||
omit: { isActive: true }
|
||||
}> | null,
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/kesehatan/grafikkepuasan/${id}`);
|
||||
@@ -95,88 +122,137 @@ const grafikkepuasan = proxy({
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: {...defaultForm},
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async byId() {
|
||||
},
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateGrafikKepuasan.safeParse(grafikkepuasan.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
this.loading = true;
|
||||
const response = await fetch(`/api/kesehatan/grafikkepuasan/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
toast.success("Berhasil update data!");
|
||||
try {
|
||||
const response = await fetch(`/api/kesehatan/grafikkepuasan/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
// ✅ Optional: refresh list kalau kamu langsung ke halaman list
|
||||
await grafikkepuasan.findMany.load();
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data grafik kepuasan");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) {
|
||||
return toast.warn("ID tidak valid");
|
||||
}
|
||||
try {
|
||||
grafikkepuasan.delete.loading = true;
|
||||
const result = await response.json();
|
||||
|
||||
const response = await fetch(`/api/kesehatan/grafikkepuasan/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Grafik kepuasan berhasil dihapus"
|
||||
);
|
||||
await grafikkepuasan.findMany.load(); // refresh list
|
||||
} else {
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
nama: data.nama,
|
||||
tanggal: data.tanggal,
|
||||
jenisKelamin: data.jenisKelamin,
|
||||
alamat: data.alamat,
|
||||
penyakit: data.penyakit,
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik kepuasan:", error);
|
||||
toast.error(
|
||||
result?.message || "Gagal menghapus grafik kepuasan"
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus grafik kepuasan");
|
||||
} finally {
|
||||
grafikkepuasan.delete.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
const formData = {
|
||||
nama: this.form.nama,
|
||||
tanggal: this.form.tanggal,
|
||||
jenisKelamin: this.form.jenisKelamin,
|
||||
alamat: this.form.alamat,
|
||||
penyakit: this.form.penyakit,
|
||||
};
|
||||
|
||||
const cek = templateGrafikKepuasan.safeParse(formData);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await fetch(`/api/kesehatan/grafikkepuasan/${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 grafikkepuasan.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Update error:", error);
|
||||
toast.error("Gagal update data grafik kepuasan");
|
||||
throw error;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) {
|
||||
return toast.warn("ID tidak valid");
|
||||
}
|
||||
try {
|
||||
grafikkepuasan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/kesehatan/grafikkepuasan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Grafik kepuasan berhasil dihapus");
|
||||
await grafikkepuasan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus grafik kepuasan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus grafik kepuasan");
|
||||
} finally {
|
||||
grafikkepuasan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default grafikkepuasan;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -20,17 +21,41 @@ const defaultForm = {
|
||||
|
||||
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 ?? [];
|
||||
data: null as
|
||||
| Prisma.InfoWabahPenyakitGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
infoWabahPenyakit.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
infoWabahPenyakit.findMany.page = page;
|
||||
infoWabahPenyakit.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.infowabahpenyakit["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
infoWabahPenyakit.findMany.data = res.data.data ?? [];
|
||||
infoWabahPenyakit.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
infoWabahPenyakit.findMany.data = [];
|
||||
infoWabahPenyakit.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch info wabah penyakit paginated:", err);
|
||||
infoWabahPenyakit.findMany.data = [];
|
||||
infoWabahPenyakit.findMany.totalPages = 1;
|
||||
} finally {
|
||||
infoWabahPenyakit.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -5,204 +6,241 @@ 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 };
|
||||
},
|
||||
},
|
||||
name: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
});
|
||||
|
||||
export default kontakDarurat
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const kontakDarurat = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.KontakDaruratGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kontakDarurat.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kontakDarurat.findMany.page = page;
|
||||
kontakDarurat.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.kontakdarurat[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kontakDarurat.findMany.data = res.data.data ?? [];
|
||||
kontakDarurat.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kontakDarurat.findMany.data = [];
|
||||
kontakDarurat.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kontak darurat paginated:", err);
|
||||
kontakDarurat.findMany.data = [];
|
||||
kontakDarurat.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kontakDarurat.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
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;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -17,21 +18,45 @@ const defaultForm = {
|
||||
}
|
||||
|
||||
const penangananDarurat = proxy({
|
||||
findMany: {
|
||||
data: [] as Prisma.PenangananDaruratGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[],
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.penanganandarurat[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
penangananDarurat.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PenangananDaruratGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
penangananDarurat.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
penangananDarurat.findMany.page = page;
|
||||
penangananDarurat.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.penanganandarurat["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
penangananDarurat.findMany.data = res.data.data ?? [];
|
||||
penangananDarurat.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
penangananDarurat.findMany.data = [];
|
||||
penangananDarurat.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch berita paginated:", err);
|
||||
penangananDarurat.findMany.data = [];
|
||||
penangananDarurat.findMany.totalPages = 1;
|
||||
} finally {
|
||||
penangananDarurat.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
create:{
|
||||
form: {...defaultForm},
|
||||
loading: false,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -20,17 +21,43 @@ const defaultForm = {
|
||||
|
||||
const programKesehatan = proxy({
|
||||
findMany: {
|
||||
data: [] as Prisma.ProgramKesehatanGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[],
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.programkesehatan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
programKesehatan.findMany.data = res.data?.data ?? [];
|
||||
data: null as
|
||||
| Prisma.ProgramKesehatanGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
programKesehatan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
programKesehatan.findMany.page = page;
|
||||
programKesehatan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.programkesehatan[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
programKesehatan.findMany.data = res.data.data ?? [];
|
||||
programKesehatan.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
programKesehatan.findMany.data = [];
|
||||
programKesehatan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch berita paginated:", err);
|
||||
programKesehatan.findMany.data = [];
|
||||
programKesehatan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
programKesehatan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -97,12 +124,15 @@ const programKesehatan = proxy({
|
||||
try {
|
||||
programKesehatan.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/kesehatan/programkesehatan/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/kesehatan/programkesehatan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if (response.ok && result?.success) {
|
||||
@@ -156,57 +186,70 @@ const programKesehatan = proxy({
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching program kesehatan:", error);
|
||||
toast.error(error instanceof Error ? error.message : "Gagal memuat data");
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(programKesehatan.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
const cek = templateForm.safeParse(programKesehatan.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
programKesehatan.edit.loading = true;
|
||||
const response = await fetch(`/api/kesehatan/programkesehatan/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
deskripsiSingkat: this.form.deskripsiSingkat,
|
||||
deskripsi: this.form.deskripsi,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success(result.message || "Program kesehatan berhasil diupdate");
|
||||
await programKesehatan.findMany.load();
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update program kesehatan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal update:", error);
|
||||
toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat mengupdate program kesehatan");
|
||||
return false;
|
||||
} finally {
|
||||
programKesehatan.edit.loading = false;
|
||||
try {
|
||||
programKesehatan.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/kesehatan/programkesehatan/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
deskripsiSingkat: this.form.deskripsiSingkat,
|
||||
deskripsi: this.form.deskripsi,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success(
|
||||
result.message || "Program kesehatan berhasil diupdate"
|
||||
);
|
||||
await programKesehatan.findMany.load();
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update program kesehatan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal update:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat mengupdate program kesehatan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
programKesehatan.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
programKesehatan.edit.id = "";
|
||||
programKesehatan.edit.form = { ...defaultForm };
|
||||
programKesehatan.edit.id = "";
|
||||
programKesehatan.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -163,13 +164,43 @@ const puskesmasState = proxy({
|
||||
},
|
||||
|
||||
findMany: {
|
||||
data: null as Prisma.PuskesmasGetPayload<{
|
||||
include: { image: true; jam: true; kontak: true };
|
||||
}>[] | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.puskesmas["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
puskesmasState.findMany.data = res.data?.data ?? [];
|
||||
data: null as
|
||||
| Prisma.PuskesmasGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
jam: true;
|
||||
kontak: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
puskesmasState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
puskesmasState.findMany.page = page;
|
||||
puskesmasState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.puskesmas["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
puskesmasState.findMany.data = res.data.data ?? [];
|
||||
puskesmasState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
puskesmasState.findMany.data = [];
|
||||
puskesmasState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch berita paginated:", err);
|
||||
puskesmasState.findMany.data = [];
|
||||
puskesmasState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
puskesmasState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -50,18 +51,50 @@ const apbdes = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.APBDesGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
file: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.apbdes["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
apbdes.findMany.data = res.data?.data ?? [];
|
||||
data: null as
|
||||
| Prisma.APBDesGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
file: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
apbdes.findMany.loading = true; // Use the full path to access the property
|
||||
apbdes.findMany.page = page;
|
||||
apbdes.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.apbdes[
|
||||
"findMany"
|
||||
].get({
|
||||
query
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
apbdes.findMany.data = res.data.data || [];
|
||||
apbdes.findMany.total = res.data.total || 0;
|
||||
apbdes.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pegawai:", res.data?.message);
|
||||
apbdes.findMany.data = [];
|
||||
apbdes.findMany.total = 0;
|
||||
apbdes.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pegawai:", error);
|
||||
apbdes.findMany.data = [];
|
||||
apbdes.findMany.total = 0;
|
||||
apbdes.findMany.totalPages = 1;
|
||||
} finally {
|
||||
apbdes.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -60,16 +60,22 @@ const desaAntikorupsi = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
desaAntikorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
desaAntikorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
desaAntikorupsi.findMany.page = page;
|
||||
desaAntikorupsi.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
desaAntikorupsi.findMany.data = res.data.data || [];
|
||||
desaAntikorupsi.findMany.total = res.data.total || 0;
|
||||
@@ -305,20 +311,25 @@ const kategoriDesaAntiKorupsi = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
kategoriDesaAntiKorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
kategoriDesaAntiKorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
kategoriDesaAntiKorupsi.findMany.page = page;
|
||||
kategoriDesaAntiKorupsi.findMany.search = search;
|
||||
try {
|
||||
const res = await ApiFetch.api.landingpage.kategoridak[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.kategoridak["findMany"].get({
|
||||
query,
|
||||
});
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriDesaAntiKorupsi.findMany.data = res.data.data || [];
|
||||
kategoriDesaAntiKorupsi.findMany.total = res.data.total || 0;
|
||||
kategoriDesaAntiKorupsi.findMany.totalPages = res.data.totalPages || 1;
|
||||
kategoriDesaAntiKorupsi.findMany.totalPages =
|
||||
res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load media sosial:", res.data?.message);
|
||||
kategoriDesaAntiKorupsi.findMany.data = [];
|
||||
@@ -363,27 +374,30 @@ const kategoriDesaAntiKorupsi = proxy({
|
||||
try {
|
||||
kategoriDesaAntiKorupsi.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/kategoridak/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/landingpage/kategoridak/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kategori desa anti korupsi berhasil dihapus");
|
||||
toast.success(
|
||||
result.message || "Kategori desa anti korupsi berhasil dihapus"
|
||||
);
|
||||
await kategoriDesaAntiKorupsi.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kategori desa anti korupsi");
|
||||
toast.error(
|
||||
result?.message || "Gagal menghapus kategori desa anti korupsi"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kategori desa anti korupsi");
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat menghapus kategori desa anti korupsi"
|
||||
);
|
||||
} finally {
|
||||
kategoriDesaAntiKorupsi.delete.loading = false;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,13 @@ const responden = proxy({
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
tanggal: this.form.tanggal,
|
||||
jenisKelaminId: this.form.jenisKelaminId,
|
||||
ratingId: this.form.ratingId,
|
||||
kelompokUmurId: this.form.kelompokUmurId,
|
||||
}),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -58,16 +59,43 @@ const prestasiDesa = proxy({
|
||||
Prisma.PrestasiDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategori: true;
|
||||
kategori: {
|
||||
select: {
|
||||
id: true;
|
||||
name: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.prestasidesa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
prestasiDesa.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
prestasiDesa.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
prestasiDesa.findMany.page = page;
|
||||
prestasiDesa.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.prestasidesa["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
prestasiDesa.findMany.data = res.data.data ?? [];
|
||||
prestasiDesa.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
prestasiDesa.findMany.data = [];
|
||||
prestasiDesa.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch prestasi desa paginated:", err);
|
||||
prestasiDesa.findMany.data = [];
|
||||
prestasiDesa.findMany.totalPages = 1;
|
||||
} finally {
|
||||
prestasiDesa.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -283,12 +311,34 @@ const kategoriPrestasi = proxy({
|
||||
id: string;
|
||||
name: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.kategoriprestasi[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
kategoriPrestasi.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kategoriPrestasi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kategoriPrestasi.findMany.page = page;
|
||||
kategoriPrestasi.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.kategoriprestasi["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriPrestasi.findMany.data = res.data.data ?? [];
|
||||
kategoriPrestasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kategoriPrestasi.findMany.data = [];
|
||||
kategoriPrestasi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kategori prestasi paginated:", err);
|
||||
kategoriPrestasi.findMany.data = [];
|
||||
kategoriPrestasi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriPrestasi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -65,14 +65,19 @@ const programInovasi = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
programInovasi.findMany.loading = true; // Use the full path to access the property
|
||||
programInovasi.findMany.page = page;
|
||||
programInovasi.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.programinovasi[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
@@ -482,14 +487,19 @@ const mediaSosial = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
mediaSosial.findMany.loading = true; // Use the full path to access the property
|
||||
mediaSosial.findMany.page = page;
|
||||
try {
|
||||
mediaSosial.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.mediasosial[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
|
||||
@@ -58,14 +58,19 @@ const sdgsDesa = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
sdgsDesa.findMany.loading = true; // Use the full path to access the property
|
||||
sdgsDesa.findMany.page = page;
|
||||
sdgsDesa.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
|
||||
@@ -49,35 +49,38 @@ const daftarInformasiPublik = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
data: null as
|
||||
| Prisma.DaftarInformasiPublikGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
daftarInformasiPublik.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
daftarInformasiPublik.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
daftarInformasiPublik.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.ppid.daftarinformasipublik[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
daftarInformasiPublik.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ppid.daftarinformasipublik["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
daftarInformasiPublik.findMany.data = res.data.data || [];
|
||||
daftarInformasiPublik.findMany.total = res.data.total || 0;
|
||||
daftarInformasiPublik.findMany.totalPages = res.data.totalPages || 1;
|
||||
daftarInformasiPublik.findMany.data = res.data.data ?? [];
|
||||
daftarInformasiPublik.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
console.error("Failed to load daftar informasi publik:", res.data?.message);
|
||||
daftarInformasiPublik.findMany.data = [];
|
||||
daftarInformasiPublik.findMany.total = 0;
|
||||
daftarInformasiPublik.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading daftar informasi publik:", error);
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch daftar informasi publik paginated:", err);
|
||||
daftarInformasiPublik.findMany.data = [];
|
||||
daftarInformasiPublik.findMany.total = 0;
|
||||
daftarInformasiPublik.findMany.totalPages = 1;
|
||||
} finally {
|
||||
daftarInformasiPublik.findMany.loading = false;
|
||||
|
||||
@@ -348,18 +348,34 @@ const posisiOrganisasi = proxy({
|
||||
deskripsi: string | null;
|
||||
hierarki: number;
|
||||
}>,
|
||||
async load() {
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
posisiOrganisasi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
posisiOrganisasi.findMany.page = page;
|
||||
posisiOrganisasi.findMany.search = search;
|
||||
|
||||
try {
|
||||
const res = await ApiFetch.api.ppid.strukturppid.posisiorganisasi[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
// The API now returns the id field, so we can use it directly
|
||||
this.data = res.data?.data ?? [];
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ppid.strukturppid.posisiorganisasi["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
posisiOrganisasi.findMany.data = res.data.data ?? [];
|
||||
posisiOrganisasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
posisiOrganisasi.findMany.data = [];
|
||||
posisiOrganisasi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
this.data = [];
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch posisi organisasi paginated:", err);
|
||||
posisiOrganisasi.findMany.data = [];
|
||||
posisiOrganisasi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
posisiOrganisasi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -438,9 +454,9 @@ const pegawai = proxy({
|
||||
|
||||
try {
|
||||
pegawai.create.loading = true;
|
||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
||||
"create"
|
||||
].post(pegawai.create.form);
|
||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai["create"].post(
|
||||
pegawai.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
toast.success("Pegawai berhasil ditambahkan");
|
||||
await pegawai.findMany.load();
|
||||
@@ -457,42 +473,55 @@ const pegawai = proxy({
|
||||
},
|
||||
|
||||
// In struktur-organisasi.ts
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
pegawai.findMany.loading = true; // Use the full path to access the property
|
||||
pegawai.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PegawaiPPIDGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
posisi: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
pegawai.findMany.loading = true; // Use the full path to access the property
|
||||
pegawai.findMany.page = page;
|
||||
pegawai.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pegawai.findMany.data = res.data.data || [];
|
||||
pegawai.findMany.total = res.data.total || 0;
|
||||
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pegawai:", res.data?.message);
|
||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
||||
"find-many"
|
||||
].get({
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pegawai.findMany.data = res.data.data || [];
|
||||
pegawai.findMany.total = res.data.total || 0;
|
||||
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pegawai:", res.data?.message);
|
||||
pegawai.findMany.data = [];
|
||||
pegawai.findMany.total = 0;
|
||||
pegawai.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pegawai:", error);
|
||||
pegawai.findMany.data = [];
|
||||
pegawai.findMany.total = 0;
|
||||
pegawai.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pegawai.findMany.loading = false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pegawai:", error);
|
||||
pegawai.findMany.data = [];
|
||||
pegawai.findMany.total = 0;
|
||||
pegawai.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pegawai.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as
|
||||
| (Prisma.PegawaiGetPayload<{
|
||||
@@ -521,12 +550,9 @@ findMany: {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
pegawai.delete.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/ppid/strukturppid/pegawai/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
const res = await fetch(`/api/ppid/strukturppid/pegawai/del/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
const json = await res.json();
|
||||
if (res.ok) {
|
||||
toast.success(json.message ?? "Berhasil hapus pegawai");
|
||||
@@ -555,15 +581,12 @@ findMany: {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ppid/strukturppid/pegawai/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/ppid/strukturppid/pegawai/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
@@ -677,7 +700,7 @@ findMany: {
|
||||
const stateStrukturPPID = proxy({
|
||||
stateStruktur,
|
||||
posisiOrganisasi,
|
||||
pegawai
|
||||
pegawai,
|
||||
});
|
||||
|
||||
export default stateStrukturPPID;
|
||||
|
||||
@@ -143,8 +143,8 @@ function ListDemografiPekerjaan({ search }: { search: string }) {
|
||||
dataKey="pekerjaan"
|
||||
type="stacked"
|
||||
series={[
|
||||
{ name: 'lakiLaki', color: 'red.6', label: 'Laki - Laki' },
|
||||
{ name: 'perempuan', color: 'orange.6', label: 'Perempuan' },
|
||||
{ name: 'lakiLaki', color: '#5082EE', label: 'Laki - Laki' },
|
||||
{ name: 'perempuan', color: '#6EDF9C', label: 'Perempuan' },
|
||||
]}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -35,7 +35,7 @@ function EditJumlahPendudukMiskin() {
|
||||
// Set the ID before submitting
|
||||
stateJPM.update.id = id;
|
||||
await stateJPM.update.submit();
|
||||
router.push('/admin/ekonomi/jumlah-penduduk-miskin-2024-2025')
|
||||
router.push('/admin/ekonomi/jumlah-penduduk-miskin')
|
||||
}
|
||||
return (
|
||||
<Box>
|
||||
|
||||
@@ -32,7 +32,7 @@ function CreateJumlahPendudukMiskin() {
|
||||
}
|
||||
}
|
||||
resetForm();
|
||||
router.push("/admin/ekonomi/jumlah-penduduk-miskin-2024-2025");
|
||||
router.push("/admin/ekonomi/jumlah-penduduk-miskin");
|
||||
}
|
||||
return (
|
||||
<Box>
|
||||
|
||||
@@ -91,7 +91,7 @@ function ListJumlahPendudukMiskin({ search }: { search: string }) {
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Jumlah Penduduk Miskin'
|
||||
href='/admin/ekonomi/jumlah-penduduk-miskin-2024-2025/create'
|
||||
href='/admin/ekonomi/jumlah-penduduk-miskin/create'
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
@@ -108,7 +108,7 @@ function ListJumlahPendudukMiskin({ search }: { search: string }) {
|
||||
<TableTd>{item.year}</TableTd>
|
||||
<TableTd>{item.totalPoorPopulation}</TableTd>
|
||||
<TableTd>
|
||||
<Button color='green' onClick={() => router.push(`/admin/ekonomi/jumlah-penduduk-miskin-2024-2025/${item.id}`)}>
|
||||
<Button color='green' onClick={() => router.push(`/admin/ekonomi/jumlah-penduduk-miskin/${item.id}`)}>
|
||||
<IconEdit size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
|
||||
@@ -8,29 +8,36 @@ import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Cell, Pie, PieChart } from 'recharts';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import JudulListTab from '../../../_com/judulListTab';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
|
||||
import grafikNganggur from '../../../_state/ekonomi/usia-kerja-nganggur';
|
||||
|
||||
function GrafikBerdasarkanPendidikan() {
|
||||
const [search, setSearch] = useState("")
|
||||
return (
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Grafik Pengangguran Berdasarkan Pendidikan</Title>
|
||||
<ListGrafikBerdasarkanPendidikan />
|
||||
<HeaderSearch
|
||||
title='Detail Data Pengangguran Berdasarkan Pendidikan'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListGrafikBerdasarkanPendidikan search={search}/>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListGrafikBerdasarkanPendidikan() {
|
||||
function ListGrafikBerdasarkanPendidikan({search}: {search: string}) {
|
||||
const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan)
|
||||
const [donutData, setDonutData] = useState<any[]>([]);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [modalHapus, setModalHapus] = useState(false)
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
const router = useRouter();
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
|
||||
const handleDelete = async () => {
|
||||
@@ -56,11 +63,11 @@ function ListGrafikBerdasarkanPendidikan() {
|
||||
const D3 = stategrafik.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.D3 || 0), 0);
|
||||
const S1 = stategrafik.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.S1 || 0), 0);
|
||||
setDonutData([
|
||||
{ name: 'SD', value: SD, color: colors['blue-button'], key: 'SD' },
|
||||
{ name: 'SMP', value: SMP, color: '#10A85AFF', key: 'SMP' },
|
||||
{ name: 'SMA', value: SMA, color: '#C07B13FF', key: 'SMA' },
|
||||
{ name: 'D3', value: D3, color: '#1094A8FF', key: 'D3' },
|
||||
{ name: 'S1', value: S1, color: '#A83610FF', key: 'S1' },
|
||||
{ name: 'SD', value: SD, color: '#4b6Ef5', key: 'SD' },
|
||||
{ name: 'SMP', value: SMP, color: '#14b885', key: 'SMP' },
|
||||
{ name: 'SMA', value: SMA, color: '#E6A03B', key: 'SMA' },
|
||||
{ name: 'D3', value: D3, color: '#DB524D', key: 'D3' },
|
||||
{ name: 'S1', value: S1, color: '#1018A8FF', key: 'S1' },
|
||||
]);
|
||||
}
|
||||
}, [stategrafik.findMany.data])
|
||||
@@ -88,13 +95,9 @@ function ListGrafikBerdasarkanPendidikan() {
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<JudulListTab
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
<JudulList
|
||||
title='List Grafik Pengangguran Berdasarkan Pendidikan'
|
||||
href='/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/create'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={16} />}
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
|
||||
@@ -8,29 +8,37 @@ import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Cell, Pie, PieChart } from 'recharts';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import JudulListTab from '../../../_com/judulListTab';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
|
||||
import grafikNganggur from '../../../_state/ekonomi/usia-kerja-nganggur';
|
||||
|
||||
|
||||
function GrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
const [search, setSearch] = useState("")
|
||||
return (
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Grafik Pengangguran Berdasarkan Usia Kerja</Title>
|
||||
<ListGrafikBerdasarkanUsiaKerjaYangMenganggur />
|
||||
<HeaderSearch
|
||||
title='Detail Data Pengangguran'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListGrafikBerdasarkanUsiaKerjaYangMenganggur search={search} />
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
function ListGrafikBerdasarkanUsiaKerjaYangMenganggur({search}: {search: string}) {
|
||||
const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanUsiaKerjaNganggur)
|
||||
const [donutData, setDonutData] = useState<any[]>([]);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [modalHapus, setModalHapus] = useState(false)
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
const router = useRouter();
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
|
||||
const handleDelete = async () => {
|
||||
@@ -85,13 +93,9 @@ function ListGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<JudulListTab
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
<JudulList
|
||||
title='List Pengangguran Berdasarkan Usia Kerja'
|
||||
href='/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/create'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={16} />}
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
|
||||
@@ -66,19 +66,23 @@ function EditDetailDataPengangguran() {
|
||||
const data = stateDetail.findUnique.data;
|
||||
|
||||
if (data) {
|
||||
// Convert year from Date to number
|
||||
const yearValue = data.year instanceof Date ? data.year.getFullYear() : data.year;
|
||||
|
||||
// Set the ID for update
|
||||
stateDetail.update.id = id;
|
||||
|
||||
// Isi state Valtio untuk update
|
||||
// Update Valtio state with converted year
|
||||
stateDetail.update.form = {
|
||||
...data,
|
||||
year: yearValue,
|
||||
percentageChange: data.percentageChange || 0 // Ensure it's always a number
|
||||
};
|
||||
|
||||
// Isi local formData supaya input bisa dikontrol
|
||||
// Update local formData with converted year
|
||||
setFormData({
|
||||
month: data.month,
|
||||
year: data.year,
|
||||
year: yearValue,
|
||||
totalUnemployment: data.totalUnemployment,
|
||||
educatedUnemployment: data.educatedUnemployment,
|
||||
uneducatedUnemployment: data.uneducatedUnemployment,
|
||||
|
||||
@@ -25,7 +25,7 @@ function DetailJumlahPengangguran() {
|
||||
stateDetail.delete.byId(selectedId)
|
||||
setModalHapus(false)
|
||||
setSelectedId(null)
|
||||
router.push("/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran")
|
||||
router.push("/admin/ekonomi/jumlah-pengangguran")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ function DetailJumlahPengangguran() {
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"}>Tahun</Text>
|
||||
<Text>{stateDetail.findUnique.data?.year}</Text>
|
||||
<Text>{stateDetail.findUnique.data?.year ? new Date(stateDetail.findUnique.data.year).getFullYear() : ''}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"}>Bulan</Text>
|
||||
@@ -86,7 +86,7 @@ function DetailJumlahPengangguran() {
|
||||
color={"red"}>
|
||||
<IconX size={20} />
|
||||
</Button>
|
||||
<Button onClick={() => router.push(`/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran/${stateDetail.findUnique.data?.id}/edit`)} color="green">
|
||||
<Button onClick={() => router.push(`/admin/ekonomi/jumlah-pengangguran/${stateDetail.findUnique.data?.id}/edit`)} color="green">
|
||||
<IconEdit size={20} />
|
||||
</Button>
|
||||
</Flex>
|
||||
@@ -108,4 +108,3 @@ function DetailJumlahPengangguran() {
|
||||
}
|
||||
|
||||
export default DetailJumlahPengangguran;
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ function CreateJumlahPengangguran() {
|
||||
/>
|
||||
<TextInput
|
||||
label="Tahun"
|
||||
type="number"
|
||||
type="date"
|
||||
value={stateDetail.create.form.year}
|
||||
onChange={(e) =>
|
||||
(stateDetail.create.form.year = Number(e.currentTarget.value))
|
||||
|
||||
@@ -8,21 +8,29 @@ import { useEffect, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
import { BarChart } from '@mantine/charts';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import JudulList from '../../_com/judulList';
|
||||
import jumlahPengangguranState from '../../_state/ekonomi/jumlah-pengangguran';
|
||||
import JudulListTab from '../../_com/judulListTab';
|
||||
|
||||
function DetailDataPengangguran() {
|
||||
const [search, setSearch] = useState("")
|
||||
return (
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Detail Data Pengangguran</Title>
|
||||
<ListDetailDataPengangguran />
|
||||
<HeaderSearch
|
||||
title='Detail Data Pengangguran'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListDetailDataPengangguran search={search} />
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListDetailDataPengangguran() {
|
||||
function ListDetailDataPengangguran({search}: {search: string}) {
|
||||
|
||||
type DetailDataPengangguran = {
|
||||
id: string;
|
||||
@@ -37,7 +45,6 @@ function ListDetailDataPengangguran() {
|
||||
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
|
||||
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran)
|
||||
const router = useRouter();
|
||||
const [search, setSearch] = useState("")
|
||||
|
||||
useShallowEffect(() => {
|
||||
setMounted(true)
|
||||
@@ -50,7 +57,7 @@ function ListDetailDataPengangguran() {
|
||||
setChartData(stateDetail.findMany.data.map((item) => ({
|
||||
id: item.id,
|
||||
month: item.month,
|
||||
year: item.year,
|
||||
year: item.year instanceof Date ? item.year.getFullYear() : Number(item.year),
|
||||
educatedUnemployment: Number(item.educatedUnemployment),
|
||||
uneducatedUnemployment: Number(item.uneducatedUnemployment),
|
||||
percentageChange: Number(item.percentageChange),
|
||||
@@ -78,13 +85,9 @@ function ListDetailDataPengangguran() {
|
||||
<Box>
|
||||
<Stack gap={"md"}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulListTab
|
||||
<JudulList
|
||||
title='List Detail Data Pengangguran'
|
||||
href='/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create'
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={16} />}
|
||||
href='/admin/ekonomi/jumlah-pengangguran/create'
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
@@ -102,7 +105,7 @@ function ListDetailDataPengangguran() {
|
||||
<TableTd>{item.educatedUnemployment}</TableTd>
|
||||
<TableTd>{item.uneducatedUnemployment}</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran/${item.id}`)}>
|
||||
<Button onClick={() => router.push(`/admin/ekonomi/jumlah-pengangguran/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
|
||||
@@ -55,17 +55,17 @@ function EditLowonganKerja() {
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
lowonganKerjaState.update.form = {
|
||||
...lowonganKerjaState.update.form,
|
||||
posisi: formData.posisi,
|
||||
namaPerusahaan: formData.namaPerusahaan,
|
||||
lokasi: formData.lokasi,
|
||||
tipePekerjaan: formData.tipePekerjaan,
|
||||
gaji: formData.gaji,
|
||||
deskripsi: formData.deskripsi,
|
||||
kualifikasi: formData.kualifikasi,
|
||||
}
|
||||
await lowonganState.update.update()
|
||||
// Set the ID for the update
|
||||
lowonganState.update.id = params?.id as string;
|
||||
|
||||
// Update the form state
|
||||
lowonganState.update.form = {
|
||||
...lowonganState.update.form,
|
||||
...formData
|
||||
};
|
||||
|
||||
// Call the update function
|
||||
await lowonganState.update.update();
|
||||
toast.success("Lowongan kerja berhasil diperbarui!");
|
||||
router.push("/admin/ekonomi/lowongan-kerja-lokal");
|
||||
} catch (error) {
|
||||
@@ -88,7 +88,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
value={formData.posisi}
|
||||
onChange={(val) => {
|
||||
formData.posisi = val.target.value;
|
||||
setFormData(prev => ({ ...prev, posisi: val.target.value }));
|
||||
}}
|
||||
label={<Text fw={"bold"} fz={"sm"}>Posisi</Text>}
|
||||
placeholder='Masukkan posisi'
|
||||
@@ -96,7 +96,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
value={formData.namaPerusahaan}
|
||||
onChange={(val) => {
|
||||
formData.namaPerusahaan = val.target.value;
|
||||
setFormData(prev => ({ ...prev, namaPerusahaan: val.target.value }));
|
||||
}}
|
||||
label={<Text fw={"bold"} fz={"sm"}>Nama Perusahaan</Text>}
|
||||
placeholder='Masukkan nama perusahaan'
|
||||
@@ -104,7 +104,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
value={formData.lokasi}
|
||||
onChange={(val) => {
|
||||
formData.lokasi = val.target.value;
|
||||
setFormData(prev => ({ ...prev, lokasi: val.target.value }));
|
||||
}}
|
||||
label={<Text fw={"bold"} fz={"sm"}>Lokasi</Text>}
|
||||
placeholder='Masukkan lokasi'
|
||||
@@ -112,7 +112,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
value={formData.tipePekerjaan}
|
||||
onChange={(val) => {
|
||||
formData.tipePekerjaan = val.target.value;
|
||||
setFormData(prev => ({ ...prev, tipePekerjaan: val.target.value }));
|
||||
}}
|
||||
label={<Text fw={"bold"} fz={"sm"}>Tipe Pekerjaan</Text>}
|
||||
placeholder='Masukkan tipe pekerjaan'
|
||||
@@ -120,7 +120,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
value={formData.gaji}
|
||||
onChange={(val) => {
|
||||
formData.gaji = val.target.value;
|
||||
setFormData(prev => ({ ...prev, gaji: val.target.value }));
|
||||
}}
|
||||
label={<Text fw={"bold"} fz={"sm"}>Gaji selama 1 bulan</Text>}
|
||||
placeholder='Masukkan gaji'
|
||||
@@ -130,7 +130,7 @@ function EditLowonganKerja() {
|
||||
<EditEditor
|
||||
value={formData.deskripsi}
|
||||
onChange={(val) => {
|
||||
formData.deskripsi = val;
|
||||
setFormData(prev => ({ ...prev, deskripsi: val }));
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
@@ -139,7 +139,7 @@ function EditLowonganKerja() {
|
||||
<EditEditor
|
||||
value={formData.kualifikasi}
|
||||
onChange={(val) => {
|
||||
formData.kualifikasi = val;
|
||||
setFormData(prev => ({ ...prev, kualifikasi: val }));
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import JudulList from '../../_com/judulList';
|
||||
@@ -30,20 +30,21 @@ function ListLowonganKerjaLokal({ search }: { search: string }) {
|
||||
const lowonganState = useProxy(lowonganKerjaState)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = lowonganState.findMany
|
||||
|
||||
useShallowEffect(() => {
|
||||
lowonganState.findMany.load();
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (lowonganState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.posisi.toLowerCase().includes(keyword) ||
|
||||
item.namaPerusahaan.toLowerCase().includes(keyword) ||
|
||||
item.lokasi.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!lowonganState.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -60,18 +61,24 @@ function ListLowonganKerjaLokal({ search }: { search: string }) {
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Bekerja Sebagai</TableTh>
|
||||
<TableTh>Nama Usaha</TableTh>
|
||||
<TableTh>Alamat Usaha</TableTh>
|
||||
<TableTh>Pekerjaan</TableTh>
|
||||
<TableTh>Nama Perusahaan</TableTh>
|
||||
<TableTh>Lokasi</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.posisi}</TableTd>
|
||||
<TableTd>{item.namaPerusahaan}</TableTd>
|
||||
<TableTd>{item.lokasi}</TableTd>
|
||||
<TableTd>
|
||||
<Text fz={"md"}>{item.posisi}</Text>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text fz={"md"}>{item.namaPerusahaan}</Text>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text fz={"md"}>{item.lokasi}</Text>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/ekonomi/lowongan-kerja-lokal/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
@@ -82,6 +89,14 @@ function ListLowonganKerjaLokal({ search }: { search: string }) {
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -13,31 +13,39 @@ import pasarDesaState from '../../../_state/ekonomi/pasar-desa/pasar-desa';
|
||||
|
||||
|
||||
function PasarDesa() {
|
||||
const [search, setSearch] = useState("")
|
||||
const [search2, setSearch2] = useState("")
|
||||
return (
|
||||
<Box>
|
||||
<HeaderSearch
|
||||
title='Kategori Produk'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
value={search2}
|
||||
onChange={(e) => setSearch2(e.currentTarget.value)}
|
||||
/>
|
||||
<ListPasarDesa search={search} />
|
||||
<ListPasarDesa search2={search2} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListPasarDesa({ search }: { search: string }) {
|
||||
function ListPasarDesa({ search2 }: { search2: string }) {
|
||||
const statePasar = useProxy(pasarDesaState.kategoriProduk)
|
||||
const [modalHapus, setModalHapus] = useState(false)
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
// const params = useParams()
|
||||
const router = useRouter()
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = statePasar.findMany
|
||||
|
||||
useShallowEffect(() => {
|
||||
statePasar.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search2)
|
||||
}, [page, search2])
|
||||
|
||||
const handleHapus = () => {
|
||||
if (selectedId) {
|
||||
@@ -47,14 +55,9 @@ function ListPasarDesa({ search }: { search: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
const filteredData = (statePasar.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.nama.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!statePasar.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -99,6 +102,14 @@ function ListPasarDesa({ search }: { search: string }) {
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
/>
|
||||
</Center>
|
||||
{/* Modal Konfirmasi Hapus */}
|
||||
<ModalKonfirmasiHapus
|
||||
opened={modalHapus}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -30,21 +30,21 @@ function ListPasarDesa({ search }: { search: string }) {
|
||||
const statePasar = useProxy(pasarDesaState.pasarDesa)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = statePasar.findMany
|
||||
|
||||
useShallowEffect(() => {
|
||||
statePasar.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (statePasar.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.nama.toLowerCase().includes(keyword) ||
|
||||
item.harga.toString().toLowerCase().includes(keyword) ||
|
||||
item.rating.toString().toLowerCase().includes(keyword) ||
|
||||
item.alamatUsaha.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!statePasar.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -86,6 +86,14 @@ function ListPasarDesa({ search }: { search: string }) {
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import JudulList from '../../_com/judulList';
|
||||
@@ -23,7 +23,7 @@ function ProgramKemiskinan() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListProgramKemiskinan search={search}/>
|
||||
<ListProgramKemiskinan search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -34,14 +34,22 @@ function ListProgramKemiskinan({ search }: { search: string }) {
|
||||
const [lineChart, setLineChart] = useState<any[]>([]);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = programState.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
setMounted(true)
|
||||
programState.findMany.load()
|
||||
load(page, 10, search)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (programState.findMany.data) {
|
||||
const chartData = programState.findMany.data
|
||||
if (data) {
|
||||
const chartData = data
|
||||
.filter(item => item.statistik)
|
||||
.map(item => ({
|
||||
tahun: item.statistik?.tahun,
|
||||
@@ -52,18 +60,11 @@ function ListProgramKemiskinan({ search }: { search: string }) {
|
||||
setLineChart(chartData);
|
||||
|
||||
}
|
||||
}, [programState.findMany.data])
|
||||
}, [data])
|
||||
|
||||
const filteredData = (programState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.nama.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword) ||
|
||||
item.statistik?.tahun.toString().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!programState.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -112,7 +113,7 @@ function ListProgramKemiskinan({ search }: { search: string }) {
|
||||
<Box >
|
||||
<Title pb={10} order={3}>Grafik Berdasarkan Responden</Title>
|
||||
{mounted && lineChart.length > 0 ? (<Box style={{ width: '100%', height: 'auto', }}>
|
||||
<Box w={"100%"} style={{overflowX: 'auto'}}>
|
||||
<Box w={"100%"} style={{ overflowX: 'auto' }}>
|
||||
<LineChart
|
||||
width={820}
|
||||
height={300}
|
||||
@@ -143,6 +144,14 @@ function ListProgramKemiskinan({ search }: { search: string }) {
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Paper, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import grafikSektorUnggulan from '../../../_state/ekonomi/sektor-unggulan-desa';
|
||||
import CreateEditor from '../../../_com/createEditor';
|
||||
|
||||
function CreateSektorUnggulanDesa() {
|
||||
const stateGrafik= useProxy(grafikSektorUnggulan);
|
||||
const stateGrafik = useProxy(grafikSektorUnggulan);
|
||||
const [chartData, setChartData] = useState<any[]>([]);
|
||||
const router = useRouter()
|
||||
|
||||
@@ -54,15 +55,15 @@ function CreateSektorUnggulanDesa() {
|
||||
stateGrafik.create.form.name = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Deskripsi Sektor Unggulan"
|
||||
type="text"
|
||||
value={stateGrafik.create.form.description}
|
||||
placeholder="Masukkan deskripsi sektor unggulan"
|
||||
onChange={(val) => {
|
||||
stateGrafik.create.form.description = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"sm"}>Deskripsi Sektor Ungggulan</Text>
|
||||
<CreateEditor
|
||||
value={stateGrafik.create.form.description}
|
||||
onChange={(val) => {
|
||||
stateGrafik.create.form.description = val;
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<TextInput
|
||||
label="Jumlah"
|
||||
type="number"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { Box, Button, Paper, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import JudulList from '../../_com/judulList';
|
||||
@@ -30,7 +30,7 @@ function SektorUnggulanDesa() {
|
||||
function ListSektorUnggulanDesa({ search }: { search: string }) {
|
||||
const router = useRouter();
|
||||
const state = useProxy(grafikSektorUnggulan);
|
||||
const [chartData, setChartData] = useState<{id: string; name: string; description: string | null; value: number | null}[]>([]);
|
||||
const [chartData, setChartData] = useState<{ id: string; name: string; description: string | null; value: number | null }[]>([]);
|
||||
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
|
||||
const isTablet = useMediaQuery('(max-width: 1024px)')
|
||||
const isMobile = useMediaQuery('(max-width: 768px)')
|
||||
@@ -61,38 +61,41 @@ function ListSektorUnggulanDesa({ search }: { search: string }) {
|
||||
}, [state.findMany.data]);
|
||||
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Sektor Unggulan Desa'
|
||||
href='/admin/ekonomi/sektor-unggulan-desa/create'
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Sektor Unggulan</TableTh>
|
||||
<TableTh>Deskripsi Sektor Unggulan</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>{item.description}</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/ekonomi/sektor-unggulan-desa/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Sektor Unggulan Desa'
|
||||
href='/admin/ekonomi/sektor-unggulan-desa/create'
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Sektor Unggulan</TableTh>
|
||||
<TableTh>Deskripsi Sektor Unggulan</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate={"end"} fz={'sm'} lineClamp={1} dangerouslySetInnerHTML={{ __html: item.description || '' }}></Text>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/ekonomi/sektor-unggulan-desa/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
|
||||
{/* Chart */}
|
||||
{!mounted && !chartData ? (
|
||||
{/* Chart */}
|
||||
{!mounted && !chartData ? (
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title pb={10} order={3}>Grafik Hasil Kepuasan Masyarakat</Title>
|
||||
@@ -115,6 +118,7 @@ function ListSektorUnggulanDesa({ search }: { search: string }) {
|
||||
</Paper>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ function DetailKeamananLingkungan() {
|
||||
{keamananState.findUnique.data ? (
|
||||
<Paper key={keamananState.findUnique.data.id} bg={colors['BG-trans']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Gambar</Text>
|
||||
<Image w={{ base: 150, md: 490}} src={keamananState.findUnique.data?.image?.link} alt="gambar" />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Judul Keamanan Lingkungan</Text>
|
||||
<Text fz={"lg"}>{keamananState.findUnique.data?.name}</Text>
|
||||
@@ -62,10 +66,6 @@ function DetailKeamananLingkungan() {
|
||||
<Text fw={"bold"} fz={"lg"}>Deskripsi</Text>
|
||||
<Text fz={"lg"} dangerouslySetInnerHTML={{ __html: keamananState.findUnique.data?.deskripsi }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Gambar</Text>
|
||||
<Image w={{ base: 150, md: 150, lg: 150 }} src={keamananState.findUnique.data?.image?.link} alt="gambar" />
|
||||
</Box>
|
||||
<Flex gap={"xs"} mt={10}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import JudulList from '../../_com/judulList';
|
||||
@@ -30,19 +30,21 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
||||
const keamananState = useProxy(keamananLingkunganState)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = keamananState.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
keamananState.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (keamananState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!keamananState.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -67,9 +69,15 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
<Text fz={"md"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
<Box w={180}>
|
||||
<Text fz={"md"} truncate={"end"} lineClamp={1}>{item.name}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={250}>
|
||||
<Text fz={"md"} truncate={"end"} lineClamp={1} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/keamanan/keamanan-lingkungan-pecalang-patwal/${item.id}`)}>
|
||||
@@ -81,6 +89,14 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -21,7 +21,7 @@ function PolsekTerdekat() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListPolsekTerdekat search={search}/>
|
||||
<ListPolsekTerdekat search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -30,20 +30,21 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
||||
const polsekState = useProxy(polsekTerdekat)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = polsekState.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
polsekState.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (polsekState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.nama.toLowerCase().includes(keyword) ||
|
||||
item.jarakKeDesa.toLowerCase().includes(keyword) ||
|
||||
item.alamat.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!polsekState.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -64,24 +65,44 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
||||
<TableTh>Jarak Polsek</TableTh>
|
||||
<TableTh>Alamat</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.nama}</TableTd>
|
||||
<TableTd>{item.jarakKeDesa}</TableTd>
|
||||
<TableTd>{item.alamat}</TableTd>
|
||||
<TableTd>
|
||||
<Box w={180}>
|
||||
<Text fz='md' truncate={"end"} lineClamp={1}>{item.nama}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={180}>
|
||||
<Text fz='md' truncate={"end"} lineClamp={1}>{item.jarakKeDesa}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={250}>
|
||||
<Text fz='md' truncate={"end"} lineClamp={1}>{item.alamat}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/keamanan/polsek-terdekat/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import JudulList from '../../_com/judulList';
|
||||
@@ -30,19 +30,21 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
||||
const stateKeamanan = useProxy(tipsKeamananState)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = stateKeamanan.findMany
|
||||
|
||||
useShallowEffect(() => {
|
||||
stateKeamanan.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (stateKeamanan.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.judul.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!stateKeamanan.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -67,9 +69,15 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.judul}</TableTd>
|
||||
<TableTd>
|
||||
<Text fz={"xs"} dangerouslySetInnerHTML={{__html: item.deskripsi}} />
|
||||
<Box w={150}>
|
||||
<Text fz={"md"} truncate={"end"} lineClamp={1}>{item.judul}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={250}>
|
||||
<Text fz={"md"} truncate={"end"} lineClamp={1} dangerouslySetInnerHTML={{__html: item.deskripsi}} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/keamanan/tips-keamanan/${item.id}`)}>
|
||||
@@ -81,6 +89,14 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -22,7 +22,7 @@ function ArtikelKesehatan() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListArtikelKesehatan search={search}/>
|
||||
<ListArtikelKesehatan search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -46,45 +46,53 @@ function ListArtikelKesehatan({ search }: { search: string }) {
|
||||
if (!stateArtikelKesehatan.findMany.data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500}/>
|
||||
<Skeleton h={500} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Artikel Kesehatan'
|
||||
href='/admin/kesehatan/data-kesehatan-warga/artikel_kesehatan/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Judul</TableTh>
|
||||
<TableTh>Content</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.title}</TableTd>
|
||||
<TableTd>{item.content}</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/artikel_kesehatan/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Artikel Kesehatan'
|
||||
href='/admin/kesehatan/data-kesehatan-warga/artikel_kesehatan/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Judul</TableTh>
|
||||
<TableTh>Content</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>
|
||||
<Box w={100}>
|
||||
<Text truncate={'end'} lineClamp={1} fz={'h5'}>{item.title}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={200}>
|
||||
<Text truncate={'end'} lineClamp={1} fz={'h5'}>{item.content}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/artikel_kesehatan/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ interface FasilitasKesehatanFormBase {
|
||||
}
|
||||
|
||||
function EditFasilitasKesehatan() {
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState);
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState.fasilitasKesehatan);
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
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, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
||||
import { Box, Button, Flex, Grid, GridCol, 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';
|
||||
@@ -12,7 +12,7 @@ import { useProxy } from 'valtio/utils';
|
||||
function DetailFasilitasKesehatan() {
|
||||
const params = useParams()
|
||||
const router = useRouter();
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState)
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState.fasilitasKesehatan)
|
||||
const [modalHapus, setModalHapus] = useState(false);
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
|
||||
@@ -45,9 +45,23 @@ function DetailFasilitasKesehatan() {
|
||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||
</Button>
|
||||
</Box>
|
||||
<Paper w={{ base: "100%", md: "50%" }} bg={colors['white-1']} p={'md'}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Text fz={"xl"} fw={"bold"}>Detail Fasilitas Kesehatan</Text>
|
||||
<Grid>
|
||||
<GridCol span={12}>
|
||||
<Text fz={"xl"} fw={"bold"}>Detail Fasilitas Kesehatan</Text>
|
||||
</GridCol>
|
||||
{/* <GridCol span={12}>
|
||||
<Flex gap={"xs"}>
|
||||
<Button color={colors['blue-button']} onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/${params?.id}/dokter-tenaga-medis`)}>
|
||||
Tambah Dokter
|
||||
</Button>
|
||||
<Button color={colors['blue-button']} onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/${params?.id}/layanan-unggulan/create`)}>
|
||||
Tambah Layanan
|
||||
</Button>
|
||||
</Flex>
|
||||
</GridCol> */}
|
||||
</Grid>
|
||||
{stateFasilitasKesehatan.findUnique.data ? (
|
||||
<Paper bg={colors['BG-trans']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
@@ -68,6 +82,14 @@ function DetailFasilitasKesehatan() {
|
||||
<Text fz={"md"} fw={"bold"}>Layanan Unggulan</Text>
|
||||
<Text fz={"md"} dangerouslySetInnerHTML={{ __html: stateFasilitasKesehatan.findUnique.data.layananunggulan.content }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Fasilitas Pendukung</Text>
|
||||
<Text fz={"md"} dangerouslySetInnerHTML={{ __html: stateFasilitasKesehatan.findUnique.data.fasilitaspendukung.content }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Prosedur Pendaftaran</Text>
|
||||
<Text fz={"md"} dangerouslySetInnerHTML={{ __html: stateFasilitasKesehatan.findUnique.data.prosedurpendaftaran.content }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"md"} fw={"bold"}>Dokter dan Tenaga Medis</Text>
|
||||
<Text fz={"md"} fw={"bold"}>Nama Dokter</Text>
|
||||
@@ -77,14 +99,6 @@ function DetailFasilitasKesehatan() {
|
||||
<Text fz={"md"} fw={"bold"}>Jadwal</Text>
|
||||
<Text fz={"md"}>{stateFasilitasKesehatan.findUnique.data.dokterdantenagamedis.jadwal}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Fasilitas Pendukung</Text>
|
||||
<Text fz={"md"} dangerouslySetInnerHTML={{ __html: stateFasilitasKesehatan.findUnique.data.fasilitaspendukung.content }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Prosedur Pendaftaran</Text>
|
||||
<Text fz={"md"} dangerouslySetInnerHTML={{ __html: stateFasilitasKesehatan.findUnique.data.prosedurpendaftaran.content }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Tarif dan Layanan</Text>
|
||||
<Text fz={"md"} fw={"bold"}>Layanan</Text>
|
||||
@@ -111,6 +125,7 @@ function DetailFasilitasKesehatan() {
|
||||
</Paper>
|
||||
) : null}
|
||||
</Stack>
|
||||
|
||||
</Paper>
|
||||
|
||||
{/* Modal Hapus */}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useProxy } from 'valtio/utils';
|
||||
|
||||
|
||||
function CreateFasilitasKesehatan() {
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState)
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState.fasilitasKesehatan)
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<div>
|
||||
Page
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<div>
|
||||
Page
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,75 @@
|
||||
'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 { useProxy } from 'valtio/utils';
|
||||
|
||||
|
||||
function CreateDokter() {
|
||||
const params = useParams()
|
||||
const createState = useProxy(fasilitasKesehatanState.dokter)
|
||||
const router = useRouter();
|
||||
|
||||
const resetForm = () => {
|
||||
createState.create.create.form = {
|
||||
name: "",
|
||||
specialist: "",
|
||||
jadwal: "",
|
||||
};
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
await createState.create.create.create();
|
||||
resetForm();
|
||||
router.push(`/admin/kesehatan/fasilitas-kesehatan/${params?.id}/dokter-tenaga-medis`)
|
||||
};
|
||||
return (
|
||||
<Box component="form" onSubmit={handleSubmit}>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Paper bg={colors['white-1']} p="md" w={{ base: '100%', md: '50%' }}>
|
||||
<Stack gap="xs">
|
||||
<Title order={3}>Create Dokter</Title>
|
||||
<TextInput
|
||||
label={<Text fz="sm" fw="bold">Nama Dokter</Text>}
|
||||
placeholder="masukkan nama dokter"
|
||||
value={createState.create.create.form.name}
|
||||
onChange={(e) => {
|
||||
createState.create.create.form.name = e.target.value;
|
||||
}}
|
||||
/>
|
||||
<Text fz="md" fw="bold">Specialist</Text>
|
||||
<TextInput
|
||||
label={<Text fz="sm" fw="bold">Specialist</Text>}
|
||||
placeholder="masukkan specialist"
|
||||
value={createState.create.create.form.specialist}
|
||||
onChange={(e) => {
|
||||
createState.create.create.form.specialist = e.target.value;
|
||||
}}
|
||||
/>
|
||||
<Box>
|
||||
<Text fz="md" fw="bold">Jadwal</Text>
|
||||
<CreateEditor
|
||||
value={createState.create.create.form.jadwal}
|
||||
onChange={(htmlContent) => {
|
||||
createState.create.create.form.jadwal = htmlContent;
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Button onClick={handleSubmit} bg={colors['blue-button']}>
|
||||
Simpan
|
||||
</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default CreateDokter;
|
||||
@@ -0,0 +1,112 @@
|
||||
'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 { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconArrowBack, IconDeviceImacCog, 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';
|
||||
|
||||
|
||||
function DokterTenagaMedis() {
|
||||
const [search, setSearch] = useState("");
|
||||
const router = useRouter();
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||
</Button>
|
||||
</Box>
|
||||
<HeaderSearch
|
||||
title='Dokter dan Tenaga Medis'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListDokterTenagaMedis search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListDokterTenagaMedis({ search }: { search: string }) {
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState.dokter)
|
||||
const router = useRouter();
|
||||
const {
|
||||
data,
|
||||
loading,
|
||||
load,
|
||||
page,
|
||||
totalPages
|
||||
} = stateFasilitasKesehatan.findMany
|
||||
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = data || []
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Fasilitas Kesehatan'
|
||||
href={`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/create`}
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Fasilitas Kesehatan</TableTh>
|
||||
<TableTh>Alamat</TableTh>
|
||||
<TableTh>Jam Operasional</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>{item.specialist}</TableTd>
|
||||
<TableTd>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.jadwal }} />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)} // ini penting!
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default DokterTenagaMedis;
|
||||
@@ -4,17 +4,39 @@ import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableT
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import fasilitasKesehatanState from '../../../_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
import { useState } from 'react';
|
||||
import fasilitasKesehatanState from '../../../_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
|
||||
|
||||
function FasilitasKesehatan() {
|
||||
const [search, setSearch] = useState("");
|
||||
// const router = useRouter();
|
||||
return (
|
||||
<Box>
|
||||
{/* <Grid>
|
||||
<GridCol span={12}>
|
||||
<HeaderSearch
|
||||
title='Fasilitas Kesehatan'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
</GridCol>
|
||||
<GridCol span={12}>
|
||||
<Flex gap={"xs"}>
|
||||
<Button color={colors['blue-button']} onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis`)}>
|
||||
<IconList size={20} /> List Dokter
|
||||
</Button>
|
||||
<Button color={colors['blue-button']} onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/tarif-layanan`)}>
|
||||
<IconList size={20} /> List Layanan
|
||||
</Button>
|
||||
</Flex>
|
||||
</GridCol>
|
||||
</Grid> */}
|
||||
<HeaderSearch
|
||||
title='Fasilitas Kesehatan'
|
||||
placeholder='pencarian'
|
||||
@@ -22,13 +44,13 @@ function FasilitasKesehatan() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListFasilitasKesehatan search={search}/>
|
||||
<ListFasilitasKesehatan search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListFasilitasKesehatan({ search }: { search: string }) {
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState)
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState.fasilitasKesehatan)
|
||||
const router = useRouter();
|
||||
|
||||
useShallowEffect(() => {
|
||||
@@ -47,47 +69,47 @@ function ListFasilitasKesehatan({ search }: { search: string }) {
|
||||
if (!stateFasilitasKesehatan.findMany.data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500}/>
|
||||
<Skeleton h={500} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Fasilitas Kesehatan'
|
||||
href='/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Fasilitas Kesehatan</TableTh>
|
||||
<TableTh>Alamat</TableTh>
|
||||
<TableTh>Jam Operasional</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>{item.informasiumum.alamat}</TableTd>
|
||||
<TableTd>{item.informasiumum.jamOperasional}</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Fasilitas Kesehatan'
|
||||
href='/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Fasilitas Kesehatan</TableTh>
|
||||
<TableTh>Dokter</TableTh>
|
||||
<TableTh>Layanan</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>{item.dokterdantenagamedis.name}</TableTd>
|
||||
<TableTd>{item.tarifdanlayanan.layanan}</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
'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 { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconArrowBack, IconDeviceImacCog, 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';
|
||||
|
||||
|
||||
function TarifLayanan() {
|
||||
const [search, setSearch] = useState("");
|
||||
const router = useRouter();
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||
</Button>
|
||||
</Box>
|
||||
<HeaderSearch
|
||||
title='Dokter dan Tenaga Medis'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListTarifLayanan search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListTarifLayanan({ search }: { search: string }) {
|
||||
const stateFasilitasKesehatan = useProxy(fasilitasKesehatanState.dokter)
|
||||
const router = useRouter();
|
||||
const {
|
||||
data,
|
||||
loading,
|
||||
load,
|
||||
page,
|
||||
totalPages
|
||||
} = stateFasilitasKesehatan.findMany
|
||||
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = data || []
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Fasilitas Kesehatan'
|
||||
href={`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/dokter-tenaga-medis/create`}
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Fasilitas Kesehatan</TableTh>
|
||||
<TableTh>Alamat</TableTh>
|
||||
<TableTh>Jam Operasional</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>{item.specialist}</TableTd>
|
||||
<TableTd>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.jadwal }} />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)} // ini penting!
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default TarifLayanan;
|
||||
@@ -0,0 +1,116 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import grafikkepuasan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/grafikKepuasan';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function EditGrafikHasilKepuasan() {
|
||||
const editState = useProxy(grafikkepuasan)
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const [formData, setFormData] = useState({
|
||||
nama: editState.update.form.nama || '',
|
||||
tanggal: editState.update.form.tanggal || '',
|
||||
jenisKelamin: editState.update.form.jenisKelamin || '',
|
||||
alamat: editState.update.form.alamat || '',
|
||||
penyakit: editState.update.form.penyakit || '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const loadKelahiran = async () => {
|
||||
const id = params?.id as string;
|
||||
if (!id) return;
|
||||
|
||||
try {
|
||||
const data = await editState.update.load(id); // akses langsung, bukan dari proxy
|
||||
if (data) {
|
||||
setFormData({
|
||||
nama: data.nama || '',
|
||||
tanggal: data.tanggal || '',
|
||||
jenisKelamin: data.jenisKelamin || '',
|
||||
alamat: data.alamat || '',
|
||||
penyakit: data.penyakit || '',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik hasil kepuasan:", error);
|
||||
toast.error("Gagal memuat data grafik hasil kepuasan");
|
||||
}
|
||||
};
|
||||
|
||||
loadKelahiran();
|
||||
}, [params?.id]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
editState.update.form = {
|
||||
...editState.update.form,
|
||||
nama: formData.nama,
|
||||
tanggal: formData.tanggal,
|
||||
jenisKelamin: formData.jenisKelamin,
|
||||
alamat: formData.alamat,
|
||||
penyakit: formData.penyakit,
|
||||
};
|
||||
await editState.update.submit();
|
||||
toast.success('grafik hasil kepuasan berhasil diperbarui!');
|
||||
router.push('/admin/kesehatan/data-kesehatan-warga/grafik_hasil_kepuasan');
|
||||
} catch (error) {
|
||||
console.error('Error updating grafik hasil kepuasan:', error);
|
||||
toast.error('Terjadi kesalahan saat memperbarui grafik hasil kepuasan');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack color={colors["blue-button"]} size={30} />
|
||||
</Button>
|
||||
</Box>
|
||||
<Paper bg={"white"} p={"md"} w={{ base: "100%", md: "50%" }}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Edit grafik hasil kepuasan</Title>
|
||||
<TextInput
|
||||
value={formData.nama}
|
||||
onChange={(e) => setFormData({ ...formData, nama: e.target.value })}
|
||||
label={<Text fz={"sm"} fw={"bold"}>Nama</Text>}
|
||||
placeholder="masukkan nama"
|
||||
/>
|
||||
<TextInput
|
||||
type='date'
|
||||
value={formData.tanggal}
|
||||
onChange={(e) => setFormData({ ...formData, tanggal: e.target.value })}
|
||||
label={<Text fz={"sm"} fw={"bold"}>Tanggal</Text>}
|
||||
placeholder="masukkan tanggal"
|
||||
/>
|
||||
<TextInput
|
||||
value={formData.jenisKelamin}
|
||||
onChange={(e) => setFormData({ ...formData, jenisKelamin: e.target.value })}
|
||||
label={<Text fz={"sm"} fw={"bold"}>Jenis Kelamin</Text>}
|
||||
placeholder="masukkan jenis kelamin"
|
||||
/>
|
||||
<TextInput
|
||||
value={formData.alamat}
|
||||
onChange={(e) => setFormData({ ...formData, alamat: e.target.value })}
|
||||
label={<Text fz={"sm"} fw={"bold"}>Alamat</Text>}
|
||||
placeholder="masukkan alamat"
|
||||
/>
|
||||
<TextInput
|
||||
value={formData.penyakit}
|
||||
onChange={(e) => setFormData({ ...formData, penyakit: e.target.value })}
|
||||
label={<Text fz={"sm"} fw={"bold"}>Penyakit</Text>}
|
||||
placeholder="masukkan penyakit"
|
||||
/>
|
||||
<Button onClick={handleSubmit}>Simpan</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditGrafikHasilKepuasan;
|
||||
@@ -1,80 +1,125 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
|
||||
import grafikkepuasan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/grafikKepuasan';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useEffect } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function EditGrafikHasilKepuasan() {
|
||||
import { Box, Button, Flex, 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 { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus';
|
||||
import grafikkepuasan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/grafikKepuasan';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
|
||||
function DetailGrafikHasilKepuasan() {
|
||||
const state = useProxy(grafikkepuasan)
|
||||
const [modalHapus, setModalHapus] = useState(false)
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
const params = useParams()
|
||||
const router = useRouter()
|
||||
const params = useParams() as { id: string }
|
||||
const stateGrafikKepuasan = useProxy(grafikkepuasan)
|
||||
|
||||
const id = params.id
|
||||
useShallowEffect(() => {
|
||||
state.findUnique.load(params?.id as string)
|
||||
}, [])
|
||||
|
||||
// Load data saat komponen mount
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
stateGrafikKepuasan.findUnique.load(id).then(() => {
|
||||
const data = stateGrafikKepuasan.findUnique.data
|
||||
if (data) {
|
||||
stateGrafikKepuasan.update.form = {
|
||||
label: data.label || '',
|
||||
jumlah: data.jumlah || '',
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleHapus = () => {
|
||||
if (selectedId) {
|
||||
state.delete.byId(selectedId)
|
||||
setModalHapus(false)
|
||||
setSelectedId(null)
|
||||
router.push("/admin/kesehatan/data-kesehatan-warga/grafik_hasil_kepuasan")
|
||||
}
|
||||
}, [id])
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// Set the ID before submitting
|
||||
stateGrafikKepuasan.update.id = id;
|
||||
await stateGrafikKepuasan.update.submit();
|
||||
router.push('/admin/kesehatan/data-kesehatan-warga/grafik_hasil_kepuasan')
|
||||
}
|
||||
return (
|
||||
|
||||
if (!state.findUnique.data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={40} />
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack size={20} />
|
||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||
</Button>
|
||||
</Box>
|
||||
<Paper bg={colors['white-1']} w={{ base: '100%', md: '50%' }} p={'md'}>
|
||||
<Paper bg={colors['white-1']} w={{ base: "100%", md: "100%", lg: "50%" }} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>Edit Grafik Hasil Kepuasan</Title>
|
||||
<TextInput
|
||||
label="Label"
|
||||
placeholder="masukkan label"
|
||||
value={stateGrafikKepuasan.update.form.label}
|
||||
onChange={(val) => {
|
||||
stateGrafikKepuasan.update.form.label = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Jumlah"
|
||||
type="number"
|
||||
placeholder="masukkan jumlah"
|
||||
value={stateGrafikKepuasan.update.form.jumlah}
|
||||
onChange={(val) => {
|
||||
stateGrafikKepuasan.update.form.jumlah = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
Simpan
|
||||
</Button>
|
||||
<Text fz={"xl"} fw={"bold"}>Detail Data Grafik Hasil Kepuasan</Text>
|
||||
{state.findUnique.data ? (
|
||||
<Paper key={state.findUnique.data.id} bg={colors['BG-trans']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Nama</Text>
|
||||
<Text fz={"lg"}>{state.findUnique.data?.nama}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Tanggal</Text>
|
||||
<Text fz={"lg"}>
|
||||
{new Date(state.findUnique.data?.tanggal).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
})}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Jenis Kelamin</Text>
|
||||
<Text fz={"lg"} >{state.findUnique.data?.jenisKelamin}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Alamat</Text>
|
||||
<Text fz={"lg"} >{state.findUnique.data?.alamat}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Penyakit</Text>
|
||||
<Text fz={"lg"} >{state.findUnique.data?.penyakit}</Text>
|
||||
</Box>
|
||||
<Flex gap={"xs"} mt={10}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (state.findUnique.data) {
|
||||
setSelectedId(state.findUnique.data.id);
|
||||
setModalHapus(true);
|
||||
}
|
||||
}}
|
||||
disabled={state.delete.loading || !state.findUnique.data}
|
||||
color={"red"}
|
||||
>
|
||||
<IconX size={20} />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (state.findUnique.data) {
|
||||
router.push(`/admin/kesehatan/data-kesehatan-warga/grafik_hasil_kepuasan/${state.findUnique.data.id}/edit`);
|
||||
}
|
||||
}}
|
||||
disabled={!state.findUnique.data}
|
||||
color={"green"}
|
||||
>
|
||||
<IconEdit size={20} />
|
||||
</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Paper>
|
||||
) : null}
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{/* Modal Konfirmasi Hapus */}
|
||||
<ModalKonfirmasiHapus
|
||||
opened={modalHapus}
|
||||
onClose={() => setModalHapus(false)}
|
||||
onConfirm={handleHapus}
|
||||
text='Apakah anda yakin ingin menghapus data ini?'
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default EditGrafikHasilKepuasan;
|
||||
export default DetailGrafikHasilKepuasan;
|
||||
@@ -16,20 +16,16 @@ function CreateGrafikHasilKepuasanMasyarakat() {
|
||||
|
||||
const resetForm = () => {
|
||||
stateGrafikKepuasan.create.form = {
|
||||
label: "",
|
||||
jumlah: "",
|
||||
nama: "",
|
||||
tanggal: "",
|
||||
jenisKelamin: "",
|
||||
alamat: "",
|
||||
penyakit: "",
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const id = await stateGrafikKepuasan.create.create();
|
||||
if (id) {
|
||||
const idStr = String(id);
|
||||
await stateGrafikKepuasan.findUnique.load(idStr);
|
||||
if (stateGrafikKepuasan.findUnique.data) {
|
||||
setChartData([stateGrafikKepuasan.findUnique.data]);
|
||||
}
|
||||
}
|
||||
await stateGrafikKepuasan.create.create();
|
||||
resetForm();
|
||||
router.push("/admin/kesehatan/data-kesehatan-warga/grafik_hasil_kepuasan");
|
||||
}
|
||||
@@ -45,21 +41,48 @@ function CreateGrafikHasilKepuasanMasyarakat() {
|
||||
<Title order={4}>Tambah Grafik Hasil Kepuasan Masyarakat</Title>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
label="Label"
|
||||
label="Nama"
|
||||
type="text"
|
||||
value={stateGrafikKepuasan.create.form.label}
|
||||
placeholder="Masukkan label"
|
||||
value={stateGrafikKepuasan.create.form.nama}
|
||||
placeholder="Masukkan nama"
|
||||
onChange={(val) => {
|
||||
stateGrafikKepuasan.create.form.label = val.currentTarget.value;
|
||||
stateGrafikKepuasan.create.form.nama = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Jumlah"
|
||||
type="number"
|
||||
value={stateGrafikKepuasan.create.form.jumlah}
|
||||
placeholder="Masukkan jumlah"
|
||||
label="Tanggal"
|
||||
type="date"
|
||||
value={stateGrafikKepuasan.create.form.tanggal}
|
||||
placeholder="Masukkan tanggal"
|
||||
onChange={(val) => {
|
||||
stateGrafikKepuasan.create.form.jumlah = val.currentTarget.value;
|
||||
stateGrafikKepuasan.create.form.tanggal = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Jenis Kelamin"
|
||||
type="text"
|
||||
value={stateGrafikKepuasan.create.form.jenisKelamin}
|
||||
placeholder="Masukkan jenis kelamin"
|
||||
onChange={(val) => {
|
||||
stateGrafikKepuasan.create.form.jenisKelamin = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Alamat"
|
||||
type="text"
|
||||
value={stateGrafikKepuasan.create.form.alamat}
|
||||
placeholder="Masukkan alamat"
|
||||
onChange={(val) => {
|
||||
stateGrafikKepuasan.create.form.alamat = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Penyakit"
|
||||
type="text"
|
||||
value={stateGrafikKepuasan.create.form.penyakit}
|
||||
placeholder="Masukkan penyakit"
|
||||
onChange={(val) => {
|
||||
stateGrafikKepuasan.create.form.penyakit = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<Group>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
||||
import { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import JudulListTab from '../../../_com/judulListTab';
|
||||
import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
|
||||
import grafikkepuasan from '../../../_state/kesehatan/data_kesehatan_warga/grafikKepuasan';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
import grafikkepuasan from '../../../_state/kesehatan/data_kesehatan_warga/grafikKepuasan';
|
||||
|
||||
function GrafikHasilKepuasanMasyarakat() {
|
||||
const [search, setSearch] = useState("");
|
||||
@@ -30,53 +30,79 @@ function GrafikHasilKepuasanMasyarakat() {
|
||||
function ListGrafikHasilKepuasanMasyarakat({ search }: { search: string }) {
|
||||
type PDKMGrafik = {
|
||||
id: string;
|
||||
label: string;
|
||||
jumlah: number;
|
||||
nama: string;
|
||||
tanggal: string | Date; // Allow both string and Date types
|
||||
jenisKelamin: string;
|
||||
alamat: string;
|
||||
penyakit: string;
|
||||
createdAt?: Date; // Add optional fields that might come from the API
|
||||
updatedAt?: Date;
|
||||
deletedAt?: Date | null;
|
||||
}
|
||||
const stateGrafikKepuasan = useProxy(grafikkepuasan);
|
||||
const [chartData, setChartData] = useState<PDKMGrafik[]>([]);
|
||||
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
|
||||
const isTablet = useMediaQuery('(max-width: 1024px)')
|
||||
const isMobile = useMediaQuery('(max-width: 768px)')
|
||||
const [modalHapus, setModalHapus] = useState(false)
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
const router = useRouter();
|
||||
|
||||
const handleDelete = () => {
|
||||
if (selectedId) {
|
||||
stateGrafikKepuasan.delete.byId(selectedId)
|
||||
setModalHapus(false)
|
||||
setSelectedId(null)
|
||||
|
||||
stateGrafikKepuasan.findMany.load()
|
||||
}
|
||||
}
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load
|
||||
} = stateGrafikKepuasan.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
setMounted(true)
|
||||
stateGrafikKepuasan.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
if (stateGrafikKepuasan.findMany.data) {
|
||||
setChartData(stateGrafikKepuasan.findMany.data.map((item) => ({
|
||||
if (data) {
|
||||
setChartData(data.map((item) => ({
|
||||
id: item.id,
|
||||
label: item.label,
|
||||
jumlah: Number(item.jumlah),
|
||||
nama: item.nama,
|
||||
tanggal: item.tanggal instanceof Date ? item.tanggal.toISOString() : item.tanggal,
|
||||
jenisKelamin: item.jenisKelamin,
|
||||
alamat: item.alamat,
|
||||
penyakit: item.penyakit,
|
||||
})));
|
||||
}
|
||||
}, [stateGrafikKepuasan.findMany.data]);
|
||||
}, [data]);
|
||||
|
||||
const filteredData = (stateGrafikKepuasan.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.label.toLowerCase().includes(keyword) ||
|
||||
item.jumlah.toString().toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
// Add this function to process the data
|
||||
const processDiseaseData = (data: PDKMGrafik[]) => {
|
||||
const diseaseCount: Record<string, number> = {};
|
||||
|
||||
if (!stateGrafikKepuasan.findMany.data) {
|
||||
data.forEach(item => {
|
||||
const penyakit = item.penyakit.trim();
|
||||
if (penyakit) {
|
||||
diseaseCount[penyakit] = (diseaseCount[penyakit] || 0) + 1;
|
||||
}
|
||||
});
|
||||
|
||||
return Object.entries(diseaseCount).map(([name, count]) => ({
|
||||
name,
|
||||
count
|
||||
}));
|
||||
};
|
||||
|
||||
// Add this state to store the processed chart data
|
||||
const [diseaseChartData, setDiseaseChartData] = useState<{ name: string, count: number }[]>([]);
|
||||
|
||||
// Update the chart data when data changes
|
||||
useEffect(() => {
|
||||
if (data && data.length > 0) {
|
||||
setDiseaseChartData(processDiseaseData(data));
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const filteredData = data || [];
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack>
|
||||
<Skeleton h={500} />
|
||||
@@ -89,40 +115,36 @@ function ListGrafikHasilKepuasanMasyarakat({ search }: { search: string }) {
|
||||
<Stack gap={"xs"}>
|
||||
{/* Form Input */}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulListTab
|
||||
<JudulList
|
||||
title='List Grafik Hasil Kepuasan Masyarakat'
|
||||
href='/admin/kesehatan/data-kesehatan-warga/grafik_hasil_kepuasan/create'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={16} />}
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Label</TableTh>
|
||||
<TableTh>Jumlah</TableTh>
|
||||
<TableTh>Edit</TableTh>
|
||||
<TableTh>Delete</TableTh>
|
||||
<TableTh>Nama</TableTh>
|
||||
<TableTh>Tanggal</TableTh>
|
||||
<TableTh>Jenis Kelamin</TableTh>
|
||||
<TableTh>Penyakit</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.label}</TableTd>
|
||||
<TableTd>{item.jumlah}</TableTd>
|
||||
<TableTd>{item.nama}</TableTd>
|
||||
<TableTd>
|
||||
{new Date(item.tanggal).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
})}
|
||||
</TableTd>
|
||||
<TableTd>{item.jenisKelamin}</TableTd>
|
||||
<TableTd>{item.penyakit}</TableTd>
|
||||
<TableTd>
|
||||
<Button color='green' onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/grafik_hasil_kepuasan/${item.id}`)}>
|
||||
<IconEdit size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button
|
||||
color='red'
|
||||
disabled={stateGrafikKepuasan.delete.loading}
|
||||
onClick={() => {
|
||||
setSelectedId(item.id)
|
||||
setModalHapus(true)
|
||||
}}>
|
||||
<IconTrash size={20} />
|
||||
<IconDeviceImacCog size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
@@ -130,6 +152,15 @@ function ListGrafikHasilKepuasanMasyarakat({ search }: { search: string }) {
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)} // ini penting!
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
|
||||
|
||||
{/* Chart */}
|
||||
@@ -141,30 +172,29 @@ function ListGrafikHasilKepuasanMasyarakat({ search }: { search: string }) {
|
||||
</Paper>
|
||||
</Box>
|
||||
) : (
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 420, minHeight: 300 }}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title pb={10} order={4}>Grafik Hasil Kepuasan Masyarakat</Title>
|
||||
{mounted && chartData.length > 0 && (
|
||||
<BarChart width={isMobile ? 450 : isTablet ? 500 : 550} height={350} data={chartData} >
|
||||
<XAxis dataKey="label" />
|
||||
{mounted && diseaseChartData.length > 0 && (
|
||||
<BarChart width={isMobile ? 450 : isTablet ? 500 : 550} height={350} data={diseaseChartData} >
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
tick={{ fontSize: 12 }}
|
||||
interval={0}
|
||||
angle={-45}
|
||||
textAnchor="end"
|
||||
height={70}
|
||||
/>
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="jumlah" fill={colors['blue-button']} name="Jumlah" />
|
||||
<Bar dataKey="count" fill={colors['blue-button']} name="Jumlah Kasus" />
|
||||
</BarChart>
|
||||
)}
|
||||
</Paper>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
{/* Modal Konfirmasi Hapus */}
|
||||
<ModalKonfirmasiHapus
|
||||
opened={modalHapus}
|
||||
onClose={() => setModalHapus(false)}
|
||||
onConfirm={handleDelete}
|
||||
text='Apakah anda yakin ingin menghapus grafik hasil kepuasan masyarakat ini?'
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import persentasekelahiran from '@/app/admin/(dashboard)/_state/kesehatan/data_k
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconArrowBack, IconEdit, IconSearch } from '@tabler/icons-react';
|
||||
import { IconArrowBack, IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
@@ -47,7 +47,7 @@ function ListKelahiran({ search }: { search: string }) {
|
||||
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search)
|
||||
}, [search])
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = data || []
|
||||
|
||||
@@ -93,7 +93,7 @@ function ListKelahiran({ search }: { search: string }) {
|
||||
<TableTd>{item.alamat}</TableTd>
|
||||
<TableTd>
|
||||
<Button color='green' onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/persentase_data_kelahiran_kematian/kelahiran/${item.id}`)}>
|
||||
<IconEdit size={20} />
|
||||
<IconDeviceImacCog size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
'use client'
|
||||
import persentasekelahiran from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran';
|
||||
import colors from '@/con/colors';
|
||||
import { ActionIcon, Box, Button, Center, Flex, Paper, Skeleton, Stack, Table, Text, Title } from '@mantine/core';
|
||||
import { ActionIcon, Box, Center, Flex, Paper, Select, Skeleton, Stack, Table, Text, Title } from '@mantine/core';
|
||||
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
||||
import { IconBabyCarriage, IconGrave2 } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -157,20 +157,18 @@ function GrafikPersentaseKelahiranKematian() {
|
||||
) : (
|
||||
<>
|
||||
{/* Year Selector */}
|
||||
<Box mb="md">
|
||||
<Text mb="xs" fw={500}>Pilih Tahun:</Text>
|
||||
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
|
||||
{chartData.map(({ tahun }) => (
|
||||
<Button
|
||||
key={tahun}
|
||||
variant={selectedYear === tahun ? 'filled' : 'outline'}
|
||||
onClick={() => setSelectedYear(tahun)}
|
||||
size="xs"
|
||||
>
|
||||
{tahun}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<Box mb="md" style={{ maxWidth: '200px' }}>
|
||||
<Select
|
||||
label="Pilih Tahun"
|
||||
placeholder="Pilih Tahun"
|
||||
data={chartData.map((item) => ({
|
||||
value: item.tahun,
|
||||
label: item.tahun
|
||||
}))}
|
||||
value={selectedYear}
|
||||
onChange={(value) => setSelectedYear(value || '')}
|
||||
size="xs"
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Main Chart */}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Image, Pagination, 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';
|
||||
@@ -21,7 +21,7 @@ function InfoWabahPenyakit() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListInfoWabahPenyakit search={search}/>
|
||||
<ListInfoWabahPenyakit search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -30,19 +30,21 @@ function ListInfoWabahPenyakit({ search }: { search: string }) {
|
||||
const infoWabahPenyakitState = useProxy(infoWabahPenyakit)
|
||||
const router = useRouter()
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = infoWabahPenyakitState.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
infoWabahPenyakitState.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (infoWabahPenyakitState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsiSingkat.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!infoWabahPenyakitState.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -51,49 +53,60 @@ function ListInfoWabahPenyakit({ search }: { search: string }) {
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Info Wabah Penyakit'
|
||||
href='/admin/kesehatan/info-wabah-penyakit/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Judul</TableTh>
|
||||
<TableTh>Deskripsi Singkat</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>
|
||||
<Box w={100}>
|
||||
<Text truncate="end" fz={"sm"}>{item.name}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"}>{item.deskripsiSingkat}</Text>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image?.link} alt="image" />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/info-wabah-penyakit/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Info Wabah Penyakit'
|
||||
href='/admin/kesehatan/info-wabah-penyakit/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Judul</TableTh>
|
||||
<TableTh>Deskripsi Singkat</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>
|
||||
<Box w={100}>
|
||||
<Text truncate="end" fz={"sm"}>{item.name}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={100}>
|
||||
<Text truncate="end" fz={"sm"}>{item.deskripsiSingkat}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image?.link} alt="image" />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/info-wabah-penyakit/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)} // ini penting!
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Image, Pagination, 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';
|
||||
@@ -21,7 +21,7 @@ function KontakDarurat() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListKontakDarurat search={search}/>
|
||||
<ListKontakDarurat search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -30,19 +30,21 @@ function ListKontakDarurat({ search }: { search: string }) {
|
||||
const kontakDaruratState = useProxy(kontakDarurat)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = kontakDaruratState.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
kontakDaruratState.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (kontakDaruratState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!kontakDaruratState.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -77,7 +79,9 @@ function ListKontakDarurat({ search }: { search: string }) {
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
<Box w={100}>
|
||||
<Text truncate="end" lineClamp={1} fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image?.link} alt="image" />
|
||||
@@ -94,6 +98,15 @@ function ListKontakDarurat({ search }: { search: string }) {
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)} // ini penting!
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Image, Pagination, 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';
|
||||
@@ -21,7 +21,7 @@ function PenangananDarurat() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListPenangananDarurat search={search}/>
|
||||
<ListPenangananDarurat search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -30,19 +30,21 @@ function ListPenangananDarurat({ search }: { search: string }) {
|
||||
const penangananDaruratState = useProxy(penangananDarurat)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = penangananDaruratState.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
penangananDaruratState.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (penangananDaruratState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!penangananDaruratState.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -52,48 +54,59 @@ function ListPenangananDarurat({ search }: { search: string }) {
|
||||
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Penanganan Darurat'
|
||||
href='/admin/kesehatan/penanganan-darurat/create'
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Penanganan Darurat'
|
||||
href='/admin/kesehatan/penanganan-darurat/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Judul</TableTh>
|
||||
<TableTh>Deskripsi</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>
|
||||
<Box w={100}>
|
||||
<Text truncate="end" fz={"sm"}>{item.name}</Text>
|
||||
</Box></TableTd>
|
||||
<TableTd>
|
||||
<Box w={100}>
|
||||
<Text lineClamp={1} truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image?.link} alt="image" />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/penanganan-darurat/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)} // ini penting!
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Judul</TableTh>
|
||||
<TableTh>Deskripsi</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>
|
||||
<Box w={100}>
|
||||
<Text truncate="end" fz={"sm"}>{item.name}</Text>
|
||||
</Box></TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image?.link} alt="image" />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/penanganan-darurat/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Image, Pagination, 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';
|
||||
@@ -21,7 +21,7 @@ function ProgramKesehatan() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListProgramKesehatan search={search}/>
|
||||
<ListProgramKesehatan search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -30,19 +30,21 @@ function ListProgramKesehatan({ search }: { search: string }) {
|
||||
const programKesehatanState = useProxy(programKesehatan)
|
||||
const router = useRouter()
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = programKesehatanState.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
programKesehatanState.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (programKesehatanState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsiSingkat.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!programKesehatanState.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -77,7 +79,9 @@ function ListProgramKesehatan({ search }: { search: string }) {
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsiSingkat }} />
|
||||
<Box w={100}>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsiSingkat }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image?.link} alt="image" />
|
||||
@@ -94,6 +98,15 @@ function ListProgramKesehatan({ search }: { search: string }) {
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)} // ini penting!
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { Box, Button, Center, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -21,7 +21,7 @@ function Puskesmas() {
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListPuskesmas search={search}/>
|
||||
<ListPuskesmas search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -30,64 +30,75 @@ function ListPuskesmas({ search }: { search: string }) {
|
||||
const statePuskesmas = useProxy(puskesmasState)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = statePuskesmas.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
statePuskesmas.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (statePuskesmas.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.alamat.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!statePuskesmas.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Skeleton h={500}/>
|
||||
<Skeleton h={500} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Puskesmas'
|
||||
href='/admin/kesehatan/puskesmas/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Puskesmas</TableTh>
|
||||
<TableTh>Alamat</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>{item.alamat}</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image.link} alt="image" />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/puskesmas/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Puskesmas'
|
||||
href='/admin/kesehatan/puskesmas/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Puskesmas</TableTh>
|
||||
<TableTh>Alamat</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>{item.alamat}</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image.link} alt="image" />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/kesehatan/puskesmas/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)} // ini penting!
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { ActionIcon, Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { ActionIcon, Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImacCog, IconFile, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import JudulList from '../../_com/judulList';
|
||||
@@ -30,19 +30,22 @@ function APBDes() {
|
||||
function ListAPBDes({ search }: { search: string }) {
|
||||
const listState = useProxy(apbdes)
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
listState.findMany.load()
|
||||
}, [])
|
||||
|
||||
const filteredData = (listState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.jumlah.toLowerCase().includes(keyword)
|
||||
)
|
||||
});
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = listState.findMany
|
||||
|
||||
if (!listState.findMany.data) {
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = data || []
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -88,7 +91,7 @@ function ListAPBDes({ search }: { search: string }) {
|
||||
rel="noopener noreferrer"
|
||||
variant='transparent'
|
||||
>
|
||||
<IconFile size={25} color={colors['blue-button']}/>
|
||||
<IconFile size={25} color={colors['blue-button']} />
|
||||
</ActionIcon>
|
||||
) : (
|
||||
<Text>Tidak ada dokumen tersedia</Text>
|
||||
@@ -106,6 +109,14 @@ function ListAPBDes({ search }: { search: string }) {
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -50,19 +50,11 @@ function ListKategoriKegiatan({ search }: { search: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10)
|
||||
}, [page])
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
const filteredData = data || []
|
||||
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'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 { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -38,22 +38,11 @@ function ListDesaAntiKorupsi({ search }: { search: string }) {
|
||||
load,
|
||||
} = listState.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10);
|
||||
}, [page]);
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search);
|
||||
}, [page, search]);
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi?.toLowerCase().includes(keyword) ||
|
||||
item.kategori?.name?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.sort((a, b) => b.createdAt - a.createdAt);
|
||||
}, [data, search]);
|
||||
const filteredData = data || []
|
||||
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
function LayoutTabsKepuasan({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const tabs = [
|
||||
{
|
||||
label: "Grafik Kepuasan Masyarakat",
|
||||
value: "grafikkepuasannamasyarakat",
|
||||
href: "/admin/landing-page/indeks-kepuasan-masyarakat/grafik-kepuasan-masyarakat"
|
||||
},
|
||||
{
|
||||
label: "Responden",
|
||||
value: "responden",
|
||||
href: "/admin/landing-page/indeks-kepuasan-masyarakat/responden"
|
||||
},
|
||||
|
||||
];
|
||||
const curentTab = tabs.find(tab => tab.href === pathname)
|
||||
const [activeTab, setActiveTab] = useState<string | null>(curentTab?.value || tabs[0].value);
|
||||
|
||||
const handleTabChange = (value: string | null) => {
|
||||
const tab = tabs.find(t => t.value === value)
|
||||
if (tab) {
|
||||
router.push(tab.href)
|
||||
}
|
||||
setActiveTab(value)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const match = tabs.find(tab => tab.href === pathname)
|
||||
if (match) {
|
||||
setActiveTab(match.value)
|
||||
}
|
||||
}, [pathname])
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Title order={3}>Indeks Kepuasan Masyarakat</Title>
|
||||
<Tabs color={colors['blue-button']} variant='pills' value={activeTab} onChange={handleTabChange}>
|
||||
<TabsList p={"xs"} bg={"#BBC8E7FF"}>
|
||||
{tabs.map((e, i) => (
|
||||
<TabsTab key={i} value={e.value}>{e.label}</TabsTab>
|
||||
))}
|
||||
</TabsList>
|
||||
{tabs.map((e, i) => (
|
||||
<TabsPanel key={i} value={e.value}>
|
||||
{/* Konten dummy, bisa diganti tergantung routing */}
|
||||
<></>
|
||||
</TabsPanel>
|
||||
))}
|
||||
</Tabs>
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default LayoutTabsKepuasan;
|
||||
@@ -0,0 +1,256 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client';
|
||||
import colors from '@/con/colors';
|
||||
import { PieChart, BarChart } from '@mantine/charts'; // ✅ Ganti recharts dengan Mantine
|
||||
import {
|
||||
Box,
|
||||
Center,
|
||||
Flex,
|
||||
Paper,
|
||||
SimpleGrid,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
Title,
|
||||
} from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import indeksKepuasanState from '../../../_state/landing-page/indeks-kepuasan';
|
||||
|
||||
interface ChartDataItem {
|
||||
name: string;
|
||||
value: number;
|
||||
color: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Page() {
|
||||
const state = useProxy(indeksKepuasanState.responden);
|
||||
const { data, loading } = state.findMany;
|
||||
const [donutDataJenisKelamin, setDonutDataJenisKelamin] = useState<ChartDataItem[]>([]);
|
||||
const [donutDataRating, setDonutDataRating] = useState<ChartDataItem[]>([]);
|
||||
const [donutDataKelompokUmur, setDonutDataKelompokUmur] = useState<ChartDataItem[]>([]);
|
||||
const [barChartData, setBarChartData] = useState<Array<{ month: string; count: number }>>([]);
|
||||
|
||||
useShallowEffect(() => {
|
||||
if (!data && !loading) {
|
||||
state.findMany.load();
|
||||
return;
|
||||
}
|
||||
if (data) {
|
||||
// Hitung total berdasarkan jenis kelamin
|
||||
const totalLaki = data.filter((item: any) => item.jenisKelamin?.name?.toLowerCase() === 'laki-laki').length;
|
||||
const totalPerempuan = data.filter((item: any) => item.jenisKelamin?.name?.toLowerCase() === 'perempuan').length;
|
||||
|
||||
// Hitung total berdasarkan rating
|
||||
const totalSangatBaik = data.filter((item: any) => item.rating?.name?.toLowerCase() === 'sangat baik').length;
|
||||
const totalBaik = data.filter((item: any) => item.rating?.name?.toLowerCase() === 'baik').length;
|
||||
const totalKurangBaik = data.filter((item: any) => item.rating?.name?.toLowerCase() === 'kurang baik').length;
|
||||
const totalSangatKurangBaik = data.filter((item: any) => item.rating?.name?.toLowerCase() === 'sangat kurang baik').length;
|
||||
|
||||
// Hitung total berdasarkan kelompok umur
|
||||
const totalMuda = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'muda').length;
|
||||
const totalDewasa = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'dewasa').length;
|
||||
const totalLansia = data.filter((item: any) => item.kelompokUmur?.name?.toLowerCase() === 'lansia').length;
|
||||
|
||||
// Update gender chart data
|
||||
setDonutDataJenisKelamin([
|
||||
{ name: 'Laki-laki', value: totalLaki, color: colors['blue-button'] },
|
||||
{ name: 'Perempuan', value: totalPerempuan, color: '#10A85AFF' },
|
||||
]);
|
||||
|
||||
// Update rating chart data
|
||||
setDonutDataRating([
|
||||
{ name: 'Sangat Baik', value: totalSangatBaik, color: colors['blue-button'] },
|
||||
{ name: 'Baik', value: totalBaik, color: '#10A85AFF' },
|
||||
{ name: 'Kurang Baik', value: totalKurangBaik, color: '#FFA500' },
|
||||
{ name: 'Sangat Kurang Baik', value: totalSangatKurangBaik, color: '#FF4500' },
|
||||
]);
|
||||
|
||||
// Update age group chart data
|
||||
setDonutDataKelompokUmur([
|
||||
{ name: 'Muda', value: totalMuda, color: colors['blue-button'] },
|
||||
{ name: 'Dewasa', value: totalDewasa, color: '#10A85AFF' },
|
||||
{ name: 'Lansia', value: totalLansia, color: '#FFA500' },
|
||||
]);
|
||||
|
||||
// Process data for bar chart (group by month)
|
||||
const monthYearMap = new Map<string, number>();
|
||||
|
||||
data.forEach((item: any) => {
|
||||
// Try both createdAt and tanggal fields
|
||||
const dateValue = item.tanggal || item.createdAt;
|
||||
if (!dateValue) return;
|
||||
|
||||
const parsedDate = new Date(dateValue);
|
||||
if (isNaN(parsedDate.getTime())) return;
|
||||
|
||||
const month = parsedDate.getMonth() + 1;
|
||||
const year = parsedDate.getFullYear();
|
||||
const monthYearKey = `${year}-${String(month).padStart(2, '0')}`;
|
||||
|
||||
monthYearMap.set(monthYearKey, (monthYearMap.get(monthYearKey) || 0) + 1);
|
||||
});
|
||||
|
||||
// Convert map to array and sort by date
|
||||
const barData = Array.from(monthYearMap.entries())
|
||||
.map(([key, count]) => {
|
||||
const [year, month] = key.split('-');
|
||||
const monthName = new Date(Number(year), Number(month) - 1, 1)
|
||||
.toLocaleString('id-ID', { month: 'long' });
|
||||
return {
|
||||
month: `${monthName} ${year}`,
|
||||
count,
|
||||
sortKey: parseInt(`${year}${String(month).padStart(2, '0')}`, 10)
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.sortKey - b.sortKey)
|
||||
.map(({ month, count }) => ({ month, count }));
|
||||
|
||||
setBarChartData(barData);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton height={730} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
Belum ada data untuk ditampilkan
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack gap="xs">
|
||||
{/* Bar Chart - Data per Tanggal */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md" mb="md">
|
||||
<Title order={4} mb="md" ta="center">Jumlah Responden per Bulan</Title>
|
||||
<Box h={300}>
|
||||
<BarChart
|
||||
h={300}
|
||||
data={barChartData}
|
||||
dataKey="month"
|
||||
series={[{ name: 'count', color: colors['blue-button'] }]}
|
||||
tickLine="y"
|
||||
xAxisLabel="Bulan"
|
||||
yAxisLabel="Jumlah Responden"
|
||||
withTooltip
|
||||
tooltipAnimationDuration={200}
|
||||
/>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
<SimpleGrid cols={{ base: 1, md: 3 }}>
|
||||
{/* Chart Jenis Kelamin */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Jenis Kelamin</Title>
|
||||
{donutDataJenisKelamin.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
<Box>
|
||||
<Center>
|
||||
<PieChart
|
||||
withLabels
|
||||
withTooltip
|
||||
labelsType="percent"
|
||||
size={250}
|
||||
data={donutDataJenisKelamin}
|
||||
/>
|
||||
</Center>
|
||||
<Stack gap="sm" mt="md">
|
||||
{donutDataJenisKelamin.map((entry) => (
|
||||
<Flex key={entry.name} gap="md" align="center">
|
||||
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
||||
<Text size="sm">{entry.name}: {entry.value}</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Stack>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{/* Chart Rating */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Pilihan</Title>
|
||||
{donutDataRating.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
<Box>
|
||||
<Center>
|
||||
<PieChart
|
||||
withLabels
|
||||
withTooltip
|
||||
labelsType="percent"
|
||||
size={250}
|
||||
data={donutDataRating}
|
||||
/>
|
||||
</Center>
|
||||
<Stack gap="sm" mt="md">
|
||||
{donutDataRating.map((entry) => (
|
||||
<Flex key={entry.name} gap="md" align="center">
|
||||
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
||||
<Text size="sm">{entry.name}: {entry.value}</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Stack>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{/* Chart Kelompok Umur */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Umur</Title>
|
||||
{donutDataKelompokUmur.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
<Box>
|
||||
<Center>
|
||||
<PieChart
|
||||
withLabels
|
||||
withTooltip
|
||||
labelsType="percent"
|
||||
size={250}
|
||||
data={donutDataKelompokUmur}
|
||||
/>
|
||||
</Center>
|
||||
<Stack gap="sm" mt="md">
|
||||
{donutDataKelompokUmur.map((entry) => (
|
||||
<Flex key={entry.name} gap="md" align="center">
|
||||
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
||||
<Text size="sm">{entry.name}: {entry.value}</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Stack>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
</Paper>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import LayoutTabsKepuasan from './_lib/layoutTab';
|
||||
|
||||
function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<LayoutTabsKepuasan>
|
||||
{children}
|
||||
</LayoutTabsKepuasan>
|
||||
);
|
||||
}
|
||||
|
||||
export default Layout;
|
||||
@@ -0,0 +1,190 @@
|
||||
'use client'
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useRouter, useParams } from 'next/navigation';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Stack, Title, TextInput, Text, Select } from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import indeksKepuasanState from '@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
interface FormResponden {
|
||||
name: string;
|
||||
tanggal: string;
|
||||
jenisKelaminId: string;
|
||||
ratingId: string;
|
||||
kelompokUmurId: string;
|
||||
}
|
||||
|
||||
function EditResponden() {
|
||||
const router = useRouter()
|
||||
const params = useParams() as { id: string }
|
||||
const state = useProxy(indeksKepuasanState.responden)
|
||||
const id = params.id
|
||||
const [formData, setFormData] = useState<FormResponden>({
|
||||
name: '',
|
||||
tanggal: '',
|
||||
jenisKelaminId: '',
|
||||
ratingId: '',
|
||||
kelompokUmurId: '',
|
||||
})
|
||||
useEffect(() => {
|
||||
indeksKepuasanState.jenisKelaminResponden.findMany.load();
|
||||
indeksKepuasanState.pilihanRatingResponden.findMany.load();
|
||||
indeksKepuasanState.kelompokUmurResponden.findMany.load();
|
||||
|
||||
const loadResponden = async () => {
|
||||
const id = params?.id as string;
|
||||
if (!id) return;
|
||||
|
||||
try {
|
||||
const data = await state.update.load(id);
|
||||
if (data) {
|
||||
state.update.id = id;
|
||||
|
||||
state.update.form = {
|
||||
name: data.name,
|
||||
tanggal: data.tanggal,
|
||||
jenisKelaminId: data.jenisKelaminId,
|
||||
ratingId: data.ratingId,
|
||||
kelompokUmurId: data.kelompokUmurId,
|
||||
};
|
||||
|
||||
setFormData({
|
||||
name: data.name,
|
||||
tanggal: data.tanggal,
|
||||
jenisKelaminId: data.jenisKelaminId,
|
||||
ratingId: data.ratingId,
|
||||
kelompokUmurId: data.kelompokUmurId,
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading program penghijauan:", error);
|
||||
toast.error("Gagal memuat data program penghijauan");
|
||||
}
|
||||
}
|
||||
|
||||
loadResponden();
|
||||
}, [params?.id]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
state.update.id = id;
|
||||
state.update.form = { ...formData }; // <-- sinkronisasi manual
|
||||
await state.update.submit();
|
||||
router.push('/admin/ppid/ikm-desa-darmasaba/responden')
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack size={20} />
|
||||
</Button>
|
||||
</Box>
|
||||
<Paper bg={colors['white-1']} w={{ base: '100%', md: '50%' }} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>Edit Responden</Title>
|
||||
<TextInput
|
||||
label="Nama"
|
||||
type='text'
|
||||
placeholder="masukkan nama"
|
||||
value={formData.name}
|
||||
onChange={(val) => {
|
||||
setFormData({
|
||||
...formData,
|
||||
name: val.currentTarget.value
|
||||
})
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Tanggal"
|
||||
type="date"
|
||||
placeholder='Pilih tanggal'
|
||||
value={formData.tanggal ? new Date(formData.tanggal).toISOString().split('T')[0] : ''}
|
||||
onChange={(e) => {
|
||||
const selectedDate = e.currentTarget.value;
|
||||
setFormData({
|
||||
...formData,
|
||||
tanggal: selectedDate,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
key={"jenisKelamin"}
|
||||
label={<Text fw="bold" fz="sm">Jenis Kelamin</Text>}
|
||||
placeholder="Pilih jenis kelamin"
|
||||
value={formData.jenisKelaminId}
|
||||
onChange={(val) => setFormData({ ...formData, jenisKelaminId: val || "" })}
|
||||
data={
|
||||
(indeksKepuasanState.jenisKelaminResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null/undefined
|
||||
.map((v) => ({
|
||||
value: v.id || '',
|
||||
label: typeof v.name === 'string' ? v.name : 'Tanpa Nama'
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.jenisKelaminResponden.findMany.loading} // ✅ disable saat loading
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
error={!formData.jenisKelaminId ? "Pilih jenis kelamin" : undefined}
|
||||
/>
|
||||
<Select
|
||||
key={"rating"}
|
||||
value={formData.ratingId}
|
||||
onChange={(val) => setFormData({ ...formData, ratingId: val || "" })}
|
||||
label={<Text fw={"bold"} fz={"sm"}>Rating</Text>}
|
||||
placeholder='Pilih rating'
|
||||
data={
|
||||
(indeksKepuasanState.pilihanRatingResponden.findMany.data || [])
|
||||
.filter(Boolean)
|
||||
.map((v) => ({
|
||||
value: v.id || '',
|
||||
label: typeof v.name === 'string' ? v.name : 'Tanpa Nama'
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.pilihanRatingResponden.findMany.loading}
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
error={!formData.ratingId ? "Pilih rating" : undefined}
|
||||
/>
|
||||
|
||||
<Select
|
||||
key={"kelompokUmur"}
|
||||
value={formData.kelompokUmurId}
|
||||
onChange={(val) => setFormData({ ...formData, kelompokUmurId: val || "" })}
|
||||
label={<Text fw={"bold"} fz={"sm"}>Kelompok Umur</Text>}
|
||||
placeholder='Pilih kelompok umur'
|
||||
data={
|
||||
(indeksKepuasanState.kelompokUmurResponden.findMany.data || [])
|
||||
.filter(Boolean)
|
||||
.map((v) => ({
|
||||
value: v.id || '',
|
||||
label: typeof v.name === 'string' ? v.name : 'Tanpa Nama'
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
error={!formData.kelompokUmurId ? "Pilih kelompok umur" : undefined}
|
||||
/>
|
||||
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditResponden;
|
||||
@@ -0,0 +1,116 @@
|
||||
'use client'
|
||||
|
||||
import { ModalKonfirmasiHapus } from "@/app/admin/(dashboard)/_com/modalKonfirmasiHapus"
|
||||
import indeksKepuasanState from "@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan"
|
||||
import colors from "@/con/colors"
|
||||
import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from "@mantine/core"
|
||||
import { useShallowEffect } from "@mantine/hooks"
|
||||
import { IconArrowBack, IconEdit, IconX } from "@tabler/icons-react"
|
||||
import { useRouter, useParams } from "next/navigation"
|
||||
import { useState } from "react"
|
||||
import { useProxy } from "valtio/utils"
|
||||
|
||||
export default function DetailResponden() {
|
||||
const [modalHapus, setModalHapus] = useState(false)
|
||||
const stateDetail = useProxy(indeksKepuasanState.responden)
|
||||
const router = useRouter()
|
||||
const params = useParams()
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
|
||||
useShallowEffect(() => {
|
||||
stateDetail.findUnique.load(params?.id as string)
|
||||
}, [params?.id])
|
||||
|
||||
const handleHapus = () => {
|
||||
if (selectedId) {
|
||||
stateDetail.delete.byId(selectedId)
|
||||
setModalHapus(false)
|
||||
setSelectedId(null)
|
||||
router.push("/admin/ppid/ikm-desa-darmasaba/responden")
|
||||
}
|
||||
}
|
||||
|
||||
if (!stateDetail.findUnique.data) {
|
||||
return (
|
||||
<Stack>
|
||||
<Skeleton h={500} />
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||
</Button>
|
||||
</Box>
|
||||
<Paper w={{ base: "100%", md: "50%" }} bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Text fz={"xl"} fw={"bold"}>Detail Responden</Text>
|
||||
|
||||
<Paper bg={colors['BG-trans']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Nama Responden</Text>
|
||||
<Text fz={"lg"}>{stateDetail.findUnique.data?.name}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Tanggal</Text>
|
||||
<Text fz={"lg"}>{
|
||||
stateDetail.findUnique.data?.tanggal
|
||||
? new Date(stateDetail.findUnique.data.tanggal).toLocaleDateString('id-ID')
|
||||
: '-'
|
||||
}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Jenis Kelamin</Text>
|
||||
<Text fz={"lg"}>{stateDetail.findUnique.data?.jenisKelamin?.name}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Rating</Text>
|
||||
<Text fz={"lg"}>{stateDetail.findUnique.data?.rating?.name}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Kelompok Umur</Text>
|
||||
<Text fz={"lg"}>{stateDetail.findUnique.data?.kelompokUmur?.name}</Text>
|
||||
</Box>
|
||||
<Flex gap={"xs"} mt={10}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (stateDetail.findUnique.data) {
|
||||
setSelectedId(stateDetail.findUnique.data.id);
|
||||
setModalHapus(true);
|
||||
}
|
||||
}}
|
||||
disabled={stateDetail.delete.loading || !stateDetail.findUnique.data}
|
||||
color={"red"}
|
||||
>
|
||||
<IconX size={20} />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (stateDetail.findUnique.data) {
|
||||
router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${stateDetail.findUnique.data.id}/edit`);
|
||||
}
|
||||
}}
|
||||
disabled={!stateDetail.findUnique.data}
|
||||
color={"green"}
|
||||
>
|
||||
<IconEdit size={20} />
|
||||
</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{/* Modal Hapus */}
|
||||
<ModalKonfirmasiHapus
|
||||
opened={modalHapus}
|
||||
onClose={() => setModalHapus(false)}
|
||||
onConfirm={handleHapus}
|
||||
text="Apakah anda yakin ingin menghapus responden ini?"
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
'use client'
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import React from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import grafikBerdasarkanJenisKelamin from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { useState } from 'react';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Stack, Title, TextInput, Select, Text } from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import indeksKepuasanState from '@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
|
||||
function RespondenCreate() {
|
||||
const router = useRouter();
|
||||
const stategrafikBerdasarkanResponden = useProxy(indeksKepuasanState.responden)
|
||||
const [donutData, setDonutData] = useState<any[]>([]);
|
||||
|
||||
const resetForm = () => {
|
||||
stategrafikBerdasarkanResponden.create.form = {
|
||||
...stategrafikBerdasarkanResponden.create.form,
|
||||
name: "",
|
||||
tanggal: "",
|
||||
jenisKelaminId: "",
|
||||
ratingId: "",
|
||||
kelompokUmurId: "",
|
||||
}
|
||||
}
|
||||
|
||||
useShallowEffect(() => {
|
||||
indeksKepuasanState.jenisKelaminResponden.findMany.load()
|
||||
indeksKepuasanState.pilihanRatingResponden.findMany.load()
|
||||
indeksKepuasanState.kelompokUmurResponden.findMany.load()
|
||||
})
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
const id = await stategrafikBerdasarkanResponden.create.create();
|
||||
if (typeof id !== 'undefined') {
|
||||
const idStr = String(id);
|
||||
await stategrafikBerdasarkanResponden.findUnique.load(idStr);
|
||||
if (stategrafikBerdasarkanResponden.findUnique.data) {
|
||||
setDonutData([stategrafikBerdasarkanResponden.findUnique.data]);
|
||||
}
|
||||
}
|
||||
resetForm();
|
||||
router.push("/admin/ppid/ikm-desa-darmasaba/responden");
|
||||
} catch (error) {
|
||||
console.error('Error submitting form:', error);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack size={20} />
|
||||
</Button>
|
||||
</Box>
|
||||
<Paper bg={colors['white-1']} w={{ base: '100%', md: '50%' }} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik</Title>
|
||||
<TextInput
|
||||
label="Nama"
|
||||
type='text'
|
||||
placeholder="masukkan nama"
|
||||
value={stategrafikBerdasarkanResponden.create.form.name}
|
||||
onChange={(val) => {
|
||||
stategrafikBerdasarkanResponden.create.form.name = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Tanggal"
|
||||
type="date"
|
||||
placeholder="masukkan tanggal"
|
||||
value={stategrafikBerdasarkanResponden.create.form.tanggal}
|
||||
onChange={(val) => {
|
||||
stategrafikBerdasarkanResponden.create.form.tanggal = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
key={"jenisKelamin"}
|
||||
label={"Jenis Kelamin"}
|
||||
placeholder={indeksKepuasanState.jenisKelaminResponden.findMany.loading ? 'Memuat...' : 'Pilih jenis kelamin'}
|
||||
value={stategrafikBerdasarkanResponden.create.form.jenisKelaminId || ""}
|
||||
onChange={(val) => {
|
||||
stategrafikBerdasarkanResponden.create.form.jenisKelaminId = val ?? "";
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.jenisKelaminResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.jenisKelaminResponden.findMany.loading}
|
||||
/>
|
||||
<Select
|
||||
key={"rating_responden"}
|
||||
label={"Rating"}
|
||||
placeholder={indeksKepuasanState.pilihanRatingResponden.findMany.loading ? 'Memuat...' : 'Pilih rating'}
|
||||
value={stategrafikBerdasarkanResponden.create.form.ratingId || ""}
|
||||
onChange={(val) => {
|
||||
stategrafikBerdasarkanResponden.create.form.ratingId = val ?? "";
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.pilihanRatingResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.pilihanRatingResponden.findMany.loading}
|
||||
/>
|
||||
<Select
|
||||
key={"kelompokUmur"}
|
||||
label={"Kelompok Umur"}
|
||||
placeholder={indeksKepuasanState.kelompokUmurResponden.findMany.loading ? 'Memuat...' : 'Pilih kelompok umur'}
|
||||
value={stategrafikBerdasarkanResponden.create.form.kelompokUmurId || ""}
|
||||
onChange={(val) => {
|
||||
stategrafikBerdasarkanResponden.create.form.kelompokUmurId = val ?? "";
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.kelompokUmurResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
|
||||
/>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default RespondenCreate;
|
||||
@@ -0,0 +1,144 @@
|
||||
'use client';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImac, 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 indeksKepuasanState from '../../../_state/landing-page/indeks-kepuasan';
|
||||
|
||||
function Responden() {
|
||||
const [search, setSearch] = useState("");
|
||||
return (
|
||||
<Box>
|
||||
<HeaderSearch
|
||||
title='Responden'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListResponden search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
interface ListRespondenProps {
|
||||
search: string;
|
||||
}
|
||||
|
||||
function ListResponden({ search }: ListRespondenProps) {
|
||||
const state = useProxy(indeksKepuasanState.responden);
|
||||
const router = useRouter();
|
||||
const { data, page, totalPages, loading, load } = state.findMany;
|
||||
|
||||
|
||||
useShallowEffect(() => {
|
||||
load(page, 10)
|
||||
}, [page]);
|
||||
|
||||
|
||||
const filteredData = (data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton height={730} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper p="md">
|
||||
<Stack>
|
||||
<Title>Responden</Title>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>No</TableTh>
|
||||
<TableTh>Nama</TableTh>
|
||||
<TableTh>Tanggal</TableTh>
|
||||
<TableTh>Jenis Kelamin</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
</Table>
|
||||
<Text ta="center">Tidak ada data berdasarkan jenis kelamin responden yang tersedia</Text>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box >
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Stack gap="xs">
|
||||
<Paper bg={colors['white-1']} p="md" h={{ base: 730, md: 650 }}>
|
||||
<Title mb={10} order={3}>List Responden</Title>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh style={{ width: '5%', textAlign: 'center' }}>No</TableTh>
|
||||
<TableTh style={{ width: '20%', textAlign: 'center' }}>Nama</TableTh>
|
||||
<TableTh style={{ width: '20%', textAlign: 'center' }}>Tanggal</TableTh>
|
||||
<TableTh style={{ width: '20%', textAlign: 'center' }}>Jenis Kelamin</TableTh>
|
||||
<TableTh style={{ width: '15%', textAlign: 'center' }}>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.length === 0 ? (
|
||||
<TableTr>
|
||||
<TableTd colSpan={6}>
|
||||
<Text ta='center' c='dimmed'>Belum ada data responden</Text>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
) : (
|
||||
filteredData.map((item, index) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd style={{ width: '5%', textAlign: 'center' }}>{index + 1}</TableTd>
|
||||
<TableTd style={{ width: '20%', textAlign: 'center' }}>{item.name}</TableTd>
|
||||
<TableTd style={{ width: '20%', textAlign: 'center' }}>{item.tanggal
|
||||
? new Date(item.tanggal).toLocaleDateString('id-ID')
|
||||
: '-'}</TableTd>
|
||||
<TableTd style={{ width: '20%', textAlign: 'center' }}>{item.jenisKelamin.name}</TableTd>
|
||||
<TableTd style={{ width: '15%', textAlign: 'center' }}>
|
||||
<Button color='green' onClick={() => router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))
|
||||
)}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
|
||||
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Responden;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -42,18 +42,21 @@ function ListKategoriPrestasi({ search }: { search: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = stateKategori.findMany
|
||||
|
||||
useShallowEffect(() => {
|
||||
stateKategori.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = (stateKategori.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = data || []
|
||||
|
||||
if (!stateKategori.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -100,6 +103,14 @@ function ListKategoriPrestasi({ search }: { search: string }) {
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
/>
|
||||
</Center>
|
||||
{/* Modal Konfirmasi Hapus */}
|
||||
<ModalKonfirmasiHapus
|
||||
opened={modalHapus}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -30,20 +30,36 @@ function ListPrestasiDesa() {
|
||||
function ListPrestasi({ search }: { search: string }) {
|
||||
const listState = useProxy(prestasiState.prestasiDesa)
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
listState.findMany.load()
|
||||
}, [])
|
||||
|
||||
const filteredData = (listState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword) ||
|
||||
item.kategori?.name?.toLowerCase().includes(keyword)
|
||||
);
|
||||
const{
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = listState.findMany
|
||||
|
||||
// Debug log
|
||||
console.log('ListPrestasi state:', {
|
||||
loading,
|
||||
data: data?.length,
|
||||
page,
|
||||
totalPages,
|
||||
search
|
||||
});
|
||||
|
||||
if (!listState.findMany.data) {
|
||||
useEffect(() => {
|
||||
console.log('Loading data...', { page, search });
|
||||
load(page, 10, search).then(() => {
|
||||
console.log('Data loaded:', listState.findMany.data);
|
||||
}).catch(error => {
|
||||
console.error('Error loading data:', error);
|
||||
});
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = data || []
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -82,7 +98,7 @@ function ListPrestasi({ search }: { search: string }) {
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>{item.kategori?.name}</TableTd>
|
||||
<TableTd>{item.kategori?.name || 'No Category'}</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/landing-page/prestasi-desa/list-prestasi-desa/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
@@ -95,6 +111,14 @@ function ListPrestasi({ search }: { search: string }) {
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -38,20 +38,11 @@ function ListMediaSosial({ search }: { search: string }) {
|
||||
load,
|
||||
} = stateMediaSosial.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10)
|
||||
}, [page])
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.iconUrl?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
const filteredData = data || []
|
||||
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
|
||||
@@ -55,7 +55,10 @@ function DetailProgramInovasi() {
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Deskripsi</Text>
|
||||
<Text fz={"lg"}>{stateProgramInovasi.findUnique.data?.description}</Text>
|
||||
<Text
|
||||
fz={"lg"}
|
||||
|
||||
>{stateProgramInovasi.findUnique.data?.description}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Link</Text>
|
||||
@@ -63,6 +66,12 @@ function DetailProgramInovasi() {
|
||||
href={stateProgramInovasi.findUnique.data?.link || "#"}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{
|
||||
wordWrap: 'break-word',
|
||||
whiteSpace: 'pre-wrap',
|
||||
overflowWrap: 'break-word',
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
{stateProgramInovasi.findUnique.data?.link || "Tidak ada link"}
|
||||
</a>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'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 { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -38,21 +38,11 @@ function ListProgramInovasi({ search }: { search: string }) {
|
||||
load,
|
||||
} = stateProgramInovasi.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10);
|
||||
}, [page]);
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search);
|
||||
}, [page, search]);
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.description?.toLowerCase().includes(keyword) ||
|
||||
item.link?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
const filteredData = data || []
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'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 { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import sdgsDesa from '../../_state/landing-page/sdgs-desa';
|
||||
import JudulList from '../../_com/judulList';
|
||||
import sdgsDesa from '../../_state/landing-page/sdgs-desa';
|
||||
|
||||
|
||||
function SdgsDesa() {
|
||||
@@ -39,20 +39,11 @@ function ListSdgsDesa({ search }: { search: string }) {
|
||||
load,
|
||||
} = listState.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10)
|
||||
}, [])
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, search)
|
||||
}, [page, search])
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.jumlah?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
const filteredData = data || []
|
||||
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
|
||||
@@ -105,9 +105,19 @@ function ListDaftarInformasi({ search }: { search: string }) {
|
||||
<TableTbody>
|
||||
{filteredData.map((item, index) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd style={{ textAlign: 'center' }}>{index + 1}</TableTd>
|
||||
<TableTd style={{ wordWrap: 'break-word' }}>{item.jenisInformasi}</TableTd>
|
||||
<TableTd style={{ wordWrap: 'break-word' }} dangerouslySetInnerHTML={{ __html: item.deskripsi }}></TableTd>
|
||||
<TableTd style={{ textAlign: 'center' }}>
|
||||
<Text mt={10} fz={"md"}>{index + 1}</Text>
|
||||
</TableTd>
|
||||
<TableTd style={{ wordWrap: 'break-word' }}>
|
||||
<Box w={200}>
|
||||
<Text mt={10} fz={"md"} truncate={"end"} lineClamp={1}>{item.jenisInformasi}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd style={{ wordWrap: 'break-word' }}>
|
||||
<Box w={200}>
|
||||
<Text fz={"md"} truncate={"end"} lineClamp={1} dangerouslySetInnerHTML={{ __html: item.deskripsi }}></Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd style={{ textAlign: 'center' }}>
|
||||
<Button bg={"green"} onClick={() => router.push(`/admin/ppid/daftar-informasi-publik-desa-darmasaba/${item.id}`)}>
|
||||
<IconDeviceImacCog size={25} />
|
||||
|
||||
@@ -41,15 +41,11 @@ function EditResponden() {
|
||||
try {
|
||||
const data = await state.update.load(id);
|
||||
if (data) {
|
||||
const formattedDate = data.tanggal && !isNaN(new Date(data.tanggal).getTime())
|
||||
? new Date(data.tanggal).toISOString().split('T')[0]
|
||||
: '';
|
||||
// ⬇️ FIX PENTING: tambahkan ini
|
||||
state.update.id = id;
|
||||
|
||||
state.update.form = {
|
||||
name: data.name,
|
||||
tanggal: formattedDate,
|
||||
tanggal: data.tanggal,
|
||||
jenisKelaminId: data.jenisKelaminId,
|
||||
ratingId: data.ratingId,
|
||||
kelompokUmurId: data.kelompokUmurId,
|
||||
@@ -76,6 +72,7 @@ function EditResponden() {
|
||||
|
||||
const handleSubmit = async () => {
|
||||
state.update.id = id;
|
||||
state.update.form = { ...formData }; // <-- sinkronisasi manual
|
||||
await state.update.submit();
|
||||
router.push('/admin/ppid/ikm-desa-darmasaba/responden')
|
||||
}
|
||||
@@ -103,12 +100,15 @@ function EditResponden() {
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Tanggal"
|
||||
type="date"
|
||||
value={formData.tanggal}
|
||||
placeholder='Pilih tanggal'
|
||||
value={formData.tanggal ? new Date(formData.tanggal).toISOString().split('T')[0] : ''}
|
||||
onChange={(e) => {
|
||||
const selectedDate = e.currentTarget.value;
|
||||
setFormData({
|
||||
...formData,
|
||||
tanggal: e.currentTarget.value, // ✅ sudah format YYYY-MM-DD
|
||||
tanggal: selectedDate,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -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, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconDeviceImac, 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 JudulList from '../../../_com/judulList';
|
||||
import indeksKepuasanState from '../../../_state/landing-page/indeks-kepuasan';
|
||||
|
||||
function Responden() {
|
||||
@@ -60,10 +59,7 @@ function ListResponden({ search }: ListRespondenProps) {
|
||||
<Box py={10}>
|
||||
<Paper p="md">
|
||||
<Stack>
|
||||
<JudulList
|
||||
title='List Data Berdasarkan Jenis Kelamin Responden'
|
||||
href='/admin/ppid/ikm-desa-darmasaba/responden/create'
|
||||
/>
|
||||
<Title>Responden</Title>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
@@ -86,10 +82,7 @@ function ListResponden({ search }: ListRespondenProps) {
|
||||
<Box>
|
||||
<Stack gap="xs">
|
||||
<Paper bg={colors['white-1']} p="md" h={{ base: 730, md: 650 }}>
|
||||
<JudulList
|
||||
title='List Data Responden'
|
||||
href='/admin/ppid/ikm-desa-darmasaba/responden/create'
|
||||
/>
|
||||
<Title mb={10} order={3}>List Responden</Title>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
|
||||
@@ -4,7 +4,7 @@ import colors from '@/con/colors';
|
||||
import { Badge, Box, Button, Center, Group, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, ThemeIcon } from '@mantine/core';
|
||||
import { IconCheck, IconDeviceImacCog, IconSearch, IconX } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -39,22 +39,10 @@ function ListPegawaiPPID({ search }: { search: string }) {
|
||||
} = stateOrganisasi.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10);
|
||||
}, [page]);
|
||||
load(page, 10, search);
|
||||
}, [page, search]);
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.namaLengkap?.toLowerCase().includes(keyword) ||
|
||||
item.gelarAkademik?.toLowerCase().includes(keyword) ||
|
||||
item.telepon?.toLowerCase().includes(keyword) ||
|
||||
item.posisi?.nama?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.sort((a, b) => a.posisi?.hierarki - b.posisi?.hierarki);
|
||||
}, [data, search]);
|
||||
const filteredData = data || []
|
||||
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -33,9 +33,17 @@ function ListPosisiOrganisasiPPID({ search }: { search: string }) {
|
||||
const [modalHapus, setModalHapus] = useState(false)
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = stateOrganisasi.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
stateOrganisasi.findMany.load()
|
||||
}, [])
|
||||
load(page, 10, search);
|
||||
}, [page, search]);
|
||||
|
||||
const handleHapus = async () => {
|
||||
if (selectedId) {
|
||||
@@ -45,17 +53,9 @@ function ListPosisiOrganisasiPPID({ search }: { search: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
const filteredData = (stateOrganisasi.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.nama?.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi?.toLowerCase().includes(keyword) ||
|
||||
item.hierarki?.toString().toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.sort((a, b) => a.hierarki - b.hierarki);
|
||||
const filteredData = data || []
|
||||
|
||||
if (!stateOrganisasi.findMany.data) {
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
@@ -120,6 +120,14 @@ function ListPosisiOrganisasiPPID({ search }: { search: string }) {
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => load(newPage)}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
/>
|
||||
</Center>
|
||||
{/* Modal Hapus */}
|
||||
<ModalKonfirmasiHapus
|
||||
opened={modalHapus}
|
||||
|
||||
@@ -17,7 +17,7 @@ export const navBar = [
|
||||
{
|
||||
id: "Landing_Page_3",
|
||||
name: "Indeks Kepuasan Masyarakat",
|
||||
path: "/admin/landing-page/indeks-kepuasan-masyarakat/list-survey"
|
||||
path: "/admin/landing-page/indeks-kepuasan-masyarakat/grafik-kepuasan-masyarakat"
|
||||
},
|
||||
{
|
||||
id: "Landing_Page_4",
|
||||
|
||||
@@ -96,28 +96,36 @@ export default async function detailDataPengangguranCreate(context: Context) {
|
||||
// Cari bulan sebelumnya
|
||||
const currentMonthIndex = monthOrder.indexOf(body.month);
|
||||
const prevMonth = currentMonthIndex > 0 ? monthOrder[currentMonthIndex - 1] : "Des";
|
||||
const prevYear = currentMonthIndex > 0 ? body.year : body.year - 1;
|
||||
|
||||
|
||||
// Handle year as number for calculations
|
||||
const currentYear = typeof body.year === 'number' ? body.year : new Date(body.year).getFullYear();
|
||||
const prevYear = currentMonthIndex > 0 ? currentYear : currentYear - 1;
|
||||
|
||||
// Create date objects for Prisma
|
||||
const currentYearDate = new Date(currentYear, 0, 1);
|
||||
const prevYearDate = new Date(prevYear, 0, 1);
|
||||
|
||||
const prevData = await prisma.detailDataPengangguran.findFirst({
|
||||
where: {
|
||||
month: prevMonth,
|
||||
year: prevYear,
|
||||
year: prevYearDate,
|
||||
},
|
||||
});
|
||||
|
||||
let percentageChange: number | null = null;
|
||||
if (prevData) {
|
||||
const change = ((body.totalUnemployment - prevData.totalUnemployment) / prevData.totalUnemployment) * 100;
|
||||
const change = ((Number(body.totalUnemployment) - Number(prevData.totalUnemployment)) / Number(prevData.totalUnemployment)) * 100;
|
||||
percentageChange = parseFloat(change.toFixed(1));
|
||||
}
|
||||
|
||||
// Create the new record with properly typed values
|
||||
const created = await prisma.detailDataPengangguran.create({
|
||||
data: {
|
||||
month: body.month,
|
||||
year: body.year,
|
||||
totalUnemployment: body.totalUnemployment,
|
||||
educatedUnemployment: body.educatedUnemployment,
|
||||
uneducatedUnemployment: body.uneducatedUnemployment,
|
||||
year: currentYearDate,
|
||||
totalUnemployment: Number(body.totalUnemployment),
|
||||
educatedUnemployment: Number(body.educatedUnemployment),
|
||||
uneducatedUnemployment: Number(body.uneducatedUnemployment),
|
||||
percentageChange,
|
||||
},
|
||||
select: {
|
||||
|
||||
@@ -15,7 +15,7 @@ export default async function findByMonthYear(context: Context) {
|
||||
const data = await prisma.detailDataPengangguran.findFirst({
|
||||
where: {
|
||||
month,
|
||||
year: Number(year),
|
||||
year: new Date(Number(year), 0, 1), // Convert year number to Date object for Prisma
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -81,13 +81,18 @@ export default async function detailDataPengangguranUpdate(context: Context) {
|
||||
return { success: false, message: "ID tidak ditemukan" };
|
||||
}
|
||||
|
||||
const { month, year, totalUnemployment, educatedUnemployment, uneducatedUnemployment } = context.body as {
|
||||
const { month, year: yearInput, totalUnemployment, educatedUnemployment, uneducatedUnemployment } = context.body as {
|
||||
month: string;
|
||||
year: number;
|
||||
totalUnemployment: number;
|
||||
educatedUnemployment: number;
|
||||
uneducatedUnemployment: number;
|
||||
year: number | string | Date;
|
||||
totalUnemployment: number | string;
|
||||
educatedUnemployment: number | string;
|
||||
uneducatedUnemployment: number | string;
|
||||
};
|
||||
|
||||
// Normalize year to Date object
|
||||
const year = typeof yearInput === 'number' ? new Date(yearInput, 0, 1) :
|
||||
yearInput instanceof Date ? yearInput :
|
||||
new Date(parseInt(yearInput as string), 0, 1);
|
||||
|
||||
const duplicate = await prisma.detailDataPengangguran.findFirst({
|
||||
where: {
|
||||
@@ -109,18 +114,19 @@ export default async function detailDataPengangguranUpdate(context: Context) {
|
||||
|
||||
const currentMonthIndex = monthOrder.indexOf(month);
|
||||
const prevMonth = currentMonthIndex > 0 ? monthOrder[currentMonthIndex - 1] : "Des";
|
||||
const prevYear = currentMonthIndex > 0 ? year : year - 1;
|
||||
const currentYear = year.getFullYear();
|
||||
const prevYear = currentMonthIndex > 0 ? currentYear : currentYear - 1;
|
||||
|
||||
const prevData = await prisma.detailDataPengangguran.findFirst({
|
||||
where: {
|
||||
month: prevMonth,
|
||||
year: prevYear,
|
||||
year: new Date(prevYear, 0, 1),
|
||||
},
|
||||
});
|
||||
|
||||
let percentageChange: number | null = null;
|
||||
if (prevData) {
|
||||
const change = ((totalUnemployment - prevData.totalUnemployment) / prevData.totalUnemployment) * 100;
|
||||
const change = ((Number(totalUnemployment) - Number(prevData.totalUnemployment)) / Number(prevData.totalUnemployment)) * 100;
|
||||
percentageChange = parseFloat(change.toFixed(1));
|
||||
}
|
||||
|
||||
@@ -128,10 +134,10 @@ export default async function detailDataPengangguranUpdate(context: Context) {
|
||||
where: { id },
|
||||
data: {
|
||||
month,
|
||||
year,
|
||||
totalUnemployment,
|
||||
educatedUnemployment,
|
||||
uneducatedUnemployment,
|
||||
year: new Date(year), // Ensure it's a new Date instance
|
||||
totalUnemployment: Number(totalUnemployment),
|
||||
educatedUnemployment: Number(educatedUnemployment),
|
||||
uneducatedUnemployment: Number(uneducatedUnemployment),
|
||||
percentageChange,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,21 +1,55 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// /api/berita/findManyPaginated.ts
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function lowonganKerjaFindMany() {
|
||||
try {
|
||||
const data = await prisma.lowonganPekerjaan.findMany({
|
||||
where: { isActive: true },
|
||||
});
|
||||
async function lowonganKerjaFindMany(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;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Success fetch lowongan kerja",
|
||||
data,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("Find many error:", e);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed fetch lowongan kerja",
|
||||
};
|
||||
}
|
||||
}
|
||||
// Buat where clause
|
||||
const where: any = { isActive: true };
|
||||
|
||||
// Tambahkan pencarian (jika ada)
|
||||
if (search) {
|
||||
where.OR = [
|
||||
{ posisi: { contains: search, mode: 'insensitive' } },
|
||||
{ namaPerusahaan: { contains: search, mode: 'insensitive' } },
|
||||
{ lokasi: { contains: search, mode: 'insensitive' } },
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
// Ambil data dan total count secara paralel
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.lowonganPekerjaan.findMany({
|
||||
where,
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma.lowonganPekerjaan.count({ where }),
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil ambil lowongan kerja 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 lowongan kerja",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default lowonganKerjaFindMany;
|
||||
@@ -1,26 +1,84 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// /api/berita/findManyPaginated.ts
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function pasarDesaFindMany() {
|
||||
const data = await prisma.pasarDesa.findMany({
|
||||
where: {
|
||||
isActive: true, // Opsional filter
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
include: {
|
||||
image: true,
|
||||
KategoriToPasar: {
|
||||
async function pasarDesaFindMany(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 categoryId = context.query.categoryId as string | undefined;
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Buat where clause
|
||||
const where: any = { isActive: true };
|
||||
|
||||
// Tambahkan filter kategori (jika ada)
|
||||
if (categoryId) {
|
||||
where.KategoriToPasar = {
|
||||
some: {
|
||||
kategoriId: categoryId
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Tambahkan pencarian (jika ada)
|
||||
if (search) {
|
||||
where.AND = where.AND || [];
|
||||
where.AND.push({
|
||||
OR: [
|
||||
{ nama: { contains: search, mode: 'insensitive' } },
|
||||
{ alamatUsaha: { contains: search, mode: 'insensitive' } },
|
||||
{
|
||||
KategoriToPasar: {
|
||||
some: {
|
||||
kategori: {
|
||||
nama: { contains: search, mode: 'insensitive' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Ambil data dan total count secara paralel
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.pasarDesa.findMany({
|
||||
where,
|
||||
include: {
|
||||
kategori: true,
|
||||
image: true,
|
||||
KategoriToPasar: {
|
||||
include: {
|
||||
kategori: true
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma.pasarDesa.count({ where }),
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil mengambil semua data pasar desa",
|
||||
data,
|
||||
};
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil ambil pasar desa 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 pasar desa",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default pasarDesaFindMany;
|
||||
@@ -1,15 +1,60 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// /api/berita/findManyPaginated.ts
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function kategoriProdukFindMany() {
|
||||
const data = await prisma.kategoriProduk.findMany();
|
||||
return {
|
||||
success: true,
|
||||
data: data.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
nama: item.nama,
|
||||
}
|
||||
}),
|
||||
async function kategoriProdukFindMany(context: Context) {
|
||||
// Ambil parameter dari query
|
||||
const page = Number(context.query.page) || 1;
|
||||
const limit = Number(context.query.limit) || 10;
|
||||
const search2 = (context.query.search as string) || '';
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Buat where clause
|
||||
const where: any = { isActive: true };
|
||||
|
||||
// Tambahkan pencarian (jika ada)
|
||||
if (search2) {
|
||||
where.OR = [
|
||||
{ nama: { contains: search2, mode: 'insensitive' } },
|
||||
{KategoriToPasar : {
|
||||
some: {
|
||||
kategori: {
|
||||
nama: { contains: search2, mode: 'insensitive' }
|
||||
}
|
||||
}
|
||||
}}
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
// Ambil data dan total count secara paralel
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.kategoriProduk.findMany({
|
||||
where,
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma.kategoriProduk.count({ where }),
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil ambil kategori produk 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 kategori produk",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default kategoriProdukFindMany;
|
||||
@@ -1,18 +1,53 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function programKemiskinanFindMany() {
|
||||
const data = await prisma.programKemiskinan.findMany({
|
||||
include: {
|
||||
statistik: true, // ikut sertakan relasinya
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Success get all program layanan",
|
||||
data,
|
||||
};
|
||||
export default async function programKemiskinanFindMany(context: Context) {
|
||||
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 = [
|
||||
{ nama: { contains: search, mode: 'insensitive' } },
|
||||
{ deskripsi: { contains: search, mode: 'insensitive' } },
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
// Ambil data dan total count secara paralel
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.programKemiskinan.findMany({
|
||||
where,
|
||||
include: {
|
||||
statistik: true,
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma.programKemiskinan.count({ where }),
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil ambil program kemiskinan 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 program kemiskinan",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,57 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// /api/berita/findManyPaginated.ts
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function keamananLingkunganFindMany() {
|
||||
try {
|
||||
const data = await prisma.keamananLingkungan.findMany({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
});
|
||||
async function keamananLingkunganFindMany(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;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Success fetch keamanan lingkungan",
|
||||
data,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("Find many error:", e);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed fetch keamanan lingkungan",
|
||||
};
|
||||
}
|
||||
}
|
||||
// Buat where clause
|
||||
const where: any = { isActive: true };
|
||||
|
||||
// Tambahkan pencarian (jika ada)
|
||||
if (search) {
|
||||
where.OR = [
|
||||
{ name: { contains: search, mode: 'insensitive' } },
|
||||
{ deskripsi: { contains: search, mode: 'insensitive' } },
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
// Ambil data dan total count secara paralel
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.keamananLingkungan.findMany({
|
||||
where,
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma.keamananLingkungan.count({ where }),
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil ambil keamanan lingkungan 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 keamanan lingkungan",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default keamananLingkunganFindMany;
|
||||
@@ -0,0 +1,31 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// find-first.ts
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
async function polsekTerdekatFindFirst() {
|
||||
const where: any = { isActive: true };
|
||||
|
||||
try {
|
||||
const data = await prisma.polsekTerdekat.findFirst({
|
||||
where,
|
||||
include: {
|
||||
layananPolsek: true,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil ambil polsek terdekat terbaru",
|
||||
data,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("Error di findFirst:", e);
|
||||
return {
|
||||
success: false,
|
||||
message: "Gagal ambil polsek terdekat terbaru",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default polsekTerdekatFindFirst;
|
||||
@@ -1,24 +1,57 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// /api/berita/findManyPaginated.ts
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function polsekTerdekatFindMany() {
|
||||
try {
|
||||
const data = await prisma.polsekTerdekat.findMany({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
layananPolsek: true,
|
||||
},
|
||||
});
|
||||
async function polsekTerdekatFindMany(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;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Success fetch polsek terdekat",
|
||||
data,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("Find many error:", e);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed fetch polsek terdekat",
|
||||
};
|
||||
}
|
||||
}
|
||||
// Buat where clause
|
||||
const where: any = { isActive: true };
|
||||
|
||||
// Tambahkan pencarian (jika ada)
|
||||
if (search) {
|
||||
where.OR = [
|
||||
{ nama: { contains: search, mode: 'insensitive' } },
|
||||
{ alamat: { contains: search, mode: 'insensitive' } },
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
// Ambil data dan total count secara paralel
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.polsekTerdekat.findMany({
|
||||
where,
|
||||
include: {
|
||||
layananPolsek: true,
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma.polsekTerdekat.count({ where }),
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil ambil polsek terdekat 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 polsek terdekat",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default polsekTerdekatFindMany;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user