Compare commits
12 Commits
nico/19-au
...
nico/23-au
| Author | SHA1 | Date | |
|---|---|---|---|
| bb8dab05ba | |||
| 3081e426bd | |||
| 8a275c2a32 | |||
| 8469ebd2e1 | |||
| 760ba4b6d2 | |||
| 20d4c90e60 | |||
| fafbb12a08 | |||
| 01aa0da5cc | |||
| b580978f8e | |||
| 1c01397c0d | |||
| 90a6605efd | |||
| c22d865283 |
@@ -3,126 +3,108 @@
|
|||||||
"id": "cmds9h9ko000pvnberdjnx64b",
|
"id": "cmds9h9ko000pvnberdjnx64b",
|
||||||
"name": "1.1 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
"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>",
|
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9sjmz000svnbesv2133of",
|
"id": "cmds9sjmz000svnbesv2133of",
|
||||||
"name": "1.2 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA",
|
"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>",
|
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9tcpi000vvnbev3ebtlnt",
|
"id": "cmds9tcpi000vvnbev3ebtlnt",
|
||||||
"name": "1.3 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
"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>",
|
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9twvj000yvnbep0pq8dzf",
|
"id": "cmds9twvj000yvnbep0pq8dzf",
|
||||||
"name": "1.4 PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA",
|
"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>",
|
"deskripsi": "<p>PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9ugap0011vnbe118yv871",
|
"id": "cmds9ugap0011vnbe118yv871",
|
||||||
"name": "1.5 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA",
|
"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>",
|
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa35310014vnbe6qy6l1rz",
|
"id": "cmdsa35310014vnbe6qy6l1rz",
|
||||||
"name": "2.1 ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA",
|
"name": "2.1 ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA",
|
||||||
"deskripsi": "<p>ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA</p>",
|
"deskripsi": "<p>ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa46590017vnbepp3noso1",
|
"id": "cmdsa46590017vnbepp3noso1",
|
||||||
"name": "2.2 ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH",
|
"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>",
|
"deskripsi": "<p>ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH</p>",
|
||||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa5m7z001avnbe4cvfrcz0",
|
"id": "cmdsa5m7z001avnbe4cvfrcz0",
|
||||||
"name": "2.3 TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI",
|
"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>",
|
"deskripsi": "<p>TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI</p>",
|
||||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa8q5q001dvnbemch8j24x",
|
"id": "cmdsa8q5q001dvnbemch8j24x",
|
||||||
"name": "3.1 ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT",
|
"name": "3.1 ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT",
|
||||||
"deskripsi": "<p>ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT</p>",
|
"deskripsi": "<p>ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa9lbi001gvnbequn2ba7m",
|
"id": "cmdsa9lbi001gvnbequn2ba7m",
|
||||||
"name": "3.2 ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA",
|
"name": "3.2 ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA",
|
||||||
"deskripsi": "<p>ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA</p>",
|
"deskripsi": "<p>ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsaa7aq001jvnbeizh04e67",
|
"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",
|
"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>",
|
"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",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsaaw8d001mvnbek3tfefrk",
|
"id": "cmdsaaw8d001mvnbek3tfefrk",
|
||||||
"name": "3.4 ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT",
|
"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>",
|
"deskripsi": "<p>ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsabhif001pvnbepm06hry6",
|
"id": "cmdsabhif001pvnbepm06hry6",
|
||||||
"name": "3.5 ADANYA MAKLUMAT PELAYANAN",
|
"name": "3.5 ADANYA MAKLUMAT PELAYANAN",
|
||||||
"deskripsi": "<p>ADANYA MAKLUMAT PELAYANAN</p>",
|
"deskripsi": "<p>ADANYA MAKLUMAT PELAYANAN</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsag40b001svnbe7krq9khc",
|
"id": "cmdsag40b001svnbe7krq9khc",
|
||||||
"name": "4.1 ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA",
|
"name": "4.1 ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA",
|
||||||
"deskripsi": "<p>ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA</p>",
|
"deskripsi": "<p>ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA</p>",
|
||||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsagkaf001vvnbejo26w8sa",
|
"id": "cmdsagkaf001vvnbejo26w8sa",
|
||||||
"name": "4.2 ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
"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>",
|
"deskripsi": "<p>ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsah4qe001yvnbeiy3mwrvb",
|
"id": "cmdsah4qe001yvnbeiy3mwrvb",
|
||||||
"name": "4.3 ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA",
|
"name": "4.3 ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA",
|
||||||
"deskripsi": "<p>ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA</p>",
|
"deskripsi": "<p>ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA</p>",
|
||||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsak5vn0021vnbemg86aab4",
|
"id": "cmdsak5vn0021vnbemg86aab4",
|
||||||
"name": "5.1 ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
"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>",
|
"deskripsi": "<p>ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
"kategoriId": "cmds9govb000mvnbesq8b4y99"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsalc800024vnbezgulhgrb",
|
"id": "cmdsalc800024vnbezgulhgrb",
|
||||||
"name": "5.2 ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
"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>",
|
"deskripsi": "<p>ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
"kategoriId": "cmds9govb000mvnbesq8b4y99"
|
||||||
"fileId": ""
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "cmeppcwzk0000vn5exmudcipd",
|
||||||
"jenisInformasi": "Peraturan Desa",
|
"jenisInformasi": "Potensi Desa",
|
||||||
"deskripsi": "Dokumen yang berisi kebijakan dan regulasi 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": "15 Januari 2024"
|
"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
|
deskripsi String @db.Text
|
||||||
kategori KategoriPrestasiDesa @relation(fields: [kategoriId], references: [id])
|
kategori KategoriPrestasiDesa @relation(fields: [kategoriId], references: [id])
|
||||||
kategoriId String
|
kategoriId String
|
||||||
image FileStorage @relation(fields: [imageId], references: [id])
|
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||||
imageId String
|
imageId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime @default(now())
|
deletedAt DateTime @default(now())
|
||||||
@@ -223,7 +223,7 @@ model KategoriPrestasiDesa {
|
|||||||
model Responden {
|
model Responden {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique
|
name String @unique
|
||||||
tanggal String // misal: 2025-05-01
|
tanggal DateTime @db.Date // misal: 2025-05-01
|
||||||
jenisKelamin JenisKelaminResponden @relation(fields: [jenisKelaminId], references: [id])
|
jenisKelamin JenisKelaminResponden @relation(fields: [jenisKelaminId], references: [id])
|
||||||
jenisKelaminId String
|
jenisKelaminId String
|
||||||
rating PilihanRatingResponden @relation(fields: [ratingId], references: [id])
|
rating PilihanRatingResponden @relation(fields: [ratingId], references: [id])
|
||||||
@@ -292,6 +292,9 @@ model PosisiOrganisasiPPID {
|
|||||||
pegawai PegawaiPPID[]
|
pegawai PegawaiPPID[]
|
||||||
strukturOrganisasi StrukturPPID[] // Relasi balik
|
strukturOrganisasi StrukturPPID[] // Relasi balik
|
||||||
parentId String?
|
parentId String?
|
||||||
|
isActive Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
||||||
children PosisiOrganisasiPPID[] @relation("Parent")
|
children PosisiOrganisasiPPID[] @relation("Parent")
|
||||||
}
|
}
|
||||||
@@ -1547,7 +1550,7 @@ model DataDemografiPekerjaan {
|
|||||||
model DetailDataPengangguran {
|
model DetailDataPengangguran {
|
||||||
id String @id @default(uuid()) @db.Uuid
|
id String @id @default(uuid()) @db.Uuid
|
||||||
month String @db.VarChar(20)
|
month String @db.VarChar(20)
|
||||||
year Int
|
year DateTime
|
||||||
totalUnemployment Int
|
totalUnemployment Int
|
||||||
educatedUnemployment Int
|
educatedUnemployment Int
|
||||||
uneducatedUnemployment Int
|
uneducatedUnemployment Int
|
||||||
|
|||||||
332
prisma/seed.ts
332
prisma/seed.ts
@@ -1,57 +1,62 @@
|
|||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import profilePejabatDesa from "./data/landing-page/profile/profile.json";
|
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 programInovasi from "./data/landing-page/profile/programInovasi.json";
|
||||||
import mediaSosial from "./data/landing-page/profile/mediaSosial.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 sdgsDesa from "./data/landing-page/sdgs-desa/sdgs-desa.json";
|
||||||
import apbdes from "./data/landing-page/apbdes/apbdes.json";
|
import apbdes from "./data/landing-page/apbdes/apbdes.json";
|
||||||
import pelayananSuratKeterangan from "./data/desa/layanan/pelayananSuratKeterangan.json";
|
import kategoriPrestasiDesa from "./data/landing-page/prestasi-desa/kategori-prestasi.json";
|
||||||
import categoryPengumuman from "./data/category-pengumuman.json";
|
import prestasiDesa from "./data/landing-page/prestasi-desa/prestasi-desa.json";
|
||||||
import kategoriBerita from "./data/kategori-berita.json";
|
import penghargaan from "./data/landing-page/penghargaan/penghargaan.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 profilePPID from "./data/ppid/profile-ppid/profilePPid.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 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 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 pilihanRatingResponden from "./data/ppid/ikm/pilihan-rating-responden/rating-responden.json";
|
||||||
import umurResponden from "./data/ppid/ikm/umur-responden/umur-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 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 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 lambangDesa from "./data/desa/profile/lambang_desa.json";
|
||||||
import maskotDesa from "./data/desa/profile/maskot_desa.json";
|
import maskotDesa from "./data/desa/profile/maskot_desa.json";
|
||||||
import profilPerbekel from "./data/desa/profile/profil_perbekel.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 kategoriProduk from "./data/ekonomi/pasar-desa/kategori-produk.json";
|
||||||
import hubunganOrganisasi from "./data/ekonomi/struktur-organisasi/hubungan-organisasi.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 pegawai from "./data/ekonomi/struktur-organisasi/pegawai.json";
|
||||||
import detailDataPengangguran from "./data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json";
|
import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json";
|
||||||
import tujuanEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
|
import kategoriBerita from "./data/kategori-berita.json";
|
||||||
import materiEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
|
|
||||||
import contohEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/contoh-kegiatan-di-desa-darmasaba.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 bentukKonservasiBerdasarkanAdat from "./data/lingkungan/konservasi-adat-bali/bentuk-konservasi.json";
|
||||||
import filosofiTriHita from "./data/lingkungan/konservasi-adat-bali/filosofi-tri-hita.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 tujuanProgram2 from "./data/pendidikan/pendidikan-non-formal/tujuan-program2.json";
|
||||||
import programUnggulan from "./data/pendidikan/program-pendidikan-anak/program-unggulan.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 tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.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";
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
// =========== LANDING PAGE ===========
|
// =========== LANDING PAGE ===========
|
||||||
// =========== PROFILE ===========
|
// =========== SUBMENU PROFILE ===========
|
||||||
|
// =========== PROFILE PEJABAT DESA ===========
|
||||||
for (const p of profilePejabatDesa) {
|
for (const p of profilePejabatDesa) {
|
||||||
await prisma.pejabatDesa.upsert({
|
await prisma.pejabatDesa.upsert({
|
||||||
where: { id: p.id },
|
where: { id: p.id },
|
||||||
@@ -106,6 +111,90 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
}
|
}
|
||||||
console.log("media sosial success ...");
|
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 ===========
|
// =========== PENGHARGAAN ===========
|
||||||
for (const p of penghargaan) {
|
for (const p of penghargaan) {
|
||||||
await prisma.penghargaan.upsert({
|
await prisma.penghargaan.upsert({
|
||||||
@@ -160,23 +249,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
}
|
}
|
||||||
console.log("pelayanan surat keterangan success ...");
|
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 ===========
|
// =========== SDGSDesa ===========
|
||||||
for (const l of sdgsDesa) {
|
for (const l of sdgsDesa) {
|
||||||
await prisma.sDGSDesa.upsert({
|
await prisma.sDGSDesa.upsert({
|
||||||
@@ -217,6 +289,9 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("sdgs desa success ...");
|
console.log("sdgs desa success ...");
|
||||||
|
|
||||||
|
// =========== MENU DESA ===========
|
||||||
|
// =========== SUBMENU PROFILE ===========
|
||||||
|
// =========== SEJARAH DESA ===========
|
||||||
for (const l of sejarahDesa) {
|
for (const l of sejarahDesa) {
|
||||||
await prisma.sejarahDesa.upsert({
|
await prisma.sejarahDesa.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -236,6 +311,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("sejarah desa success ...");
|
console.log("sejarah desa success ...");
|
||||||
|
|
||||||
|
// =========== MASKOT DESA ===========
|
||||||
for (const l of maskotDesa) {
|
for (const l of maskotDesa) {
|
||||||
await prisma.maskotDesa.upsert({
|
await prisma.maskotDesa.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -255,6 +331,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("maskot desa success ...");
|
console.log("maskot desa success ...");
|
||||||
|
|
||||||
|
// =========== LAMBANG DESA ===========
|
||||||
for (const l of lambangDesa) {
|
for (const l of lambangDesa) {
|
||||||
await prisma.lambangDesa.upsert({
|
await prisma.lambangDesa.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -274,6 +351,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("lambang desa success ...");
|
console.log("lambang desa success ...");
|
||||||
|
|
||||||
|
// =========== PROFIL PERBEKEL ===========
|
||||||
for (const c of profilPerbekel) {
|
for (const c of profilPerbekel) {
|
||||||
await prisma.profilPerbekel.upsert({
|
await prisma.profilPerbekel.upsert({
|
||||||
where: { id: c.id },
|
where: { id: c.id },
|
||||||
@@ -298,6 +376,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
"✅ profilePerbekel seeded without imageId (editable later via UI)"
|
"✅ profilePerbekel seeded without imageId (editable later via UI)"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// =========== VISI MISI DESA ===========
|
||||||
for (const l of visiMisiDesa) {
|
for (const l of visiMisiDesa) {
|
||||||
await prisma.visiMisiDesa.upsert({
|
await prisma.visiMisiDesa.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -317,6 +396,35 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("visi misi desa success ...");
|
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();
|
const flattenedPosisi = posisiOrganisasiPPID.flat();
|
||||||
|
|
||||||
// ✅ Urutkan berdasarkan hierarki
|
// ✅ Urutkan berdasarkan hierarki
|
||||||
@@ -341,9 +449,9 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
create: p,
|
create: p,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("✅ Posisi organisasi berhasil");
|
console.log("posisi organisasi berhasil");
|
||||||
|
|
||||||
// 2. Seed Pegawai
|
// =========== PEGAWAI PPID ===========
|
||||||
const flattenedPegawai = pegawaiPPID.flat();
|
const flattenedPegawai = pegawaiPPID.flat();
|
||||||
for (const p of flattenedPegawai) {
|
for (const p of flattenedPegawai) {
|
||||||
await prisma.pegawaiPPID.upsert({
|
await prisma.pegawaiPPID.upsert({
|
||||||
@@ -352,7 +460,70 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
create: p,
|
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) {
|
for (const l of pelayananPerizinanBerusaha) {
|
||||||
await prisma.pelayananPerizinanBerusaha.upsert({
|
await prisma.pelayananPerizinanBerusaha.upsert({
|
||||||
@@ -486,48 +657,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
}
|
}
|
||||||
console.log("cara memperoleh salinan informasi success ...");
|
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) {
|
for (const j of jenisKelamin) {
|
||||||
await prisma.jenisKelaminResponden.upsert({
|
await prisma.jenisKelaminResponden.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -576,24 +705,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
}
|
}
|
||||||
console.log("umur responden success ...");
|
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) {
|
for (const k of kategoriProduk) {
|
||||||
await prisma.kategoriProduk.upsert({
|
await prisma.kategoriProduk.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -681,9 +792,12 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
console.log("hubungan organisasi success ...");
|
console.log("hubungan organisasi success ...");
|
||||||
|
|
||||||
for (const d of detailDataPengangguran) {
|
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({
|
await prisma.detailDataPengangguran.upsert({
|
||||||
where: {
|
where: {
|
||||||
month_year: { month: d.month, year: d.year },
|
month_year: { month: d.month, year: yearAsDate },
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
totalUnemployment: d.totalUnemployment,
|
totalUnemployment: d.totalUnemployment,
|
||||||
@@ -693,7 +807,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
month: d.month,
|
month: d.month,
|
||||||
year: d.year,
|
year: yearAsDate,
|
||||||
totalUnemployment: d.totalUnemployment,
|
totalUnemployment: d.totalUnemployment,
|
||||||
educatedUnemployment: d.educatedUnemployment,
|
educatedUnemployment: d.educatedUnemployment,
|
||||||
uneducatedUnemployment: d.uneducatedUnemployment,
|
uneducatedUnemployment: d.uneducatedUnemployment,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -61,13 +62,39 @@ const lowonganKerjaState = proxy({
|
|||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.LowonganPekerjaanGetPayload<{
|
| Prisma.LowonganPekerjaanGetPayload<{
|
||||||
omit: { isActive: true };
|
omit: {
|
||||||
|
isActive: true;
|
||||||
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.lowongankerja["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
loading: false,
|
||||||
lowonganKerjaState.findMany.data = res.data?.data ?? [];
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -53,22 +54,47 @@ const pasarDesa = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as Array<
|
data: null as
|
||||||
Prisma.PasarDesaGetPayload<{
|
| Prisma.PasarDesaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
KategoriToPasar: {
|
KategoriToPasar: {
|
||||||
include: {
|
include: {
|
||||||
kategori: true;
|
kategori: true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
}>[]
|
||||||
}>
|
| null,
|
||||||
> | null,
|
page: 1,
|
||||||
async load() {
|
totalPages: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.pasardesa["find-many"].get();
|
loading: false,
|
||||||
if (res.status === 200) {
|
search: "",
|
||||||
pasarDesa.findMany.data = res.data?.data ?? [];
|
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: {
|
findMany: {
|
||||||
data: null as Array<{
|
data: null as
|
||||||
id: string;
|
| Prisma.KategoriProdukGetPayload<{
|
||||||
nama: string;
|
omit: {
|
||||||
}> | null,
|
isActive: true;
|
||||||
async load() {
|
};
|
||||||
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get();
|
}>[]
|
||||||
if (res.status === 200) {
|
| null,
|
||||||
kategoriProduk.findMany.data = res.data?.data ?? [];
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -11,8 +12,7 @@ const templateForm = z.object({
|
|||||||
statistik: z.object({
|
statistik: z.object({
|
||||||
tahun: z.string().min(1, "Tahun minimal 1 karakter"),
|
tahun: z.string().min(1, "Tahun minimal 1 karakter"),
|
||||||
jumlah: z.string().min(1, "Jumlah minimal 1 karakter"),
|
jumlah: z.string().min(1, "Jumlah minimal 1 karakter"),
|
||||||
})
|
}),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultForm = {
|
const defaultForm = {
|
||||||
@@ -21,8 +21,8 @@ const defaultForm = {
|
|||||||
ikonUrl: "",
|
ikonUrl: "",
|
||||||
statistik: {
|
statistik: {
|
||||||
tahun: "",
|
tahun: "",
|
||||||
jumlah: ""
|
jumlah: "",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const programKemiskinanState = proxy({
|
const programKemiskinanState = proxy({
|
||||||
@@ -64,12 +64,35 @@ const programKemiskinanState = proxy({
|
|||||||
};
|
};
|
||||||
}>[],
|
}>[],
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.programkemiskinan[
|
totalPages: 1,
|
||||||
"find-many"
|
search: "",
|
||||||
].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
programKemiskinanState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
programKemiskinanState.findMany.data = res.data?.data ?? [];
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -53,15 +54,39 @@ const tipsKeamananState = proxy({
|
|||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.MenuTipsKeamananGetPayload<{
|
| Prisma.MenuTipsKeamananGetPayload<{
|
||||||
include: { image: true };
|
include: {
|
||||||
|
image: true;
|
||||||
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.keamanan.menutipskeamanan[
|
totalPages: 1,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
tipsKeamananState.findMany.data = res.data?.data ?? [];
|
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;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -50,18 +51,50 @@ const apbdes = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as Array<
|
data: null as
|
||||||
Prisma.APBDesGetPayload<{
|
| Prisma.APBDesGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
file: true;
|
file: true;
|
||||||
};
|
};
|
||||||
}>
|
}>[]
|
||||||
> | null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.landingpage.apbdes["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
total: 0,
|
||||||
apbdes.findMany.data = res.data?.data ?? [];
|
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,14 +60,20 @@ const desaAntikorupsi = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
desaAntikorupsi.findMany.loading = true; // Use the full path to access the property
|
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.page = page;
|
||||||
|
desaAntikorupsi.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
||||||
"findMany"
|
"findMany"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
@@ -305,20 +311,25 @@ const kategoriDesaAntiKorupsi = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
kategoriDesaAntiKorupsi.findMany.loading = true; // Use the full path to access the property
|
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.page = page;
|
||||||
|
kategoriDesaAntiKorupsi.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
const res = await ApiFetch.api.landingpage.kategoridak[
|
const query: any = { page, limit };
|
||||||
"findMany"
|
if (search) query.search = search;
|
||||||
].get({
|
|
||||||
query: { page, limit },
|
const res = await ApiFetch.api.landingpage.kategoridak["findMany"].get({
|
||||||
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
kategoriDesaAntiKorupsi.findMany.data = res.data.data || [];
|
kategoriDesaAntiKorupsi.findMany.data = res.data.data || [];
|
||||||
kategoriDesaAntiKorupsi.findMany.total = res.data.total || 0;
|
kategoriDesaAntiKorupsi.findMany.total = res.data.total || 0;
|
||||||
kategoriDesaAntiKorupsi.findMany.totalPages = res.data.totalPages || 1;
|
kategoriDesaAntiKorupsi.findMany.totalPages =
|
||||||
|
res.data.totalPages || 1;
|
||||||
} else {
|
} else {
|
||||||
console.error("Failed to load media sosial:", res.data?.message);
|
console.error("Failed to load media sosial:", res.data?.message);
|
||||||
kategoriDesaAntiKorupsi.findMany.data = [];
|
kategoriDesaAntiKorupsi.findMany.data = [];
|
||||||
@@ -363,27 +374,30 @@ const kategoriDesaAntiKorupsi = proxy({
|
|||||||
try {
|
try {
|
||||||
kategoriDesaAntiKorupsi.delete.loading = true;
|
kategoriDesaAntiKorupsi.delete.loading = true;
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/landingpage/kategoridak/del/${id}`, {
|
||||||
`/api/landingpage/kategoridak/del/${id}`,
|
method: "DELETE",
|
||||||
{
|
headers: {
|
||||||
method: "DELETE",
|
"Content-Type": "application/json",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json",
|
});
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (response.ok && result?.success) {
|
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
|
await kategoriDesaAntiKorupsi.findMany.load(); // refresh list
|
||||||
} else {
|
} else {
|
||||||
toast.error(result?.message || "Gagal menghapus kategori desa anti korupsi");
|
toast.error(
|
||||||
|
result?.message || "Gagal menghapus kategori desa anti korupsi"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Gagal delete:", 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 {
|
} finally {
|
||||||
kategoriDesaAntiKorupsi.delete.loading = false;
|
kategoriDesaAntiKorupsi.delete.loading = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -58,16 +59,43 @@ const prestasiDesa = proxy({
|
|||||||
Prisma.PrestasiDesaGetPayload<{
|
Prisma.PrestasiDesaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
kategori: true;
|
kategori: {
|
||||||
|
select: {
|
||||||
|
id: true;
|
||||||
|
name: true;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}>
|
}>
|
||||||
> | null,
|
> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.landingpage.prestasidesa[
|
totalPages: 1,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
prestasiDesa.findMany.data = res.data?.data ?? [];
|
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;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
}> | null,
|
}> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.landingpage.kategoriprestasi[
|
totalPages: 1,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
kategoriPrestasi.findMany.data = res.data?.data ?? [];
|
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,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
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.loading = true; // Use the full path to access the property
|
||||||
programInovasi.findMany.page = page;
|
programInovasi.findMany.page = page;
|
||||||
|
programInovasi.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.landingpage.programinovasi[
|
const res = await ApiFetch.api.landingpage.programinovasi[
|
||||||
"findMany"
|
"findMany"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
@@ -482,14 +487,19 @@ const mediaSosial = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
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.loading = true; // Use the full path to access the property
|
||||||
mediaSosial.findMany.page = page;
|
mediaSosial.findMany.page = page;
|
||||||
|
mediaSosial.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.landingpage.mediasosial[
|
const res = await ApiFetch.api.landingpage.mediasosial[
|
||||||
"findMany"
|
"findMany"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
|||||||
@@ -58,14 +58,19 @@ const sdgsDesa = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
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.loading = true; // Use the full path to access the property
|
||||||
sdgsDesa.findMany.page = page;
|
sdgsDesa.findMany.page = page;
|
||||||
|
sdgsDesa.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
||||||
"findMany"
|
"findMany"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
|||||||
@@ -348,18 +348,34 @@ const posisiOrganisasi = proxy({
|
|||||||
deskripsi: string | null;
|
deskripsi: string | null;
|
||||||
hierarki: number;
|
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 {
|
try {
|
||||||
const res = await ApiFetch.api.ppid.strukturppid.posisiorganisasi[
|
const query: any = { page, limit };
|
||||||
"find-many"
|
if (search) query.search = search;
|
||||||
].get();
|
|
||||||
if (res.status === 200) {
|
const res = await ApiFetch.api.ppid.strukturppid.posisiorganisasi["find-many"].get({ query });
|
||||||
// The API now returns the id field, so we can use it directly
|
|
||||||
this.data = res.data?.data ?? [];
|
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) {
|
} catch (err) {
|
||||||
console.error("Find many error:", error);
|
console.error("Gagal fetch posisi organisasi paginated:", err);
|
||||||
this.data = [];
|
posisiOrganisasi.findMany.data = [];
|
||||||
|
posisiOrganisasi.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
posisiOrganisasi.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -438,9 +454,9 @@ const pegawai = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
pegawai.create.loading = true;
|
pegawai.create.loading = true;
|
||||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
const res = await ApiFetch.api.ppid.strukturppid.pegawai["create"].post(
|
||||||
"create"
|
pegawai.create.form
|
||||||
].post(pegawai.create.form);
|
);
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
toast.success("Pegawai berhasil ditambahkan");
|
toast.success("Pegawai berhasil ditambahkan");
|
||||||
await pegawai.findMany.load();
|
await pegawai.findMany.load();
|
||||||
@@ -457,42 +473,55 @@ const pegawai = proxy({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// In struktur-organisasi.ts
|
// In struktur-organisasi.ts
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as any[] | null,
|
data: null as
|
||||||
page: 1,
|
| Prisma.PegawaiPPIDGetPayload<{
|
||||||
totalPages: 1,
|
include: {
|
||||||
total: 0,
|
image: true;
|
||||||
loading: false,
|
posisi: true;
|
||||||
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;
|
| null,
|
||||||
try {
|
page: 1,
|
||||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
totalPages: 1,
|
||||||
"find-many"
|
total: 0,
|
||||||
].get({
|
loading: false,
|
||||||
query: { page, limit },
|
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) {
|
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
||||||
pegawai.findMany.data = res.data.data || [];
|
"find-many"
|
||||||
pegawai.findMany.total = res.data.total || 0;
|
].get({
|
||||||
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
query,
|
||||||
} else {
|
});
|
||||||
console.error("Failed to load pegawai:", res.data?.message);
|
|
||||||
|
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.data = [];
|
||||||
pegawai.findMany.total = 0;
|
pegawai.findMany.total = 0;
|
||||||
pegawai.findMany.totalPages = 1;
|
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: {
|
findUnique: {
|
||||||
data: null as
|
data: null as
|
||||||
| (Prisma.PegawaiGetPayload<{
|
| (Prisma.PegawaiGetPayload<{
|
||||||
@@ -521,12 +550,9 @@ findMany: {
|
|||||||
if (!id) return toast.warn("ID tidak valid");
|
if (!id) return toast.warn("ID tidak valid");
|
||||||
try {
|
try {
|
||||||
pegawai.delete.loading = true;
|
pegawai.delete.loading = true;
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/ppid/strukturppid/pegawai/del/${id}`, {
|
||||||
`/api/ppid/strukturppid/pegawai/del/${id}`,
|
method: "DELETE",
|
||||||
{
|
});
|
||||||
method: "DELETE",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
toast.success(json.message ?? "Berhasil hapus pegawai");
|
toast.success(json.message ?? "Berhasil hapus pegawai");
|
||||||
@@ -555,15 +581,12 @@ findMany: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/ppid/strukturppid/pegawai/${id}`, {
|
||||||
`/api/ppid/strukturppid/pegawai/${id}`,
|
method: "GET",
|
||||||
{
|
headers: {
|
||||||
method: "GET",
|
"Content-Type": "application/json",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json",
|
});
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
@@ -677,7 +700,7 @@ findMany: {
|
|||||||
const stateStrukturPPID = proxy({
|
const stateStrukturPPID = proxy({
|
||||||
stateStruktur,
|
stateStruktur,
|
||||||
posisiOrganisasi,
|
posisiOrganisasi,
|
||||||
pegawai
|
pegawai,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default stateStrukturPPID;
|
export default stateStrukturPPID;
|
||||||
|
|||||||
@@ -143,8 +143,8 @@ function ListDemografiPekerjaan({ search }: { search: string }) {
|
|||||||
dataKey="pekerjaan"
|
dataKey="pekerjaan"
|
||||||
type="stacked"
|
type="stacked"
|
||||||
series={[
|
series={[
|
||||||
{ name: 'lakiLaki', color: 'red.6', label: 'Laki - Laki' },
|
{ name: 'lakiLaki', color: '#5082EE', label: 'Laki - Laki' },
|
||||||
{ name: 'perempuan', color: 'orange.6', label: 'Perempuan' },
|
{ name: 'perempuan', color: '#6EDF9C', label: 'Perempuan' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ function EditJumlahPendudukMiskin() {
|
|||||||
// Set the ID before submitting
|
// Set the ID before submitting
|
||||||
stateJPM.update.id = id;
|
stateJPM.update.id = id;
|
||||||
await stateJPM.update.submit();
|
await stateJPM.update.submit();
|
||||||
router.push('/admin/ekonomi/jumlah-penduduk-miskin-2024-2025')
|
router.push('/admin/ekonomi/jumlah-penduduk-miskin')
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function CreateJumlahPendudukMiskin() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
resetForm();
|
resetForm();
|
||||||
router.push("/admin/ekonomi/jumlah-penduduk-miskin-2024-2025");
|
router.push("/admin/ekonomi/jumlah-penduduk-miskin");
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ function ListJumlahPendudukMiskin({ search }: { search: string }) {
|
|||||||
<Paper bg={colors['white-1']} p={'md'}>
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
<JudulList
|
<JudulList
|
||||||
title='List Jumlah Penduduk Miskin'
|
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>
|
<Table striped withTableBorder withRowBorders>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
@@ -108,7 +108,7 @@ function ListJumlahPendudukMiskin({ search }: { search: string }) {
|
|||||||
<TableTd>{item.year}</TableTd>
|
<TableTd>{item.year}</TableTd>
|
||||||
<TableTd>{item.totalPoorPopulation}</TableTd>
|
<TableTd>{item.totalPoorPopulation}</TableTd>
|
||||||
<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} />
|
<IconEdit size={20} />
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
|
|||||||
@@ -8,29 +8,36 @@ import { useRouter } from 'next/navigation';
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Cell, Pie, PieChart } from 'recharts';
|
import { Cell, Pie, PieChart } from 'recharts';
|
||||||
import { useProxy } from 'valtio/utils';
|
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 { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
|
||||||
import grafikNganggur from '../../../_state/ekonomi/usia-kerja-nganggur';
|
import grafikNganggur from '../../../_state/ekonomi/usia-kerja-nganggur';
|
||||||
|
|
||||||
function GrafikBerdasarkanPendidikan() {
|
function GrafikBerdasarkanPendidikan() {
|
||||||
|
const [search, setSearch] = useState("")
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Title order={3}>Grafik Pengangguran Berdasarkan Pendidikan</Title>
|
<HeaderSearch
|
||||||
<ListGrafikBerdasarkanPendidikan />
|
title='Detail Data Pengangguran Berdasarkan Pendidikan'
|
||||||
|
placeholder='pencarian'
|
||||||
|
searchIcon={<IconSearch size={20} />}
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
<ListGrafikBerdasarkanPendidikan search={search}/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ListGrafikBerdasarkanPendidikan() {
|
function ListGrafikBerdasarkanPendidikan({search}: {search: string}) {
|
||||||
const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan)
|
const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanPendidikan)
|
||||||
const [donutData, setDonutData] = useState<any[]>([]);
|
const [donutData, setDonutData] = useState<any[]>([]);
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
const [modalHapus, setModalHapus] = useState(false)
|
const [modalHapus, setModalHapus] = useState(false)
|
||||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [search, setSearch] = useState("");
|
|
||||||
|
|
||||||
|
|
||||||
const handleDelete = async () => {
|
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 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);
|
const S1 = stategrafik.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.S1 || 0), 0);
|
||||||
setDonutData([
|
setDonutData([
|
||||||
{ name: 'SD', value: SD, color: colors['blue-button'], key: 'SD' },
|
{ name: 'SD', value: SD, color: '#4b6Ef5', key: 'SD' },
|
||||||
{ name: 'SMP', value: SMP, color: '#10A85AFF', key: 'SMP' },
|
{ name: 'SMP', value: SMP, color: '#14b885', key: 'SMP' },
|
||||||
{ name: 'SMA', value: SMA, color: '#C07B13FF', key: 'SMA' },
|
{ name: 'SMA', value: SMA, color: '#E6A03B', key: 'SMA' },
|
||||||
{ name: 'D3', value: D3, color: '#1094A8FF', key: 'D3' },
|
{ name: 'D3', value: D3, color: '#DB524D', key: 'D3' },
|
||||||
{ name: 'S1', value: S1, color: '#A83610FF', key: 'S1' },
|
{ name: 'S1', value: S1, color: '#1018A8FF', key: 'S1' },
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}, [stategrafik.findMany.data])
|
}, [stategrafik.findMany.data])
|
||||||
@@ -88,13 +95,9 @@ function ListGrafikBerdasarkanPendidikan() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Paper bg={colors['white-1']} p={"md"}>
|
<Paper bg={colors['white-1']} p={"md"}>
|
||||||
<JudulListTab
|
<JudulList
|
||||||
value={search}
|
|
||||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
|
||||||
title='List Grafik Pengangguran Berdasarkan Pendidikan'
|
title='List Grafik Pengangguran Berdasarkan Pendidikan'
|
||||||
href='/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/create'
|
href='/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_pendidikan/create'
|
||||||
placeholder='pencarian'
|
|
||||||
searchIcon={<IconSearch size={16} />}
|
|
||||||
/>
|
/>
|
||||||
<Table striped withTableBorder withRowBorders>
|
<Table striped withTableBorder withRowBorders>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
|
|||||||
@@ -8,29 +8,37 @@ import { useRouter } from 'next/navigation';
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Cell, Pie, PieChart } from 'recharts';
|
import { Cell, Pie, PieChart } from 'recharts';
|
||||||
import { useProxy } from 'valtio/utils';
|
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 { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
|
||||||
import grafikNganggur from '../../../_state/ekonomi/usia-kerja-nganggur';
|
import grafikNganggur from '../../../_state/ekonomi/usia-kerja-nganggur';
|
||||||
|
|
||||||
|
|
||||||
function GrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
function GrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||||
|
const [search, setSearch] = useState("")
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Title order={3}>Grafik Pengangguran Berdasarkan Usia Kerja</Title>
|
<HeaderSearch
|
||||||
<ListGrafikBerdasarkanUsiaKerjaYangMenganggur />
|
title='Detail Data Pengangguran'
|
||||||
|
placeholder='pencarian'
|
||||||
|
searchIcon={<IconSearch size={20} />}
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
<ListGrafikBerdasarkanUsiaKerjaYangMenganggur search={search} />
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ListGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
function ListGrafikBerdasarkanUsiaKerjaYangMenganggur({search}: {search: string}) {
|
||||||
const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanUsiaKerjaNganggur)
|
const stategrafik = useProxy(grafikNganggur.grafikBerdasarkanUsiaKerjaNganggur)
|
||||||
const [donutData, setDonutData] = useState<any[]>([]);
|
const [donutData, setDonutData] = useState<any[]>([]);
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
const [modalHapus, setModalHapus] = useState(false)
|
const [modalHapus, setModalHapus] = useState(false)
|
||||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [search, setSearch] = useState("");
|
|
||||||
|
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
@@ -85,13 +93,9 @@ function ListGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Paper bg={colors['white-1']} p={"md"}>
|
<Paper bg={colors['white-1']} p={"md"}>
|
||||||
<JudulListTab
|
<JudulList
|
||||||
value={search}
|
|
||||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
|
||||||
title='List Pengangguran Berdasarkan Usia Kerja'
|
title='List Pengangguran Berdasarkan Usia Kerja'
|
||||||
href='/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/create'
|
href='/admin/ekonomi/jumlah-penduduk-usia-kerja-yang-menganggur/pengangguran_berdasarkan_usia/create'
|
||||||
placeholder='pencarian'
|
|
||||||
searchIcon={<IconSearch size={16} />}
|
|
||||||
/>
|
/>
|
||||||
<Table striped withTableBorder withRowBorders>
|
<Table striped withTableBorder withRowBorders>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
|
|||||||
@@ -66,19 +66,23 @@ function EditDetailDataPengangguran() {
|
|||||||
const data = stateDetail.findUnique.data;
|
const data = stateDetail.findUnique.data;
|
||||||
|
|
||||||
if (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
|
// Set the ID for update
|
||||||
stateDetail.update.id = id;
|
stateDetail.update.id = id;
|
||||||
|
|
||||||
// Isi state Valtio untuk update
|
// Update Valtio state with converted year
|
||||||
stateDetail.update.form = {
|
stateDetail.update.form = {
|
||||||
...data,
|
...data,
|
||||||
|
year: yearValue,
|
||||||
percentageChange: data.percentageChange || 0 // Ensure it's always a number
|
percentageChange: data.percentageChange || 0 // Ensure it's always a number
|
||||||
};
|
};
|
||||||
|
|
||||||
// Isi local formData supaya input bisa dikontrol
|
// Update local formData with converted year
|
||||||
setFormData({
|
setFormData({
|
||||||
month: data.month,
|
month: data.month,
|
||||||
year: data.year,
|
year: yearValue,
|
||||||
totalUnemployment: data.totalUnemployment,
|
totalUnemployment: data.totalUnemployment,
|
||||||
educatedUnemployment: data.educatedUnemployment,
|
educatedUnemployment: data.educatedUnemployment,
|
||||||
uneducatedUnemployment: data.uneducatedUnemployment,
|
uneducatedUnemployment: data.uneducatedUnemployment,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function DetailJumlahPengangguran() {
|
|||||||
stateDetail.delete.byId(selectedId)
|
stateDetail.delete.byId(selectedId)
|
||||||
setModalHapus(false)
|
setModalHapus(false)
|
||||||
setSelectedId(null)
|
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>
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={"bold"}>Tahun</Text>
|
<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>
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={"bold"}>Bulan</Text>
|
<Text fw={"bold"}>Bulan</Text>
|
||||||
@@ -86,7 +86,7 @@ function DetailJumlahPengangguran() {
|
|||||||
color={"red"}>
|
color={"red"}>
|
||||||
<IconX size={20} />
|
<IconX size={20} />
|
||||||
</Button>
|
</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} />
|
<IconEdit size={20} />
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -108,4 +108,3 @@ function DetailJumlahPengangguran() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default DetailJumlahPengangguran;
|
export default DetailJumlahPengangguran;
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ function CreateJumlahPengangguran() {
|
|||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Tahun"
|
label="Tahun"
|
||||||
type="number"
|
type="date"
|
||||||
value={stateDetail.create.form.year}
|
value={stateDetail.create.form.year}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
(stateDetail.create.form.year = Number(e.currentTarget.value))
|
(stateDetail.create.form.year = Number(e.currentTarget.value))
|
||||||
|
|||||||
@@ -8,21 +8,29 @@ import { useEffect, useState } from 'react';
|
|||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
import { BarChart } from '@mantine/charts';
|
import { BarChart } from '@mantine/charts';
|
||||||
|
import HeaderSearch from '../../_com/header';
|
||||||
|
import JudulList from '../../_com/judulList';
|
||||||
import jumlahPengangguranState from '../../_state/ekonomi/jumlah-pengangguran';
|
import jumlahPengangguranState from '../../_state/ekonomi/jumlah-pengangguran';
|
||||||
import JudulListTab from '../../_com/judulListTab';
|
|
||||||
|
|
||||||
function DetailDataPengangguran() {
|
function DetailDataPengangguran() {
|
||||||
|
const [search, setSearch] = useState("")
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Title order={3}>Detail Data Pengangguran</Title>
|
<HeaderSearch
|
||||||
<ListDetailDataPengangguran />
|
title='Detail Data Pengangguran'
|
||||||
|
placeholder='pencarian'
|
||||||
|
searchIcon={<IconSearch size={20} />}
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
<ListDetailDataPengangguran search={search} />
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ListDetailDataPengangguran() {
|
function ListDetailDataPengangguran({search}: {search: string}) {
|
||||||
|
|
||||||
type DetailDataPengangguran = {
|
type DetailDataPengangguran = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -37,7 +45,6 @@ function ListDetailDataPengangguran() {
|
|||||||
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
|
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
|
||||||
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran)
|
const stateDetail = useProxy(jumlahPengangguranState.jumlahPengangguran)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [search, setSearch] = useState("")
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
setMounted(true)
|
setMounted(true)
|
||||||
@@ -50,7 +57,7 @@ function ListDetailDataPengangguran() {
|
|||||||
setChartData(stateDetail.findMany.data.map((item) => ({
|
setChartData(stateDetail.findMany.data.map((item) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
month: item.month,
|
month: item.month,
|
||||||
year: item.year,
|
year: item.year instanceof Date ? item.year.getFullYear() : Number(item.year),
|
||||||
educatedUnemployment: Number(item.educatedUnemployment),
|
educatedUnemployment: Number(item.educatedUnemployment),
|
||||||
uneducatedUnemployment: Number(item.uneducatedUnemployment),
|
uneducatedUnemployment: Number(item.uneducatedUnemployment),
|
||||||
percentageChange: Number(item.percentageChange),
|
percentageChange: Number(item.percentageChange),
|
||||||
@@ -78,13 +85,9 @@ function ListDetailDataPengangguran() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Stack gap={"md"}>
|
<Stack gap={"md"}>
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
<JudulListTab
|
<JudulList
|
||||||
title='List Detail Data Pengangguran'
|
title='List Detail Data Pengangguran'
|
||||||
href='/admin/ekonomi/jumlah-pengangguran/detail-data-pengangguran/create'
|
href='/admin/ekonomi/jumlah-pengangguran/create'
|
||||||
value={search}
|
|
||||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
|
||||||
placeholder='pencarian'
|
|
||||||
searchIcon={<IconSearch size={16} />}
|
|
||||||
/>
|
/>
|
||||||
<Table striped withTableBorder withRowBorders>
|
<Table striped withTableBorder withRowBorders>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
@@ -102,7 +105,7 @@ function ListDetailDataPengangguran() {
|
|||||||
<TableTd>{item.educatedUnemployment}</TableTd>
|
<TableTd>{item.educatedUnemployment}</TableTd>
|
||||||
<TableTd>{item.uneducatedUnemployment}</TableTd>
|
<TableTd>{item.uneducatedUnemployment}</TableTd>
|
||||||
<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} />
|
<IconDeviceImac size={20} />
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
|
|||||||
@@ -55,17 +55,17 @@ function EditLowonganKerja() {
|
|||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
lowonganKerjaState.update.form = {
|
// Set the ID for the update
|
||||||
...lowonganKerjaState.update.form,
|
lowonganState.update.id = params?.id as string;
|
||||||
posisi: formData.posisi,
|
|
||||||
namaPerusahaan: formData.namaPerusahaan,
|
// Update the form state
|
||||||
lokasi: formData.lokasi,
|
lowonganState.update.form = {
|
||||||
tipePekerjaan: formData.tipePekerjaan,
|
...lowonganState.update.form,
|
||||||
gaji: formData.gaji,
|
...formData
|
||||||
deskripsi: formData.deskripsi,
|
};
|
||||||
kualifikasi: formData.kualifikasi,
|
|
||||||
}
|
// Call the update function
|
||||||
await lowonganState.update.update()
|
await lowonganState.update.update();
|
||||||
toast.success("Lowongan kerja berhasil diperbarui!");
|
toast.success("Lowongan kerja berhasil diperbarui!");
|
||||||
router.push("/admin/ekonomi/lowongan-kerja-lokal");
|
router.push("/admin/ekonomi/lowongan-kerja-lokal");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -88,7 +88,7 @@ function EditLowonganKerja() {
|
|||||||
<TextInput
|
<TextInput
|
||||||
value={formData.posisi}
|
value={formData.posisi}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
formData.posisi = val.target.value;
|
setFormData(prev => ({ ...prev, posisi: val.target.value }));
|
||||||
}}
|
}}
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Posisi</Text>}
|
label={<Text fw={"bold"} fz={"sm"}>Posisi</Text>}
|
||||||
placeholder='Masukkan posisi'
|
placeholder='Masukkan posisi'
|
||||||
@@ -96,7 +96,7 @@ function EditLowonganKerja() {
|
|||||||
<TextInput
|
<TextInput
|
||||||
value={formData.namaPerusahaan}
|
value={formData.namaPerusahaan}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
formData.namaPerusahaan = val.target.value;
|
setFormData(prev => ({ ...prev, namaPerusahaan: val.target.value }));
|
||||||
}}
|
}}
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Nama Perusahaan</Text>}
|
label={<Text fw={"bold"} fz={"sm"}>Nama Perusahaan</Text>}
|
||||||
placeholder='Masukkan nama perusahaan'
|
placeholder='Masukkan nama perusahaan'
|
||||||
@@ -104,7 +104,7 @@ function EditLowonganKerja() {
|
|||||||
<TextInput
|
<TextInput
|
||||||
value={formData.lokasi}
|
value={formData.lokasi}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
formData.lokasi = val.target.value;
|
setFormData(prev => ({ ...prev, lokasi: val.target.value }));
|
||||||
}}
|
}}
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Lokasi</Text>}
|
label={<Text fw={"bold"} fz={"sm"}>Lokasi</Text>}
|
||||||
placeholder='Masukkan lokasi'
|
placeholder='Masukkan lokasi'
|
||||||
@@ -112,7 +112,7 @@ function EditLowonganKerja() {
|
|||||||
<TextInput
|
<TextInput
|
||||||
value={formData.tipePekerjaan}
|
value={formData.tipePekerjaan}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
formData.tipePekerjaan = val.target.value;
|
setFormData(prev => ({ ...prev, tipePekerjaan: val.target.value }));
|
||||||
}}
|
}}
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Tipe Pekerjaan</Text>}
|
label={<Text fw={"bold"} fz={"sm"}>Tipe Pekerjaan</Text>}
|
||||||
placeholder='Masukkan tipe pekerjaan'
|
placeholder='Masukkan tipe pekerjaan'
|
||||||
@@ -120,7 +120,7 @@ function EditLowonganKerja() {
|
|||||||
<TextInput
|
<TextInput
|
||||||
value={formData.gaji}
|
value={formData.gaji}
|
||||||
onChange={(val) => {
|
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>}
|
label={<Text fw={"bold"} fz={"sm"}>Gaji selama 1 bulan</Text>}
|
||||||
placeholder='Masukkan gaji'
|
placeholder='Masukkan gaji'
|
||||||
@@ -130,7 +130,7 @@ function EditLowonganKerja() {
|
|||||||
<EditEditor
|
<EditEditor
|
||||||
value={formData.deskripsi}
|
value={formData.deskripsi}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
formData.deskripsi = val;
|
setFormData(prev => ({ ...prev, deskripsi: val }));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -139,7 +139,7 @@ function EditLowonganKerja() {
|
|||||||
<EditEditor
|
<EditEditor
|
||||||
value={formData.kualifikasi}
|
value={formData.kualifikasi}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
formData.kualifikasi = val;
|
setFormData(prev => ({ ...prev, kualifikasi: val }));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import HeaderSearch from '../../_com/header';
|
import HeaderSearch from '../../_com/header';
|
||||||
import JudulList from '../../_com/judulList';
|
import JudulList from '../../_com/judulList';
|
||||||
@@ -30,20 +30,21 @@ function ListLowonganKerjaLokal({ search }: { search: string }) {
|
|||||||
const lowonganState = useProxy(lowonganKerjaState)
|
const lowonganState = useProxy(lowonganKerjaState)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = lowonganState.findMany
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
lowonganState.findMany.load();
|
load(page, 10, search)
|
||||||
}, [])
|
}, [page, search])
|
||||||
|
|
||||||
const filteredData = (lowonganState.findMany.data || []).filter(item => {
|
const filteredData = data || []
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.posisi.toLowerCase().includes(keyword) ||
|
|
||||||
item.namaPerusahaan.toLowerCase().includes(keyword) ||
|
|
||||||
item.lokasi.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!lowonganState.findMany.data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -60,18 +61,24 @@ function ListLowonganKerjaLokal({ search }: { search: string }) {
|
|||||||
<Table striped withTableBorder withRowBorders>
|
<Table striped withTableBorder withRowBorders>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Bekerja Sebagai</TableTh>
|
<TableTh>Pekerjaan</TableTh>
|
||||||
<TableTh>Nama Usaha</TableTh>
|
<TableTh>Nama Perusahaan</TableTh>
|
||||||
<TableTh>Alamat Usaha</TableTh>
|
<TableTh>Lokasi</TableTh>
|
||||||
<TableTh>Detail</TableTh>
|
<TableTh>Detail</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
{filteredData.map((item) => (
|
{filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>{item.posisi}</TableTd>
|
<TableTd>
|
||||||
<TableTd>{item.namaPerusahaan}</TableTd>
|
<Text fz={"md"}>{item.posisi}</Text>
|
||||||
<TableTd>{item.lokasi}</TableTd>
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Text fz={"md"}>{item.namaPerusahaan}</Text>
|
||||||
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Text fz={"md"}>{item.lokasi}</Text>
|
||||||
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Button onClick={() => router.push(`/admin/ekonomi/lowongan-kerja-lokal/${item.id}`)}>
|
<Button onClick={() => router.push(`/admin/ekonomi/lowongan-kerja-lokal/${item.id}`)}>
|
||||||
<IconDeviceImac size={20} />
|
<IconDeviceImac size={20} />
|
||||||
@@ -82,6 +89,14 @@ function ListLowonganKerjaLokal({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my="md"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
import { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -13,31 +13,39 @@ import pasarDesaState from '../../../_state/ekonomi/pasar-desa/pasar-desa';
|
|||||||
|
|
||||||
|
|
||||||
function PasarDesa() {
|
function PasarDesa() {
|
||||||
const [search, setSearch] = useState("")
|
const [search2, setSearch2] = useState("")
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<HeaderSearch
|
<HeaderSearch
|
||||||
title='Kategori Produk'
|
title='Kategori Produk'
|
||||||
placeholder='pencarian'
|
placeholder='pencarian'
|
||||||
searchIcon={<IconSearch size={20} />}
|
searchIcon={<IconSearch size={20} />}
|
||||||
value={search}
|
value={search2}
|
||||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
onChange={(e) => setSearch2(e.currentTarget.value)}
|
||||||
/>
|
/>
|
||||||
<ListPasarDesa search={search} />
|
<ListPasarDesa search2={search2} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ListPasarDesa({ search }: { search: string }) {
|
function ListPasarDesa({ search2 }: { search2: string }) {
|
||||||
const statePasar = useProxy(pasarDesaState.kategoriProduk)
|
const statePasar = useProxy(pasarDesaState.kategoriProduk)
|
||||||
const [modalHapus, setModalHapus] = useState(false)
|
const [modalHapus, setModalHapus] = useState(false)
|
||||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||||
// const params = useParams()
|
// const params = useParams()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = statePasar.findMany
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
statePasar.findMany.load()
|
load(page, 10, search2)
|
||||||
}, [])
|
}, [page, search2])
|
||||||
|
|
||||||
const handleHapus = () => {
|
const handleHapus = () => {
|
||||||
if (selectedId) {
|
if (selectedId) {
|
||||||
@@ -47,14 +55,9 @@ function ListPasarDesa({ search }: { search: string }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredData = (statePasar.findMany.data || []).filter(item => {
|
const filteredData = data || []
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.nama.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!statePasar.findMany.data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -99,6 +102,14 @@ function ListPasarDesa({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my={"md"}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
{/* Modal Konfirmasi Hapus */}
|
{/* Modal Konfirmasi Hapus */}
|
||||||
<ModalKonfirmasiHapus
|
<ModalKonfirmasiHapus
|
||||||
opened={modalHapus}
|
opened={modalHapus}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -30,21 +30,21 @@ function ListPasarDesa({ search }: { search: string }) {
|
|||||||
const statePasar = useProxy(pasarDesaState.pasarDesa)
|
const statePasar = useProxy(pasarDesaState.pasarDesa)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = statePasar.findMany
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
statePasar.findMany.load()
|
load(page, 10, search)
|
||||||
}, [])
|
}, [page, search])
|
||||||
|
|
||||||
const filteredData = (statePasar.findMany.data || []).filter(item => {
|
const filteredData = data || []
|
||||||
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)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!statePasar.findMany.data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -86,6 +86,14 @@ function ListPasarDesa({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my={"md"}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import HeaderSearch from '../../_com/header';
|
import HeaderSearch from '../../_com/header';
|
||||||
import JudulList from '../../_com/judulList';
|
import JudulList from '../../_com/judulList';
|
||||||
@@ -23,7 +23,7 @@ function ProgramKemiskinan() {
|
|||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
/>
|
/>
|
||||||
<ListProgramKemiskinan search={search}/>
|
<ListProgramKemiskinan search={search} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -34,14 +34,22 @@ function ListProgramKemiskinan({ search }: { search: string }) {
|
|||||||
const [lineChart, setLineChart] = useState<any[]>([]);
|
const [lineChart, setLineChart] = useState<any[]>([]);
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = programState.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
setMounted(true)
|
setMounted(true)
|
||||||
programState.findMany.load()
|
load(page, 10, search)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (programState.findMany.data) {
|
if (data) {
|
||||||
const chartData = programState.findMany.data
|
const chartData = data
|
||||||
.filter(item => item.statistik)
|
.filter(item => item.statistik)
|
||||||
.map(item => ({
|
.map(item => ({
|
||||||
tahun: item.statistik?.tahun,
|
tahun: item.statistik?.tahun,
|
||||||
@@ -52,18 +60,11 @@ function ListProgramKemiskinan({ search }: { search: string }) {
|
|||||||
setLineChart(chartData);
|
setLineChart(chartData);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [programState.findMany.data])
|
}, [data])
|
||||||
|
|
||||||
const filteredData = (programState.findMany.data || []).filter(item => {
|
const filteredData = data || []
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.nama.toLowerCase().includes(keyword) ||
|
|
||||||
item.deskripsi.toLowerCase().includes(keyword) ||
|
|
||||||
item.statistik?.tahun.toString().includes(keyword)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!programState.findMany.data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -112,7 +113,7 @@ function ListProgramKemiskinan({ search }: { search: string }) {
|
|||||||
<Box >
|
<Box >
|
||||||
<Title pb={10} order={3}>Grafik Berdasarkan Responden</Title>
|
<Title pb={10} order={3}>Grafik Berdasarkan Responden</Title>
|
||||||
{mounted && lineChart.length > 0 ? (<Box style={{ width: '100%', height: 'auto', }}>
|
{mounted && lineChart.length > 0 ? (<Box style={{ width: '100%', height: 'auto', }}>
|
||||||
<Box w={"100%"} style={{overflowX: 'auto'}}>
|
<Box w={"100%"} style={{ overflowX: 'auto' }}>
|
||||||
<LineChart
|
<LineChart
|
||||||
width={820}
|
width={820}
|
||||||
height={300}
|
height={300}
|
||||||
@@ -143,6 +144,14 @@ function ListProgramKemiskinan({ search }: { search: string }) {
|
|||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my={"md"}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,15 +2,16 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconArrowBack } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import grafikSektorUnggulan from '../../../_state/ekonomi/sektor-unggulan-desa';
|
import grafikSektorUnggulan from '../../../_state/ekonomi/sektor-unggulan-desa';
|
||||||
|
import CreateEditor from '../../../_com/createEditor';
|
||||||
|
|
||||||
function CreateSektorUnggulanDesa() {
|
function CreateSektorUnggulanDesa() {
|
||||||
const stateGrafik= useProxy(grafikSektorUnggulan);
|
const stateGrafik = useProxy(grafikSektorUnggulan);
|
||||||
const [chartData, setChartData] = useState<any[]>([]);
|
const [chartData, setChartData] = useState<any[]>([]);
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@@ -54,15 +55,15 @@ function CreateSektorUnggulanDesa() {
|
|||||||
stateGrafik.create.form.name = val.currentTarget.value;
|
stateGrafik.create.form.name = val.currentTarget.value;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<Box>
|
||||||
label="Deskripsi Sektor Unggulan"
|
<Text fw={"bold"} fz={"sm"}>Deskripsi Sektor Ungggulan</Text>
|
||||||
type="text"
|
<CreateEditor
|
||||||
value={stateGrafik.create.form.description}
|
value={stateGrafik.create.form.description}
|
||||||
placeholder="Masukkan deskripsi sektor unggulan"
|
onChange={(val) => {
|
||||||
onChange={(val) => {
|
stateGrafik.create.form.description = val;
|
||||||
stateGrafik.create.form.description = val.currentTarget.value;
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</Box>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Jumlah"
|
label="Jumlah"
|
||||||
type="number"
|
type="number"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import HeaderSearch from '../../_com/header';
|
import HeaderSearch from '../../_com/header';
|
||||||
import JudulList from '../../_com/judulList';
|
import JudulList from '../../_com/judulList';
|
||||||
@@ -30,7 +30,7 @@ function SektorUnggulanDesa() {
|
|||||||
function ListSektorUnggulanDesa({ search }: { search: string }) {
|
function ListSektorUnggulanDesa({ search }: { search: string }) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const state = useProxy(grafikSektorUnggulan);
|
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 [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
|
||||||
const isTablet = useMediaQuery('(max-width: 1024px)')
|
const isTablet = useMediaQuery('(max-width: 1024px)')
|
||||||
const isMobile = useMediaQuery('(max-width: 768px)')
|
const isMobile = useMediaQuery('(max-width: 768px)')
|
||||||
@@ -61,38 +61,41 @@ function ListSektorUnggulanDesa({ search }: { search: string }) {
|
|||||||
}, [state.findMany.data]);
|
}, [state.findMany.data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box>
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
<Stack gap={"xs"}>
|
||||||
<JudulList
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
title='List Sektor Unggulan Desa'
|
<JudulList
|
||||||
href='/admin/ekonomi/sektor-unggulan-desa/create'
|
title='List Sektor Unggulan Desa'
|
||||||
/>
|
href='/admin/ekonomi/sektor-unggulan-desa/create'
|
||||||
<Table striped withTableBorder withRowBorders>
|
/>
|
||||||
<TableThead>
|
<Table striped withTableBorder withRowBorders>
|
||||||
<TableTr>
|
<TableThead>
|
||||||
<TableTh>Nama Sektor Unggulan</TableTh>
|
<TableTr>
|
||||||
<TableTh>Deskripsi Sektor Unggulan</TableTh>
|
<TableTh>Nama Sektor Unggulan</TableTh>
|
||||||
<TableTh>Detail</TableTh>
|
<TableTh>Deskripsi Sektor Unggulan</TableTh>
|
||||||
</TableTr>
|
<TableTh>Detail</TableTh>
|
||||||
</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>
|
|
||||||
</TableTr>
|
</TableTr>
|
||||||
))}
|
</TableThead>
|
||||||
</TableTbody>
|
<TableTbody>
|
||||||
</Table>
|
{filteredData.map((item) => (
|
||||||
</Paper>
|
<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 */}
|
{/* Chart */}
|
||||||
{!mounted && !chartData ? (
|
{!mounted && !chartData ? (
|
||||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
<Title pb={10} order={3}>Grafik Hasil Kepuasan Masyarakat</Title>
|
<Title pb={10} order={3}>Grafik Hasil Kepuasan Masyarakat</Title>
|
||||||
@@ -115,6 +118,7 @@ function ListSektorUnggulanDesa({ search }: { search: string }) {
|
|||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import HeaderSearch from '../../_com/header';
|
import HeaderSearch from '../../_com/header';
|
||||||
import JudulList from '../../_com/judulList';
|
import JudulList from '../../_com/judulList';
|
||||||
@@ -30,19 +30,21 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
|||||||
const stateKeamanan = useProxy(tipsKeamananState)
|
const stateKeamanan = useProxy(tipsKeamananState)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = stateKeamanan.findMany
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
stateKeamanan.findMany.load()
|
load(page, 10, search)
|
||||||
}, [])
|
}, [page, search])
|
||||||
|
|
||||||
const filteredData = (stateKeamanan.findMany.data || []).filter(item => {
|
const filteredData = data || []
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.judul.toLowerCase().includes(keyword) ||
|
|
||||||
item.deskripsi.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!stateKeamanan.findMany.data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -67,9 +69,15 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
|||||||
<TableTbody>
|
<TableTbody>
|
||||||
{filteredData.map((item) => (
|
{filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>{item.judul}</TableTd>
|
|
||||||
<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>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Button onClick={() => router.push(`/admin/keamanan/tips-keamanan/${item.id}`)}>
|
<Button onClick={() => router.push(`/admin/keamanan/tips-keamanan/${item.id}`)}>
|
||||||
@@ -81,6 +89,14 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my="md"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ function DetailFasilitasKesehatan() {
|
|||||||
<GridCol span={12}>
|
<GridCol span={12}>
|
||||||
<Text fz={"xl"} fw={"bold"}>Detail Fasilitas Kesehatan</Text>
|
<Text fz={"xl"} fw={"bold"}>Detail Fasilitas Kesehatan</Text>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
<GridCol span={12}>
|
{/* <GridCol span={12}>
|
||||||
<Flex gap={"xs"}>
|
<Flex gap={"xs"}>
|
||||||
<Button color={colors['blue-button']} onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/${params?.id}/dokter-tenaga-medis`)}>
|
<Button color={colors['blue-button']} onClick={() => router.push(`/admin/kesehatan/data-kesehatan-warga/fasilitas_kesehatan/${params?.id}/dokter-tenaga-medis`)}>
|
||||||
Tambah Dokter
|
Tambah Dokter
|
||||||
@@ -60,7 +60,7 @@ function DetailFasilitasKesehatan() {
|
|||||||
Tambah Layanan
|
Tambah Layanan
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
</GridCol>
|
</GridCol> */}
|
||||||
</Grid>
|
</Grid>
|
||||||
{stateFasilitasKesehatan.findUnique.data ? (
|
{stateFasilitasKesehatan.findUnique.data ? (
|
||||||
<Paper bg={colors['BG-trans']} p={'md'}>
|
<Paper bg={colors['BG-trans']} p={'md'}>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconDeviceImacCog, IconFile, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import HeaderSearch from '../../_com/header';
|
import HeaderSearch from '../../_com/header';
|
||||||
import JudulList from '../../_com/judulList';
|
import JudulList from '../../_com/judulList';
|
||||||
@@ -30,19 +30,22 @@ function APBDes() {
|
|||||||
function ListAPBDes({ search }: { search: string }) {
|
function ListAPBDes({ search }: { search: string }) {
|
||||||
const listState = useProxy(apbdes)
|
const listState = useProxy(apbdes)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
useEffect(() => {
|
|
||||||
listState.findMany.load()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const filteredData = (listState.findMany.data || []).filter(item => {
|
const {
|
||||||
const keyword = search.toLowerCase();
|
data,
|
||||||
return (
|
page,
|
||||||
item.name.toLowerCase().includes(keyword) ||
|
totalPages,
|
||||||
item.jumlah.toLowerCase().includes(keyword)
|
loading,
|
||||||
)
|
load,
|
||||||
});
|
} = listState.findMany
|
||||||
|
|
||||||
if (!listState.findMany.data) {
|
useShallowEffect(() => {
|
||||||
|
load(page, 10, search)
|
||||||
|
}, [page, search])
|
||||||
|
|
||||||
|
const filteredData = data || []
|
||||||
|
|
||||||
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -88,7 +91,7 @@ function ListAPBDes({ search }: { search: string }) {
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
variant='transparent'
|
variant='transparent'
|
||||||
>
|
>
|
||||||
<IconFile size={25} color={colors['blue-button']}/>
|
<IconFile size={25} color={colors['blue-button']} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
) : (
|
) : (
|
||||||
<Text>Tidak ada dokumen tersedia</Text>
|
<Text>Tidak ada dokumen tersedia</Text>
|
||||||
@@ -106,6 +109,14 @@ function ListAPBDes({ search }: { search: string }) {
|
|||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my={"md"}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Center, Pagination, 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 { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import HeaderSearch from '../../../_com/header';
|
import HeaderSearch from '../../../_com/header';
|
||||||
import JudulList from '../../../_com/judulList';
|
import JudulList from '../../../_com/judulList';
|
||||||
@@ -50,19 +50,11 @@ function ListKategoriKegiatan({ search }: { search: string }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10)
|
load(page, 10, search)
|
||||||
}, [page])
|
}, [page, search])
|
||||||
|
|
||||||
const filteredData = useMemo(() => {
|
const filteredData = data || []
|
||||||
if (!data) return [];
|
|
||||||
return data.filter(item => {
|
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.name?.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}, [data, search]);
|
|
||||||
|
|
||||||
// Handle loading state
|
// Handle loading state
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import HeaderSearch from '../../../_com/header';
|
import HeaderSearch from '../../../_com/header';
|
||||||
import JudulList from '../../../_com/judulList';
|
import JudulList from '../../../_com/judulList';
|
||||||
@@ -38,22 +38,11 @@ function ListDesaAntiKorupsi({ search }: { search: string }) {
|
|||||||
load,
|
load,
|
||||||
} = listState.findMany;
|
} = listState.findMany;
|
||||||
|
|
||||||
useEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10);
|
load(page, 10, search);
|
||||||
}, [page]);
|
}, [page, search]);
|
||||||
|
|
||||||
const filteredData = useMemo(() => {
|
const filteredData = data || []
|
||||||
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]);
|
|
||||||
|
|
||||||
// Handle loading state
|
// Handle loading state
|
||||||
if (loading || !data) {
|
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'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
import { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -42,18 +42,21 @@ function ListKategoriPrestasi({ search }: { search: string }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = stateKategori.findMany
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
stateKategori.findMany.load()
|
load(page, 10, search)
|
||||||
}, [])
|
}, [page, search])
|
||||||
|
|
||||||
const filteredData = (stateKategori.findMany.data || []).filter(item => {
|
const filteredData = data || []
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.name.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!stateKategori.findMany.data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -100,6 +103,14 @@ function ListKategoriPrestasi({ search }: { search: string }) {
|
|||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my={"md"}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
{/* Modal Konfirmasi Hapus */}
|
{/* Modal Konfirmasi Hapus */}
|
||||||
<ModalKonfirmasiHapus
|
<ModalKonfirmasiHapus
|
||||||
opened={modalHapus}
|
opened={modalHapus}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -30,20 +30,36 @@ function ListPrestasiDesa() {
|
|||||||
function ListPrestasi({ search }: { search: string }) {
|
function ListPrestasi({ search }: { search: string }) {
|
||||||
const listState = useProxy(prestasiState.prestasiDesa)
|
const listState = useProxy(prestasiState.prestasiDesa)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
useEffect(() => {
|
|
||||||
listState.findMany.load()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const filteredData = (listState.findMany.data || []).filter(item => {
|
const{
|
||||||
const keyword = search.toLowerCase();
|
data,
|
||||||
return (
|
page,
|
||||||
item.name.toLowerCase().includes(keyword) ||
|
totalPages,
|
||||||
item.deskripsi.toLowerCase().includes(keyword) ||
|
loading,
|
||||||
item.kategori?.name?.toLowerCase().includes(keyword)
|
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 (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -82,7 +98,7 @@ function ListPrestasi({ search }: { search: string }) {
|
|||||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||||
</Box>
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>{item.kategori?.name}</TableTd>
|
<TableTd>{item.kategori?.name || 'No Category'}</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Button onClick={() => router.push(`/admin/landing-page/prestasi-desa/list-prestasi-desa/${item.id}`)}>
|
<Button onClick={() => router.push(`/admin/landing-page/prestasi-desa/list-prestasi-desa/${item.id}`)}>
|
||||||
<IconDeviceImacCog size={25} />
|
<IconDeviceImacCog size={25} />
|
||||||
@@ -95,6 +111,14 @@ function ListPrestasi({ search }: { search: string }) {
|
|||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my={"md"}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { 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 { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import HeaderSearch from '../../../_com/header';
|
import HeaderSearch from '../../../_com/header';
|
||||||
import JudulList from '../../../_com/judulList';
|
import JudulList from '../../../_com/judulList';
|
||||||
@@ -38,20 +38,11 @@ function ListMediaSosial({ search }: { search: string }) {
|
|||||||
load,
|
load,
|
||||||
} = stateMediaSosial.findMany;
|
} = stateMediaSosial.findMany;
|
||||||
|
|
||||||
useEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10)
|
load(page, 10, search)
|
||||||
}, [page])
|
}, [page, search])
|
||||||
|
|
||||||
const filteredData = useMemo(() => {
|
const filteredData = data || []
|
||||||
if (!data) return [];
|
|
||||||
return data.filter(item => {
|
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.name?.toLowerCase().includes(keyword) ||
|
|
||||||
item.iconUrl?.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}, [data, search]);
|
|
||||||
|
|
||||||
// Handle loading state
|
// Handle loading state
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ function DetailProgramInovasi() {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz={"lg"} fw={"bold"}>Deskripsi</Text>
|
<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>
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz={"lg"} fw={"bold"}>Link</Text>
|
<Text fz={"lg"} fw={"bold"}>Link</Text>
|
||||||
@@ -63,6 +66,12 @@ function DetailProgramInovasi() {
|
|||||||
href={stateProgramInovasi.findUnique.data?.link || "#"}
|
href={stateProgramInovasi.findUnique.data?.link || "#"}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
|
style={{
|
||||||
|
wordWrap: 'break-word',
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
overflowWrap: 'break-word',
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{stateProgramInovasi.findUnique.data?.link || "Tidak ada link"}
|
{stateProgramInovasi.findUnique.data?.link || "Tidak ada link"}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import HeaderSearch from '../../../_com/header';
|
import HeaderSearch from '../../../_com/header';
|
||||||
import JudulList from '../../../_com/judulList';
|
import JudulList from '../../../_com/judulList';
|
||||||
@@ -38,21 +38,11 @@ function ListProgramInovasi({ search }: { search: string }) {
|
|||||||
load,
|
load,
|
||||||
} = stateProgramInovasi.findMany;
|
} = stateProgramInovasi.findMany;
|
||||||
|
|
||||||
useEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10);
|
load(page, 10, search);
|
||||||
}, [page]);
|
}, [page, search]);
|
||||||
|
|
||||||
const filteredData = useMemo(() => {
|
const filteredData = data || []
|
||||||
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]);
|
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import HeaderSearch from '../../_com/header';
|
import HeaderSearch from '../../_com/header';
|
||||||
import sdgsDesa from '../../_state/landing-page/sdgs-desa';
|
|
||||||
import JudulList from '../../_com/judulList';
|
import JudulList from '../../_com/judulList';
|
||||||
|
import sdgsDesa from '../../_state/landing-page/sdgs-desa';
|
||||||
|
|
||||||
|
|
||||||
function SdgsDesa() {
|
function SdgsDesa() {
|
||||||
@@ -39,20 +39,11 @@ function ListSdgsDesa({ search }: { search: string }) {
|
|||||||
load,
|
load,
|
||||||
} = listState.findMany;
|
} = listState.findMany;
|
||||||
|
|
||||||
useEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10)
|
load(page, 10, search)
|
||||||
}, [])
|
}, [page, search])
|
||||||
|
|
||||||
const filteredData = useMemo(() => {
|
const filteredData = data || []
|
||||||
if (!data) return [];
|
|
||||||
return data.filter(item => {
|
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.name?.toLowerCase().includes(keyword) ||
|
|
||||||
item.jumlah?.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}, [data, search]);
|
|
||||||
|
|
||||||
// Handle loading state
|
// Handle loading state
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
|
|||||||
@@ -105,10 +105,12 @@ function ListDaftarInformasi({ search }: { search: string }) {
|
|||||||
<TableTbody>
|
<TableTbody>
|
||||||
{filteredData.map((item, index) => (
|
{filteredData.map((item, index) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd style={{ textAlign: 'center' }}>{index + 1}</TableTd>
|
<TableTd style={{ textAlign: 'center' }}>
|
||||||
|
<Text mt={10} fz={"md"}>{index + 1}</Text>
|
||||||
|
</TableTd>
|
||||||
<TableTd style={{ wordWrap: 'break-word' }}>
|
<TableTd style={{ wordWrap: 'break-word' }}>
|
||||||
<Box w={200}>
|
<Box w={200}>
|
||||||
<Text fz={"md"} truncate={"end"} lineClamp={1}>{item.jenisInformasi}</Text>
|
<Text mt={10} fz={"md"} truncate={"end"} lineClamp={1}>{item.jenisInformasi}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd style={{ wordWrap: 'break-word' }}>
|
<TableTd style={{ wordWrap: 'break-word' }}>
|
||||||
|
|||||||
@@ -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 { 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 { IconCheck, IconDeviceImacCog, IconSearch, IconX } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import HeaderSearch from '../../../_com/header';
|
import HeaderSearch from '../../../_com/header';
|
||||||
import JudulList from '../../../_com/judulList';
|
import JudulList from '../../../_com/judulList';
|
||||||
@@ -39,22 +39,10 @@ function ListPegawaiPPID({ search }: { search: string }) {
|
|||||||
} = stateOrganisasi.findMany;
|
} = stateOrganisasi.findMany;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
load(page, 10);
|
load(page, 10, search);
|
||||||
}, [page]);
|
}, [page, search]);
|
||||||
|
|
||||||
const filteredData = useMemo(() => {
|
const filteredData = data || []
|
||||||
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]);
|
|
||||||
|
|
||||||
// Handle loading state
|
// Handle loading state
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -33,9 +33,17 @@ function ListPosisiOrganisasiPPID({ search }: { search: string }) {
|
|||||||
const [modalHapus, setModalHapus] = useState(false)
|
const [modalHapus, setModalHapus] = useState(false)
|
||||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = stateOrganisasi.findMany;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
stateOrganisasi.findMany.load()
|
load(page, 10, search);
|
||||||
}, [])
|
}, [page, search]);
|
||||||
|
|
||||||
const handleHapus = async () => {
|
const handleHapus = async () => {
|
||||||
if (selectedId) {
|
if (selectedId) {
|
||||||
@@ -45,17 +53,9 @@ function ListPosisiOrganisasiPPID({ search }: { search: string }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredData = (stateOrganisasi.findMany.data || []).filter(item => {
|
const filteredData = data || []
|
||||||
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);
|
|
||||||
|
|
||||||
if (!stateOrganisasi.findMany.data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -120,6 +120,14 @@ function ListPosisiOrganisasiPPID({ search }: { search: string }) {
|
|||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my={"md"}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
{/* Modal Hapus */}
|
{/* Modal Hapus */}
|
||||||
<ModalKonfirmasiHapus
|
<ModalKonfirmasiHapus
|
||||||
opened={modalHapus}
|
opened={modalHapus}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const navBar = [
|
|||||||
{
|
{
|
||||||
id: "Landing_Page_3",
|
id: "Landing_Page_3",
|
||||||
name: "Indeks Kepuasan Masyarakat",
|
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",
|
id: "Landing_Page_4",
|
||||||
|
|||||||
@@ -96,28 +96,36 @@ export default async function detailDataPengangguranCreate(context: Context) {
|
|||||||
// Cari bulan sebelumnya
|
// Cari bulan sebelumnya
|
||||||
const currentMonthIndex = monthOrder.indexOf(body.month);
|
const currentMonthIndex = monthOrder.indexOf(body.month);
|
||||||
const prevMonth = currentMonthIndex > 0 ? monthOrder[currentMonthIndex - 1] : "Des";
|
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({
|
const prevData = await prisma.detailDataPengangguran.findFirst({
|
||||||
where: {
|
where: {
|
||||||
month: prevMonth,
|
month: prevMonth,
|
||||||
year: prevYear,
|
year: prevYearDate,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let percentageChange: number | null = null;
|
let percentageChange: number | null = null;
|
||||||
if (prevData) {
|
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));
|
percentageChange = parseFloat(change.toFixed(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the new record with properly typed values
|
||||||
const created = await prisma.detailDataPengangguran.create({
|
const created = await prisma.detailDataPengangguran.create({
|
||||||
data: {
|
data: {
|
||||||
month: body.month,
|
month: body.month,
|
||||||
year: body.year,
|
year: currentYearDate,
|
||||||
totalUnemployment: body.totalUnemployment,
|
totalUnemployment: Number(body.totalUnemployment),
|
||||||
educatedUnemployment: body.educatedUnemployment,
|
educatedUnemployment: Number(body.educatedUnemployment),
|
||||||
uneducatedUnemployment: body.uneducatedUnemployment,
|
uneducatedUnemployment: Number(body.uneducatedUnemployment),
|
||||||
percentageChange,
|
percentageChange,
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default async function findByMonthYear(context: Context) {
|
|||||||
const data = await prisma.detailDataPengangguran.findFirst({
|
const data = await prisma.detailDataPengangguran.findFirst({
|
||||||
where: {
|
where: {
|
||||||
month,
|
month,
|
||||||
year: Number(year),
|
year: new Date(Number(year), 0, 1), // Convert year number to Date object for Prisma
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -81,14 +81,19 @@ export default async function detailDataPengangguranUpdate(context: Context) {
|
|||||||
return { success: false, message: "ID tidak ditemukan" };
|
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;
|
month: string;
|
||||||
year: number;
|
year: number | string | Date;
|
||||||
totalUnemployment: number;
|
totalUnemployment: number | string;
|
||||||
educatedUnemployment: number;
|
educatedUnemployment: number | string;
|
||||||
uneducatedUnemployment: number;
|
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({
|
const duplicate = await prisma.detailDataPengangguran.findFirst({
|
||||||
where: {
|
where: {
|
||||||
month,
|
month,
|
||||||
@@ -109,18 +114,19 @@ export default async function detailDataPengangguranUpdate(context: Context) {
|
|||||||
|
|
||||||
const currentMonthIndex = monthOrder.indexOf(month);
|
const currentMonthIndex = monthOrder.indexOf(month);
|
||||||
const prevMonth = currentMonthIndex > 0 ? monthOrder[currentMonthIndex - 1] : "Des";
|
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({
|
const prevData = await prisma.detailDataPengangguran.findFirst({
|
||||||
where: {
|
where: {
|
||||||
month: prevMonth,
|
month: prevMonth,
|
||||||
year: prevYear,
|
year: new Date(prevYear, 0, 1),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let percentageChange: number | null = null;
|
let percentageChange: number | null = null;
|
||||||
if (prevData) {
|
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));
|
percentageChange = parseFloat(change.toFixed(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,10 +134,10 @@ export default async function detailDataPengangguranUpdate(context: Context) {
|
|||||||
where: { id },
|
where: { id },
|
||||||
data: {
|
data: {
|
||||||
month,
|
month,
|
||||||
year,
|
year: new Date(year), // Ensure it's a new Date instance
|
||||||
totalUnemployment,
|
totalUnemployment: Number(totalUnemployment),
|
||||||
educatedUnemployment,
|
educatedUnemployment: Number(educatedUnemployment),
|
||||||
uneducatedUnemployment,
|
uneducatedUnemployment: Number(uneducatedUnemployment),
|
||||||
percentageChange,
|
percentageChange,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,21 +1,55 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function lowonganKerjaFindMany() {
|
async function lowonganKerjaFindMany(context: Context) {
|
||||||
try {
|
// Ambil parameter dari query
|
||||||
const data = await prisma.lowonganPekerjaan.findMany({
|
const page = Number(context.query.page) || 1;
|
||||||
where: { isActive: true },
|
const limit = Number(context.query.limit) || 10;
|
||||||
});
|
const search = (context.query.search as string) || '';
|
||||||
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
return {
|
// Buat where clause
|
||||||
success: true,
|
const where: any = { isActive: true };
|
||||||
message: "Success fetch lowongan kerja",
|
|
||||||
data,
|
// Tambahkan pencarian (jika ada)
|
||||||
};
|
if (search) {
|
||||||
} catch (e) {
|
where.OR = [
|
||||||
console.error("Find many error:", e);
|
{ posisi: { contains: search, mode: 'insensitive' } },
|
||||||
return {
|
{ namaPerusahaan: { contains: search, mode: 'insensitive' } },
|
||||||
success: false,
|
{ lokasi: { contains: search, mode: 'insensitive' } },
|
||||||
message: "Failed fetch lowongan kerja",
|
];
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
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 prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function pasarDesaFindMany() {
|
async function pasarDesaFindMany(context: Context) {
|
||||||
const data = await prisma.pasarDesa.findMany({
|
// Ambil parameter dari query
|
||||||
where: {
|
const page = Number(context.query.page) || 1;
|
||||||
isActive: true, // Opsional filter
|
const limit = Number(context.query.limit) || 10;
|
||||||
},
|
const search = (context.query.search as string) || '';
|
||||||
orderBy: {
|
const categoryId = context.query.categoryId as string | undefined;
|
||||||
createdAt: "desc",
|
const skip = (page - 1) * limit;
|
||||||
},
|
|
||||||
include: {
|
// Buat where clause
|
||||||
image: true,
|
const where: any = { isActive: true };
|
||||||
KategoriToPasar: {
|
|
||||||
|
// 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: {
|
include: {
|
||||||
kategori: true,
|
image: true,
|
||||||
|
KategoriToPasar: {
|
||||||
|
include: {
|
||||||
|
kategori: true
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
skip,
|
||||||
},
|
take: limit,
|
||||||
});
|
orderBy: { createdAt: 'desc' },
|
||||||
|
}),
|
||||||
|
prisma.pasarDesa.count({ where }),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Berhasil mengambil semua data pasar desa",
|
message: "Berhasil ambil pasar desa dengan pagination",
|
||||||
data,
|
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 */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
]);
|
||||||
|
|
||||||
export default async function kategoriProdukFindMany() {
|
|
||||||
const data = await prisma.kategoriProduk.findMany();
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: data.map((item: any) => {
|
message: "Berhasil ambil kategori produk dengan pagination",
|
||||||
return {
|
data,
|
||||||
id: item.id,
|
page,
|
||||||
nama: item.nama,
|
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 prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function programKemiskinanFindMany() {
|
export default async function programKemiskinanFindMany(context: Context) {
|
||||||
const data = await prisma.programKemiskinan.findMany({
|
const page = Number(context.query.page) || 1;
|
||||||
include: {
|
const limit = Number(context.query.limit) || 10;
|
||||||
statistik: true, // ikut sertakan relasinya
|
const search = (context.query.search as string) || '';
|
||||||
},
|
const skip = (page - 1) * limit;
|
||||||
orderBy: {
|
|
||||||
createdAt: "desc",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
// Buat where clause
|
||||||
success: true,
|
const where: any = { isActive: true };
|
||||||
message: "Success get all program layanan",
|
|
||||||
data,
|
// 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 prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function menuTipsKeamananFindMany() {
|
async function tipsKeamananFindMany(context: Context) {
|
||||||
try {
|
// Ambil parameter dari query
|
||||||
const data = await prisma.menuTipsKeamanan.findMany({
|
const page = Number(context.query.page) || 1;
|
||||||
where: { isActive: true },
|
const limit = Number(context.query.limit) || 10;
|
||||||
include: {
|
const search = (context.query.search as string) || '';
|
||||||
image: true,
|
const skip = (page - 1) * limit;
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
// Buat where clause
|
||||||
success: true,
|
const where: any = { isActive: true };
|
||||||
message: "Success fetch menu tips keamanan",
|
|
||||||
data,
|
// Tambahkan pencarian (jika ada)
|
||||||
};
|
if (search) {
|
||||||
} catch (e) {
|
where.OR = [
|
||||||
console.error("Find many error:", e);
|
{ judul: { contains: search, mode: 'insensitive' } },
|
||||||
return {
|
{ deskripsi: { contains: search, mode: 'insensitive' } },
|
||||||
success: false,
|
];
|
||||||
message: "Failed fetch menu tips keamanan",
|
}
|
||||||
};
|
|
||||||
}
|
try {
|
||||||
|
// Ambil data dan total count secara paralel
|
||||||
|
const [data, total] = await Promise.all([
|
||||||
|
prisma.menuTipsKeamanan.findMany({
|
||||||
|
where,
|
||||||
|
include: {
|
||||||
|
image: true,
|
||||||
|
},
|
||||||
|
skip,
|
||||||
|
take: limit,
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
}),
|
||||||
|
prisma.menuTipsKeamanan.count({ where }),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Berhasil ambil menu tips keamanan 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 tips keamanan",
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default tipsKeamananFindMany;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
// /api/berita/findManyPaginated.ts
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
@@ -5,12 +6,23 @@ import { Context } from "elysia";
|
|||||||
async function apbdesFindMany(context: Context) {
|
async function apbdesFindMany(context: Context) {
|
||||||
const page = Number(context.query.page) || 1;
|
const page = Number(context.query.page) || 1;
|
||||||
const limit = Number(context.query.limit) || 10;
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || '';
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Buat where clause
|
||||||
|
const where: any = { isActive: true };
|
||||||
|
|
||||||
|
// Tambahkan pencarian (jika ada)
|
||||||
|
if (search) {
|
||||||
|
where.OR = [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.aPBDes.findMany({
|
prisma.aPBDes.findMany({
|
||||||
where: { isActive: true },
|
where,
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
file: true,
|
file: true,
|
||||||
@@ -20,7 +32,7 @@ async function apbdesFindMany(context: Context) {
|
|||||||
orderBy: { name: "asc" }, // opsional, kalau mau urut berdasarkan waktu
|
orderBy: { name: "asc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||||
}),
|
}),
|
||||||
prisma.aPBDes.count({
|
prisma.aPBDes.count({
|
||||||
where: { isActive: true },
|
where,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const APBDes = new Elysia({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// ✅ Find all
|
// ✅ Find all
|
||||||
.get("/find-many", apbdesFindMany)
|
.get("/findMany", apbdesFindMany)
|
||||||
|
|
||||||
// ✅ Find by ID
|
// ✅ Find by ID
|
||||||
.get("/:id", apbdesFindUnique)
|
.get("/:id", apbdesFindUnique)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
// /api/berita/findManyPaginated.ts
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
@@ -5,23 +6,35 @@ import { Context } from "elysia";
|
|||||||
async function desaAntiKorupsiFindMany(context: Context) {
|
async function desaAntiKorupsiFindMany(context: Context) {
|
||||||
const page = Number(context.query.page) || 1;
|
const page = Number(context.query.page) || 1;
|
||||||
const limit = Number(context.query.limit) || 10;
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || "";
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// 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" } },
|
||||||
|
{ kategori: { name: { contains: search, mode: "insensitive" } } },
|
||||||
|
];
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.desaAntiKorupsi.findMany({
|
prisma.desaAntiKorupsi.findMany({
|
||||||
where: { isActive: true },
|
where,
|
||||||
include: {
|
include: {
|
||||||
kategori: true,
|
kategori: true,
|
||||||
file: true,
|
file: true,
|
||||||
},
|
},
|
||||||
skip,
|
skip,
|
||||||
take: limit,
|
take: limit,
|
||||||
orderBy: { name: 'asc' }, // opsional, kalau mau urut berdasarkan waktu
|
orderBy: { name: "asc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||||
}),
|
}),
|
||||||
prisma.desaAntiKorupsi.count({
|
prisma.desaAntiKorupsi.count({
|
||||||
where: { isActive: true }
|
where,
|
||||||
})
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
// /api/berita/findManyPaginated.ts
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
@@ -5,18 +6,29 @@ import { Context } from "elysia";
|
|||||||
async function kategoriDesaAntiKorupsiFindMany(context: Context) {
|
async function kategoriDesaAntiKorupsiFindMany(context: Context) {
|
||||||
const page = Number(context.query.page) || 1;
|
const page = Number(context.query.page) || 1;
|
||||||
const limit = Number(context.query.limit) || 10;
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || '';
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Buat where clause
|
||||||
|
const where: any = { isActive: true };
|
||||||
|
|
||||||
|
// Tambahkan pencarian (jika ada)
|
||||||
|
if (search) {
|
||||||
|
where.OR = [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.kategoriDesaAntiKorupsi.findMany({
|
prisma.kategoriDesaAntiKorupsi.findMany({
|
||||||
where: { isActive: true },
|
where,
|
||||||
skip,
|
skip,
|
||||||
take: limit,
|
take: limit,
|
||||||
orderBy: { name: 'asc' }, // opsional, kalau mau urut berdasarkan waktu
|
orderBy: { name: 'asc' }, // opsional, kalau mau urut berdasarkan waktu
|
||||||
}),
|
}),
|
||||||
prisma.kategoriDesaAntiKorupsi.count({
|
prisma.kategoriDesaAntiKorupsi.count({
|
||||||
where: { isActive: true }
|
where,
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
// /api/berita/findManyPaginated.ts
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
@@ -5,22 +6,45 @@ import { Context } from "elysia";
|
|||||||
async function prestasiDesaFindMany(context: Context) {
|
async function prestasiDesaFindMany(context: Context) {
|
||||||
const page = Number(context.query.page) || 1;
|
const page = Number(context.query.page) || 1;
|
||||||
const limit = Number(context.query.limit) || 10;
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || '';
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Buat where clause
|
||||||
|
const where: any = {};
|
||||||
|
|
||||||
|
// Tambahkan pencarian (jika ada)
|
||||||
|
if (search) {
|
||||||
|
where.OR = [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
{ deskripsi: { contains: search, mode: 'insensitive' } },
|
||||||
|
{ kategori: { name: { contains: search, mode: 'insensitive' } } },
|
||||||
|
];
|
||||||
|
// Tetap filter hanya yang aktif saat melakukan pencarian
|
||||||
|
where.isActive = true;
|
||||||
|
} else {
|
||||||
|
// Jika tidak ada pencarian, tampilkan hanya data yang aktif
|
||||||
|
where.isActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.prestasiDesa.findMany({
|
prisma.prestasiDesa.findMany({
|
||||||
where: { isActive: true },
|
where,
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
kategori: true,
|
kategori: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
skip,
|
skip,
|
||||||
take: limit,
|
take: limit,
|
||||||
orderBy: { createdAt: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
orderBy: { createdAt: "desc" },
|
||||||
}),
|
}),
|
||||||
prisma.prestasiDesa.count({
|
prisma.prestasiDesa.count({
|
||||||
where: { isActive: true },
|
where,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,52 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
|
async function kategoriPrestasiFindMany(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 = [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [data, total] = await Promise.all([
|
||||||
|
prisma.kategoriPrestasiDesa.findMany({
|
||||||
|
where,
|
||||||
|
skip,
|
||||||
|
take: limit,
|
||||||
|
orderBy: { createdAt: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||||
|
}),
|
||||||
|
prisma.kategoriPrestasiDesa.count({
|
||||||
|
where,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
export default async function kategoriPrestasiFindMany() {
|
|
||||||
const data = await prisma.kategoriPrestasiDesa.findMany();
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: data.map((item: any) => {
|
message: "Success fetch Kategori Prestasi Desa with pagination",
|
||||||
return {
|
data,
|
||||||
id: item.id,
|
page,
|
||||||
name: item.name,
|
totalPages: Math.ceil(total / limit),
|
||||||
}
|
total,
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Find many paginated error:", e);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Failed fetch Kategori Prestasi Desa with pagination",
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default kategoriPrestasiFindMany;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
// /api/berita/findManyPaginated.ts
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
@@ -5,12 +6,23 @@ import { Context } from "elysia";
|
|||||||
async function mediaSosialFindMany(context: Context) {
|
async function mediaSosialFindMany(context: Context) {
|
||||||
const page = Number(context.query.page) || 1;
|
const page = Number(context.query.page) || 1;
|
||||||
const limit = Number(context.query.limit) || 10;
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || '';
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Buat where clause
|
||||||
|
const where: any = { isActive: true };
|
||||||
|
|
||||||
|
// Tambahkan pencarian (jika ada)
|
||||||
|
if (search) {
|
||||||
|
where.OR = [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.mediaSosial.findMany({
|
prisma.mediaSosial.findMany({
|
||||||
where: { isActive: true },
|
where,
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
// // /api/berita/findManyPaginated.ts
|
// // /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
@@ -5,12 +6,23 @@ import { Context } from "elysia";
|
|||||||
async function programInovasiFindMany(context: Context) {
|
async function programInovasiFindMany(context: Context) {
|
||||||
const page = Number(context.query.page) || 1;
|
const page = Number(context.query.page) || 1;
|
||||||
const limit = Number(context.query.limit) || 10;
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || '';
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
const where: any = { isActive: true };
|
||||||
|
|
||||||
|
// Tambahkan pencarian (jika ada)
|
||||||
|
if (search) {
|
||||||
|
where.OR = [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
{ description: { contains: search, mode: 'insensitive' } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.programInovasi.findMany({
|
prisma.programInovasi.findMany({
|
||||||
where: { isActive: true },
|
where,
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
// /api/berita/findManyPaginated.ts
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
@@ -5,12 +6,23 @@ import { Context } from "elysia";
|
|||||||
async function sdgsDesaFindMany(context: Context) {
|
async function sdgsDesaFindMany(context: Context) {
|
||||||
const page = Number(context.query.page) || 1;
|
const page = Number(context.query.page) || 1;
|
||||||
const limit = Number(context.query.limit) || 10;
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || '';
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Buat where clause
|
||||||
|
const where: any = { isActive: true };
|
||||||
|
|
||||||
|
// Tambahkan pencarian (jika ada)
|
||||||
|
if (search) {
|
||||||
|
where.OR = [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.sDGSDesa.findMany({
|
prisma.sDGSDesa.findMany({
|
||||||
where: { isActive: true },
|
where,
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
},
|
},
|
||||||
@@ -19,7 +31,7 @@ async function sdgsDesaFindMany(context: Context) {
|
|||||||
orderBy: { jumlah: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
orderBy: { jumlah: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||||
}),
|
}),
|
||||||
prisma.sDGSDesa.count({
|
prisma.sDGSDesa.count({
|
||||||
where: { isActive: true },
|
where,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
|
|
||||||
@@ -5,12 +6,24 @@ import { Context } from "elysia";
|
|||||||
export default async function pegawaiFindMany(context: Context) {
|
export default async function pegawaiFindMany(context: Context) {
|
||||||
const page = Number(context.query.page) || 1;
|
const page = Number(context.query.page) || 1;
|
||||||
const limit = Number(context.query.limit) || 10;
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || '';
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Buat where clause
|
||||||
|
const where: any = { isActive: true };
|
||||||
|
|
||||||
|
// Tambahkan pencarian (jika ada)
|
||||||
|
if (search) {
|
||||||
|
where.OR = [
|
||||||
|
{ namaLengkap: { contains: search, mode: 'insensitive' } },
|
||||||
|
{ alamat: { contains: search, mode: 'insensitive' } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.pegawaiPPID.findMany({
|
prisma.pegawaiPPID.findMany({
|
||||||
where: { isActive: true },
|
where,
|
||||||
include: {
|
include: {
|
||||||
posisi: true,
|
posisi: true,
|
||||||
image: true,
|
image: true,
|
||||||
@@ -20,7 +33,7 @@ export default async function pegawaiFindMany(context: Context) {
|
|||||||
orderBy: { posisi: { hierarki: 'asc' } },
|
orderBy: { posisi: { hierarki: 'asc' } },
|
||||||
}),
|
}),
|
||||||
prisma.pegawaiPPID.count({
|
prisma.pegawaiPPID.count({
|
||||||
where: { isActive: true }
|
where,
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,58 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
// /api/posisi-organisasi/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function posisiOrganisasiFindMany() {
|
async function posisiOrganisasiFindMany(context: Context) {
|
||||||
const data = await prisma.posisiOrganisasiPPID.findMany();
|
const page = Number(context.query.page) || 1;
|
||||||
|
const limit = Number(context.query.limit) || 10;
|
||||||
|
const search = (context.query.search as string) || "";
|
||||||
|
|
||||||
|
const where: any = { isActive: true };
|
||||||
|
|
||||||
|
if (search) {
|
||||||
|
where.OR = [
|
||||||
|
{ nama: { contains: search, mode: "insensitive" } },
|
||||||
|
{ deskripsi: { contains: search, mode: "insensitive" } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const whereClause = {
|
||||||
|
...where,
|
||||||
|
isActive: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const [data, total] = await Promise.all([
|
||||||
|
prisma.posisiOrganisasiPPID.findMany({
|
||||||
|
where: whereClause,
|
||||||
|
skip: (page - 1) * limit,
|
||||||
|
take: limit,
|
||||||
|
orderBy: { hierarki: "asc" },
|
||||||
|
}),
|
||||||
|
prisma.posisiOrganisasiPPID.count({ where: whereClause }),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Berhasil mengambil semua data posisi organisasi",
|
message: "Berhasil mengambil data posisi organisasi dengan pagination",
|
||||||
data: data.map((item: any) => ({
|
data: data.map((item: any) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
nama: item.nama,
|
nama: item.nama,
|
||||||
deskripsi: item.deskripsi,
|
deskripsi: item.deskripsi,
|
||||||
hierarki: item.hierarki,
|
hierarki: item.hierarki,
|
||||||
})),
|
})),
|
||||||
|
page,
|
||||||
|
totalPages: Math.ceil(total / limit),
|
||||||
|
total,
|
||||||
};
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Find many paginated error:", e);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Gagal mengambil data posisi organisasi",
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default posisiOrganisasiFindMany;
|
||||||
|
|||||||
@@ -1,21 +1,157 @@
|
|||||||
|
'use client'
|
||||||
|
import PendapatanAsliDesa from '@/app/admin/(dashboard)/_state/ekonomi/PADesa';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Stack, Box, Text, Image, Paper } from '@mantine/core';
|
import { Box, Grid, GridCol, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
||||||
import React from 'react';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const state = useProxy(PendapatanAsliDesa.ApbDesa);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
state.findMany.load();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
PendapatanAsliDesa.pembiayaan.findMany.load();
|
||||||
|
PendapatanAsliDesa.belanja.findMany.load();
|
||||||
|
PendapatanAsliDesa.pendapatan.findMany.load();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Get the latest APB data
|
||||||
|
const latestApb = state.findMany.data?.[0];
|
||||||
|
|
||||||
|
// Calculate totals
|
||||||
|
const totalPendapatan = latestApb?.pendapatan?.reduce((sum, item) => sum + (item?.value || 0), 0) || 0;
|
||||||
|
const totalBelanja = latestApb?.belanja?.reduce((sum, item) => sum + (item?.value || 0), 0) || 0;
|
||||||
|
const totalPembiayaan = latestApb?.pembiayaan?.reduce((sum, item) => sum + (item?.value || 0), 0) || 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="lg">
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Text ta="center" fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw="bold">
|
||||||
Pendapatan Asli Desa
|
Pendapatan Asli Desa
|
||||||
</Text>
|
</Text>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap={'lg'} justify='center'>
|
<Stack gap="lg" justify="center">
|
||||||
<Paper bg={colors['white-1']} p={"xl"}>
|
<Paper bg={colors['white-1']} p="xl">
|
||||||
<Image src="/pa-desa.png" alt=''/>
|
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="md">
|
||||||
|
{/* Pendapatan Card */}
|
||||||
|
<Box p="md" style={{ border: '1px solid #e9ecef', borderRadius: '8px' }}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Title order={3}>Pendapatan</Title>
|
||||||
|
{PendapatanAsliDesa.pendapatan.findMany.data?.map((item) => (
|
||||||
|
<Box key={item.id}>
|
||||||
|
<Grid>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="md" fw={500}>{item.name}</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="md" fw={500}>{new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(item.value)}</Text>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
<Grid>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="lg" fw={600} mb="xs">Total Pendapatan</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="xl" fw={700} c={colors['blue-button']}>
|
||||||
|
{new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(totalPendapatan)}
|
||||||
|
</Text>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Belanja Card */}
|
||||||
|
<Box p="md" style={{ border: '1px solid #e9ecef', borderRadius: '8px' }}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Title order={3}>Belanja</Title>
|
||||||
|
{PendapatanAsliDesa.belanja.findMany.data?.map((item) => (
|
||||||
|
<Box key={item.id}>
|
||||||
|
<Grid>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="md" fw={500}>{item.name}</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="md" fw={500}>{new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(item.value)}</Text>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
<Grid>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="lg" fw={600} mb="xs">Total Belanja</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="xl" fw={700} c="orange">
|
||||||
|
{new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(totalBelanja)}
|
||||||
|
</Text>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Pembiayaan Card */}
|
||||||
|
<Box p="md" style={{ border: '1px solid #e9ecef', borderRadius: '8px' }}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Title order={3}>Pembiayaan</Title>
|
||||||
|
{PendapatanAsliDesa.pembiayaan.findMany.data?.map((item) => (
|
||||||
|
<Box key={item.id}>
|
||||||
|
<Grid>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="md" fw={500}>{item.name}</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="md" fw={500}>{new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(item.value)}</Text>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
<Grid>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="lg" fw={600} mb="xs">Total Pembiayaan</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
|
<Text fz="xl" fw={700} c="green">
|
||||||
|
{new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(totalPembiayaan)}
|
||||||
|
</Text>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
</SimpleGrid>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,192 +1,32 @@
|
|||||||
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Stack, Box, Paper, Text, ColorSwatch, Flex } from '@mantine/core';
|
import { Stack, Box, Paper, Text, ColorSwatch, Flex, Skeleton } from '@mantine/core';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
import { BarChart } from '@mantine/charts';
|
import { BarChart } from '@mantine/charts';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import grafikDemografiPekerjaan from '@/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
Pekerjaan: 'Guru',
|
|
||||||
laki: 2,
|
|
||||||
perempuan: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
Pekerjaan: 'Belajar/Mahasiswa',
|
|
||||||
laki: 37,
|
|
||||||
perempuan: 38
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
Pekerjaan: 'Karyawan Bumdn',
|
|
||||||
laki: 1,
|
|
||||||
perempuan: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
Pekerjaan: 'Buruh Tani/Perkebunan',
|
|
||||||
laki: 1,
|
|
||||||
perempuan: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
Pekerjaan: 'Karyawan Swasta',
|
|
||||||
laki: 3,
|
|
||||||
perempuan: 17
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
Pekerjaan: 'Karyawan Honorer',
|
|
||||||
laki: 2,
|
|
||||||
perempuan: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
Pekerjaan: 'Buruh Harian Lepas',
|
|
||||||
laki: 8,
|
|
||||||
perempuan: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
Pekerjaan: 'Belum/Tidak Bekerja',
|
|
||||||
laki: 87,
|
|
||||||
perempuan: 44
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
Pekerjaan: ' Kepolisian RI (Polri)',
|
|
||||||
laki: 4,
|
|
||||||
perempuan: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
Pekerjaan: 'Wiraswasta Mengurus Rumah Tangga',
|
|
||||||
laki: 1,
|
|
||||||
perempuan: 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
Pekerjaan: 'Dosen',
|
|
||||||
laki: 1,
|
|
||||||
perempuan: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
Pekerjaan: 'Perangkat Desa',
|
|
||||||
laki: 17,
|
|
||||||
perempuan: 19
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 13,
|
|
||||||
Pekerjaan: 'Nelayan',
|
|
||||||
laki: 3,
|
|
||||||
perempuan: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 14,
|
|
||||||
Pekerjaan: 'Penyuluh Pertanian',
|
|
||||||
laki: 33,
|
|
||||||
perempuan: 24
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 15,
|
|
||||||
Pekerjaan: 'Tukang Las/Pandai Besi',
|
|
||||||
laki: 5,
|
|
||||||
perempuan: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 16,
|
|
||||||
Pekerjaan: 'Sopir/Driver',
|
|
||||||
laki: 10,
|
|
||||||
perempuan: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 17,
|
|
||||||
Pekerjaan: 'Teknisi/Listrik',
|
|
||||||
laki: 25,
|
|
||||||
perempuan: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 18,
|
|
||||||
Pekerjaan: 'Montir/Mekanik',
|
|
||||||
laki: 25,
|
|
||||||
perempuan: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 19,
|
|
||||||
Pekerjaan: 'Karyawan Hotel/Pariwisata',
|
|
||||||
laki: 2,
|
|
||||||
perempuan: 52
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 20,
|
|
||||||
Pekerjaan: 'Pengrajin (Batik, Anyaman, Kayu)',
|
|
||||||
laki: 5,
|
|
||||||
perempuan: 25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 21,
|
|
||||||
Pekerjaan: 'Tukang Bangunan',
|
|
||||||
laki: 25,
|
|
||||||
perempuan: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 22,
|
|
||||||
Pekerjaan: 'Tukang Kayu/Furnitur',
|
|
||||||
laki: 25,
|
|
||||||
perempuan: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 23,
|
|
||||||
Pekerjaan: 'Penjahit',
|
|
||||||
laki: 2,
|
|
||||||
perempuan: 35
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 24,
|
|
||||||
Pekerjaan: 'Pedagang Pasar',
|
|
||||||
laki: 25,
|
|
||||||
perempuan: 30
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 25,
|
|
||||||
Pekerjaan: 'Warung Makan/Penjual Makanan',
|
|
||||||
laki: 15,
|
|
||||||
perempuan: 30
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 26,
|
|
||||||
Pekerjaan: 'Satpam/Security',
|
|
||||||
laki: 20,
|
|
||||||
perempuan: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 27,
|
|
||||||
Pekerjaan: 'Pengusaha Kecil (UMKM)',
|
|
||||||
laki: 5,
|
|
||||||
perempuan: 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 28,
|
|
||||||
Pekerjaan: 'Karyawan Restoran/Kafe',
|
|
||||||
laki: 5,
|
|
||||||
perempuan: 15
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 29,
|
|
||||||
Pekerjaan: 'Freelancer',
|
|
||||||
laki: 20,
|
|
||||||
perempuan: 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 30,
|
|
||||||
Pekerjaan: 'Fotografer',
|
|
||||||
laki: 25,
|
|
||||||
perempuan: 9
|
|
||||||
},
|
|
||||||
]
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const state = useProxy(grafikDemografiPekerjaan)
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
} = state.findMany
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
state.findMany.load()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
@@ -207,7 +47,13 @@ function Page() {
|
|||||||
p={10}
|
p={10}
|
||||||
mb={50}
|
mb={50}
|
||||||
h={400}
|
h={400}
|
||||||
data={data}
|
w={150}
|
||||||
|
data={data.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
Pekerjaan: item.pekerjaan,
|
||||||
|
laki: item.lakiLaki,
|
||||||
|
perempuan: item.perempuan,
|
||||||
|
}))}
|
||||||
dataKey="Pekerjaan"
|
dataKey="Pekerjaan"
|
||||||
series={[
|
series={[
|
||||||
{ name: 'laki', color: '#5082EE' },
|
{ name: 'laki', color: '#5082EE' },
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, CheckIcon, Combobox, ComboboxChevron, ComboboxOption, ComboboxOptions, ComboboxTarget, Group, InputBase, InputPlaceholder, Paper, SimpleGrid, Stack, Text, useCombobox } from '@mantine/core';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
|
||||||
import { BarChart } from '@mantine/charts';
|
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
tahun: '2024',
|
|
||||||
Penduduk: 400000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
tahun: '2025',
|
|
||||||
Penduduk: 450000
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
|
||||||
const tahun = [
|
|
||||||
'2024',
|
|
||||||
'2025'
|
|
||||||
];
|
|
||||||
function Page() {
|
|
||||||
const combobox = useCombobox({
|
|
||||||
onDropdownClose: () => combobox.resetSelectedOption(),
|
|
||||||
onDropdownOpen: (eventSource) => {
|
|
||||||
if (eventSource === 'keyboard') {
|
|
||||||
combobox.selectActiveOption();
|
|
||||||
} else {
|
|
||||||
combobox.updateSelectedOptionIndex('active');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const [value, setValue] = useState<string | null>('2024');
|
|
||||||
|
|
||||||
const options = tahun.map((item) => (
|
|
||||||
<ComboboxOption value={item} key={item} active={item === value}>
|
|
||||||
<Group gap="xs">
|
|
||||||
{item === value && <CheckIcon size={12} />}
|
|
||||||
<span>{item}</span>
|
|
||||||
</Group>
|
|
||||||
</ComboboxOption>
|
|
||||||
));
|
|
||||||
return (
|
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
|
||||||
<BackButton />
|
|
||||||
</Box>
|
|
||||||
<Box px={{ base: 'md', md: 100 }} >
|
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
|
||||||
Jumlah Penduduk Miskin Tahun 2024-2025
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
|
||||||
<Stack gap={'lg'} justify='center'>
|
|
||||||
<SimpleGrid
|
|
||||||
pb={20}
|
|
||||||
cols={{
|
|
||||||
base: 1,
|
|
||||||
md: 2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paper p={'xl'}>
|
|
||||||
<Text fz={'h3'}>Tahun: 2024</Text>
|
|
||||||
<Text fw={"bold"} fz={'h1'}>4,800,000 Orang</Text>
|
|
||||||
</Paper>
|
|
||||||
<Paper p={'xl'}>
|
|
||||||
<Text>Pilih Tahun</Text>
|
|
||||||
<Combobox
|
|
||||||
store={combobox}
|
|
||||||
resetSelectionOnOptionHover
|
|
||||||
withinPortal={false}
|
|
||||||
onOptionSubmit={(val) => {
|
|
||||||
setValue(val);
|
|
||||||
combobox.updateSelectedOptionIndex('active');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ComboboxTarget targetType="button">
|
|
||||||
<InputBase
|
|
||||||
component="button"
|
|
||||||
type="button"
|
|
||||||
pointer
|
|
||||||
rightSection={<ComboboxChevron />}
|
|
||||||
rightSectionPointerEvents="none"
|
|
||||||
onClick={() => combobox.toggleDropdown()}
|
|
||||||
>
|
|
||||||
{value || <InputPlaceholder>Pick value</InputPlaceholder>}
|
|
||||||
</InputBase>
|
|
||||||
</ComboboxTarget>
|
|
||||||
|
|
||||||
<Combobox.Dropdown>
|
|
||||||
<ComboboxOptions>{options}</ComboboxOptions>
|
|
||||||
</Combobox.Dropdown>
|
|
||||||
</Combobox>
|
|
||||||
</Paper>
|
|
||||||
</SimpleGrid>
|
|
||||||
<Paper p={'xl'}>
|
|
||||||
<Text pb={10} fw={'bold'} fz={'h4'}>Jumlah Penduduk Miskin Per Tahun</Text>
|
|
||||||
<BarChart
|
|
||||||
p={10}
|
|
||||||
h={300}
|
|
||||||
data={data}
|
|
||||||
dataKey="tahun"
|
|
||||||
series={[
|
|
||||||
{ name: 'Penduduk', color: '#8785D3' },
|
|
||||||
]}
|
|
||||||
tickLine="y"
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Page;
|
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
'use client'
|
||||||
|
import jumlahPendudukMiskin from '@/app/admin/(dashboard)/_state/ekonomi/jumlah-penduduk-miskin';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { BarChart } from '@mantine/charts';
|
||||||
|
import { Box, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
|
function Page() {
|
||||||
|
type JPMGrafik = {
|
||||||
|
id: string;
|
||||||
|
year: number;
|
||||||
|
totalPoorPopulation: number;
|
||||||
|
}
|
||||||
|
const state = useProxy(jumlahPendudukMiskin)
|
||||||
|
const [chartData, setChartData] = useState<JPMGrafik[]>([])
|
||||||
|
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
state.findMany.load()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (state.findMany.data) {
|
||||||
|
setChartData(state.findMany.data.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
year: Number(item.year),
|
||||||
|
totalPoorPopulation: Number(item.totalPoorPopulation),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
}, [state.findMany.data]);
|
||||||
|
|
||||||
|
if (!state.findMany.data) {
|
||||||
|
return (
|
||||||
|
<Stack>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
|
<BackButton />
|
||||||
|
</Box>
|
||||||
|
<Box px={{ base: 'md', md: 100 }} >
|
||||||
|
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
|
Jumlah Penduduk Miskin
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
|
<Stack gap={'lg'} justify='center'>
|
||||||
|
<Paper p={'xl'}>
|
||||||
|
<Text fz={'h3'}>Jumlah Data Penduduk Miskin</Text>
|
||||||
|
<Text fw={"bold"} fz={'h1'}>
|
||||||
|
{state.findMany.data?.reduce((sum, item) => sum + (Number(item.totalPoorPopulation) || 0), 0).toLocaleString()} Orang
|
||||||
|
</Text>
|
||||||
|
</Paper>
|
||||||
|
<Paper p={'xl'}>
|
||||||
|
<Text pb={10} fw={'bold'} fz={'h4'}>Jumlah Penduduk Miskin Per Tahun</Text>
|
||||||
|
<BarChart
|
||||||
|
h={300}
|
||||||
|
data={chartData}
|
||||||
|
dataKey="year"
|
||||||
|
series={[
|
||||||
|
{ name: 'totalPoorPopulation', color: 'blue.6', label: 'Jumlah Penduduk Miskin' },
|
||||||
|
]}
|
||||||
|
xAxisLabel="Tahun"
|
||||||
|
yAxisLabel="Jumlah Penduduk"
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -1,62 +1,76 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
'use client'
|
||||||
|
import grafikNganggur from '@/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Stack, Box, Text, Center, Paper, ColorSwatch, Flex } from '@mantine/core';
|
|
||||||
import React from 'react';
|
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
|
||||||
import { PieChart } from '@mantine/charts';
|
import { PieChart } from '@mantine/charts';
|
||||||
|
import { Box, Center, ColorSwatch, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
const datausiaKerja = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: '18 - 25',
|
|
||||||
value: 45,
|
|
||||||
color: 'indigo.6'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: '26 - 35',
|
|
||||||
value: 35,
|
|
||||||
color: 'teal.6'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: '36 - 45',
|
|
||||||
value: 15,
|
|
||||||
color: 'yellow.6'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: '46+',
|
|
||||||
value: 5,
|
|
||||||
color: 'red.6'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const datakerjaPendidikan = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'SD',
|
|
||||||
value: 10,
|
|
||||||
color: 'indigo.6'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'SMP',
|
|
||||||
value: 20,
|
|
||||||
color: 'teal.6'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: 'SMA/SMK',
|
|
||||||
value: 45,
|
|
||||||
color: 'yellow.6'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: 'D3/S1',
|
|
||||||
value: 25,
|
|
||||||
color: 'red.6'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const stateGrafikNganggur = useProxy(grafikNganggur.grafikBerdasarkanUsiaKerjaNganggur)
|
||||||
|
const stateGrafikNganggurPendidikan = useProxy(grafikNganggur.grafikBerdasarkanPendidikan)
|
||||||
|
const [donutGrafikNganggurData, setDonutGrafikNganggurData] = useState<any[]>([])
|
||||||
|
const [donutGrafikNganggurDataPendidikan, setDonutGrafikNganggurDataPendidikan] = useState<any[]>([])
|
||||||
|
const [mounted, setMounted] = useState(false)
|
||||||
|
const [mounted2, setMounted2] = useState(false)
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
setMounted(true)
|
||||||
|
setMounted2(true)
|
||||||
|
stateGrafikNganggur.findMany.load()
|
||||||
|
stateGrafikNganggurPendidikan.findMany.load()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (stateGrafikNganggur.findMany.data) {
|
||||||
|
const totalUsia18_25 = stateGrafikNganggur.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.usia18_25 || 0), 0);
|
||||||
|
const totalUsia26_35 = stateGrafikNganggur.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.usia26_35 || 0), 0);
|
||||||
|
const totalUsia36_45 = stateGrafikNganggur.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.usia36_45 || 0), 0);
|
||||||
|
const totalUsia46_keatas = stateGrafikNganggur.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.usia46_keatas || 0), 0);
|
||||||
|
setDonutGrafikNganggurData([
|
||||||
|
{ name: 'usia 18 - 25', value: totalUsia18_25, color: '#4b6Ef5', key: 'usia18_25' },
|
||||||
|
{ name: 'usia 26 - 35', value: totalUsia26_35, color: '#14b885', key: 'usia26_35' },
|
||||||
|
{ name: 'usia 36 - 45', value: totalUsia36_45, color: '#E6A03B', key: 'usia36_45' },
|
||||||
|
{ name: 'usia 46 +', value: totalUsia46_keatas, color: '#DB524D', key: 'usia46_keatas' },
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}, [stateGrafikNganggur.findMany.data])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (stateGrafikNganggurPendidikan.findMany.data) {
|
||||||
|
const SD = stateGrafikNganggurPendidikan.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.SD || 0), 0);
|
||||||
|
const SMP = stateGrafikNganggurPendidikan.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.SMP || 0), 0);
|
||||||
|
const SMA = stateGrafikNganggurPendidikan.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.SMA || 0), 0);
|
||||||
|
const D3 = stateGrafikNganggurPendidikan.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.D3 || 0), 0);
|
||||||
|
const S1 = stateGrafikNganggurPendidikan.findMany.data.reduce((acc: number, cur: any) => acc + Number(cur.S1 || 0), 0);
|
||||||
|
setDonutGrafikNganggurDataPendidikan([
|
||||||
|
{ 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' },
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}, [stateGrafikNganggurPendidikan.findMany.data])
|
||||||
|
|
||||||
|
if (!stateGrafikNganggur.findMany.data) {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stateGrafikNganggur.findMany.data) {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
@@ -71,9 +85,18 @@ function Page() {
|
|||||||
<Stack gap={'lg'} justify='center'>
|
<Stack gap={'lg'} justify='center'>
|
||||||
<Paper p={'lg'}>
|
<Paper p={'lg'}>
|
||||||
<Text fw={'bold'} fz={'h3'}>Pengangguran Berdasarkan Usia</Text>
|
<Text fw={'bold'} fz={'h3'}>Pengangguran Berdasarkan Usia</Text>
|
||||||
<Center>
|
{mounted && donutGrafikNganggurData.length > 0 ? (<Box style={{ width: '100%', height: 'auto', minHeight: 200 }}>
|
||||||
<PieChart size={300} withLabelsLine labelsPosition="outside" labelsType="percent" withLabels data={datausiaKerja} withTooltip tooltipDataSource="segment" mx="auto" />
|
<PieChart
|
||||||
</Center>
|
size={300}
|
||||||
|
withLabelsLine
|
||||||
|
labelsPosition="outside"
|
||||||
|
labelsType="percent"
|
||||||
|
withLabels
|
||||||
|
data={donutGrafikNganggurData}
|
||||||
|
withTooltip
|
||||||
|
tooltipDataSource="segment"
|
||||||
|
mx="auto" />
|
||||||
|
</Box>) : <Skeleton h={500} />}
|
||||||
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'}>
|
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'}>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={{ base: 5, md: 8 }} align={'center'}>
|
<Flex gap={{ base: 5, md: 8 }} align={'center'}>
|
||||||
@@ -103,9 +126,18 @@ function Page() {
|
|||||||
</Paper>
|
</Paper>
|
||||||
<Paper p={'lg'}>
|
<Paper p={'lg'}>
|
||||||
<Text fw={'bold'} fz={'h3'}>Pengangguran Berdasarkan Pendidikan</Text>
|
<Text fw={'bold'} fz={'h3'}>Pengangguran Berdasarkan Pendidikan</Text>
|
||||||
<Center>
|
{mounted2 && donutGrafikNganggurDataPendidikan.length > 0 ? (<Center>
|
||||||
<PieChart size={300} withLabelsLine labelsPosition="outside" labelsType="percent" withLabels data={datakerjaPendidikan} withTooltip tooltipDataSource="segment" mx="auto" />
|
<PieChart
|
||||||
</Center>
|
size={300}
|
||||||
|
withLabelsLine
|
||||||
|
labelsPosition="outside"
|
||||||
|
labelsType="percent"
|
||||||
|
withLabels
|
||||||
|
data={donutGrafikNganggurDataPendidikan}
|
||||||
|
withTooltip
|
||||||
|
tooltipDataSource="segment"
|
||||||
|
mx="auto" />
|
||||||
|
</Center>) : <Skeleton h={500} />}
|
||||||
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'}>
|
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'}>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={{ base: 5, md: 8 }} align={'center'}>
|
<Flex gap={{ base: 5, md: 8 }} align={'center'}>
|
||||||
@@ -127,10 +159,16 @@ function Page() {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={{ base: 5, md: 8 }} align={'center'}>
|
<Flex gap={{ base: 5, md: 8 }} align={'center'}>
|
||||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>D3/S1</Text>
|
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>D3</Text>
|
||||||
<ColorSwatch color="#DB524D" size={30} />
|
<ColorSwatch color="#DB524D" size={30} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Flex gap={{ base: 5, md: 8 }} align={'center'}>
|
||||||
|
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>S1</Text>
|
||||||
|
<ColorSwatch color="#1018A8FF" size={30} />
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,177 +0,0 @@
|
|||||||
import colors from '@/con/colors';
|
|
||||||
import { BarChart } from '@mantine/charts';
|
|
||||||
import { Box, Button, Center, ColorSwatch, Flex, Group, Paper, SimpleGrid, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
|
||||||
import { IconChevronDown, IconDownload, IconSchool, IconSchoolOff, IconUserOff } from '@tabler/icons-react';
|
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
|
||||||
|
|
||||||
const data1 = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
icon: <IconUserOff size={35} />,
|
|
||||||
judul: 'Total Pengangguran',
|
|
||||||
jumlah: '140',
|
|
||||||
persentase: <Text fz={'h4'} c={'green'}>-12.5% dari 2024</Text>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
icon: <IconSchool size={35} />,
|
|
||||||
judul: 'Pengangguran Terdidik',
|
|
||||||
jumlah: '80',
|
|
||||||
persentase: <Text fz={'h4'} c={'gray'}>57.1% dari total</Text>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
icon: <IconSchoolOff size={35} />,
|
|
||||||
judul: 'Pengangguran Tidak Terdidik',
|
|
||||||
jumlah: '60',
|
|
||||||
persentase: <Text fz={'h4'} c={'gray'}>42.9% dari total</Text>
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const dataPengangguran = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
bulan: 'Jan',
|
|
||||||
berpendidikan: 98,
|
|
||||||
takberpendidikan: 74,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
bulan: 'Feb',
|
|
||||||
berpendidikan: 85,
|
|
||||||
takberpendidikan: 74,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
bulan: 'Mar',
|
|
||||||
berpendidikan: 76,
|
|
||||||
takberpendidikan: 55,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
bulan: 'Apr',
|
|
||||||
berpendidikan: 98,
|
|
||||||
takberpendidikan: 74,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
bulan: 'Mei',
|
|
||||||
berpendidikan: 74,
|
|
||||||
takberpendidikan: 54,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
bulan: 'Jun',
|
|
||||||
berpendidikan: 55,
|
|
||||||
takberpendidikan: 50,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const dataTable = [
|
|
||||||
{ bulan: 'Jan', total: 160, terdidik: 95, takterdidik: 65, perubahan: '-' },
|
|
||||||
{ bulan: 'Feb', total: 155, terdidik: 90, takterdidik: 65, perubahan: '-3.1%' },
|
|
||||||
{ bulan: 'Mar', total: 150, terdidik: 88, takterdidik: 62, perubahan: '-3.2%' },
|
|
||||||
{ bulan: 'Apr', total: 148, terdidik: 85, takterdidik: 63, perubahan: '-1.3%' },
|
|
||||||
{ bulan: 'Mei', total: 145, terdidik: 82, takterdidik: 63, perubahan: '-2.0%' },
|
|
||||||
{ bulan: 'Jun', total: 140, terdidik: 80, takterdidik: 60, perubahan: '-3.4%' },
|
|
||||||
]
|
|
||||||
function Page() {
|
|
||||||
const rows = dataTable.map((element) => (
|
|
||||||
<TableTr key={element.bulan}>
|
|
||||||
<TableTd ta={'center'}>{element.bulan}</TableTd>
|
|
||||||
<TableTd ta={'center'}>{element.total}</TableTd>
|
|
||||||
<TableTd ta={'center'}>{element.terdidik}</TableTd>
|
|
||||||
<TableTd ta={'center'}>{element.takterdidik}</TableTd>
|
|
||||||
<TableTd ta={'center'}>{element.perubahan}</TableTd>
|
|
||||||
</TableTr>
|
|
||||||
));
|
|
||||||
return (
|
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
|
||||||
<BackButton />
|
|
||||||
</Box>
|
|
||||||
<Box px={{ base: 'md', md: 100 }} >
|
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
|
||||||
Jumlah Pengangguran 2024 - 2025
|
|
||||||
</Text>
|
|
||||||
<Group py={20} align='center' justify='space-between'>
|
|
||||||
<Text fz={'h4'} fw={"bold"}>DATA PENGANGGURAN DESA</Text>
|
|
||||||
<Flex gap={'xl'}>
|
|
||||||
<Button c={'black'} bg={colors['white-1']} rightSection={<IconChevronDown size={20} />}>2025</Button>
|
|
||||||
<Button leftSection={<IconDownload size={20} />}>Export</Button>
|
|
||||||
</Flex>
|
|
||||||
</Group>
|
|
||||||
</Box>
|
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
|
||||||
<Stack gap={'lg'} justify='center'>
|
|
||||||
<SimpleGrid
|
|
||||||
cols={1}
|
|
||||||
pb={20}
|
|
||||||
>
|
|
||||||
{data1.map((v, k) => {
|
|
||||||
return (
|
|
||||||
<Paper px={25} key={k} py={'lg'} bg={colors['white-1']} shadow={'md'}>
|
|
||||||
<Flex justify={'space-between'} align={'center'}>
|
|
||||||
<Box>
|
|
||||||
<Stack>
|
|
||||||
<Text fz={'h4'}>{v.judul}</Text>
|
|
||||||
<Text fz={'h2'} fw={'bold'}>{v.jumlah}</Text>
|
|
||||||
{v.persentase}
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
{v.icon}
|
|
||||||
</Flex>
|
|
||||||
</Paper>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</SimpleGrid>
|
|
||||||
<Paper p={'lg'}>
|
|
||||||
<Flex pb={30} justify={'flex-end'} gap={'xl'} align={'center'}>
|
|
||||||
<Box>
|
|
||||||
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
|
||||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Pengangguran Berpendidikan</Text>
|
|
||||||
<ColorSwatch color="#5082EE" size={30} />
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
|
||||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Pengangguran Tak Berpendidikan</Text>
|
|
||||||
<ColorSwatch color="#DA524C" size={30} />
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
<Center>
|
|
||||||
<BarChart
|
|
||||||
p={10}
|
|
||||||
h={400}
|
|
||||||
data={dataPengangguran}
|
|
||||||
dataKey="bulan"
|
|
||||||
series={[
|
|
||||||
{ name: 'berpendidikan', color: '#5082EE' },
|
|
||||||
{ name: 'takberpendidikan', color: '#DA524C' },
|
|
||||||
]}
|
|
||||||
tickLine="y"
|
|
||||||
/>
|
|
||||||
</Center>
|
|
||||||
</Paper>
|
|
||||||
<Paper p={'lg'}>
|
|
||||||
<Text fw={'bold'} fz={'h4'}>Detail Data Pengangguran</Text>
|
|
||||||
<Table striped highlightOnHover>
|
|
||||||
<TableThead>
|
|
||||||
<TableTr>
|
|
||||||
<TableTh ta={'center'}>Bulan</TableTh>
|
|
||||||
<TableTh ta={'center'}>Total</TableTh>
|
|
||||||
<TableTh ta={'center'}>Terdidik</TableTh>
|
|
||||||
<TableTh ta={'center'}>Tidak Terdidik</TableTh>
|
|
||||||
<TableTh ta={'center'}>Perubahan</TableTh>
|
|
||||||
</TableTr>
|
|
||||||
</TableThead>
|
|
||||||
<TableTbody>{rows}</TableTbody>
|
|
||||||
</Table>
|
|
||||||
</Paper>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Page;
|
|
||||||
182
src/app/darmasaba/(pages)/ekonomi/jumlah-pengangguran/page.tsx
Normal file
182
src/app/darmasaba/(pages)/ekonomi/jumlah-pengangguran/page.tsx
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
'use client'
|
||||||
|
import jumlahPengangguranState from '@/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { BarChart } from '@mantine/charts';
|
||||||
|
import { Box, ColorSwatch, Flex, Group, Paper, SimpleGrid, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
import { IconSchool, IconSchoolOff, IconUserOff } from '@tabler/icons-react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
|
type DataPengangguran = {
|
||||||
|
id: string;
|
||||||
|
bulan: string;
|
||||||
|
berpendidikan: number;
|
||||||
|
takberpendidikan: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Page() {
|
||||||
|
const [chartData, setChartData] = useState<DataPengangguran[]>([])
|
||||||
|
const [mounted, setMounted] = useState(false)
|
||||||
|
const state = useProxy(jumlahPengangguranState.jumlahPengangguran)
|
||||||
|
// const [selectedYear, setSelectedYear] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
setMounted(true)
|
||||||
|
state.findMany.load()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
if (state.findMany.data) {
|
||||||
|
setChartData(state.findMany.data.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
bulan: item.month,
|
||||||
|
berpendidikan: Number(item.educatedUnemployment),
|
||||||
|
takberpendidikan: Number(item.uneducatedUnemployment),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
}, [state.findMany.data]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
|
<BackButton />
|
||||||
|
</Box>
|
||||||
|
<Box px={{ base: 'md', md: 100 }} >
|
||||||
|
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
|
Jumlah Pengangguran
|
||||||
|
</Text>
|
||||||
|
<Group py={20} align='center' justify='space-between'>
|
||||||
|
<Text fz={'h4'} fw={"bold"}>DATA PENGANGGURAN DESA</Text>
|
||||||
|
</Group>
|
||||||
|
</Box>
|
||||||
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
|
<Stack gap={'lg'} justify='center'>
|
||||||
|
<SimpleGrid
|
||||||
|
cols={1}
|
||||||
|
pb={20}
|
||||||
|
>
|
||||||
|
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="md">
|
||||||
|
{/* Total Unemployment Card */}
|
||||||
|
<Paper px={25} py={'lg'} bg={colors['white-1']} shadow="md">
|
||||||
|
<Flex direction="column" gap="md">
|
||||||
|
<IconUserOff size={35} color={colors['blue-button']} />
|
||||||
|
<Text fz="h4" fw={600}>Total Pengangguran</Text>
|
||||||
|
<Text fz="h2" fw={700} c={colors['blue-button']}>
|
||||||
|
{state.findMany.data?.[0]?.totalUnemployment || 0} Orang
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" c="dimmed">
|
||||||
|
Data tahun {state.findMany.data?.[0]?.year ? new Date(state.findMany.data[0].year).getFullYear() : ''}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
{/* Educated Unemployment Card */}
|
||||||
|
<Paper px={25} py={'lg'} bg={colors['white-1']} shadow="md">
|
||||||
|
<Flex direction="column" gap="md">
|
||||||
|
<IconSchool size={35} color="#5082EE" />
|
||||||
|
<Text fz="h4" fw={600}>Pengangguran Terdidik</Text>
|
||||||
|
<Text fz="h2" fw={700} c="#5082EE">
|
||||||
|
{state.findMany.data?.[0]?.educatedUnemployment || 0} Orang
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" c="dimmed">
|
||||||
|
{state.findMany.data?.[0]?.totalUnemployment ?
|
||||||
|
`${Math.round((state.findMany.data[0].educatedUnemployment / state.findMany.data[0].totalUnemployment) * 100)}% dari total` :
|
||||||
|
'0% dari total'}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
{/* Uneducated Unemployment Card */}
|
||||||
|
<Paper px={25} py={'lg'} bg={colors['white-1']} shadow="md">
|
||||||
|
<Flex direction="column" gap="md">
|
||||||
|
<IconSchoolOff size={35} color="#DA524C" />
|
||||||
|
<Text fz="h4" fw={600}>Pengangguran Tidak Terdidik</Text>
|
||||||
|
<Text fz="h2" fw={700} c="#DA524C">
|
||||||
|
{state.findMany.data?.[0]?.uneducatedUnemployment || 0} Orang
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" c="dimmed">
|
||||||
|
{state.findMany.data?.[0]?.totalUnemployment ?
|
||||||
|
`${Math.round((state.findMany.data[0].uneducatedUnemployment / state.findMany.data[0].totalUnemployment) * 100)}% dari total` :
|
||||||
|
'0% dari total'}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Paper>
|
||||||
|
</SimpleGrid>
|
||||||
|
</SimpleGrid>
|
||||||
|
<Paper p={'lg'}>
|
||||||
|
<Flex pb={30} justify={'flex-end'} gap={'xl'} align={'center'}>
|
||||||
|
<Box>
|
||||||
|
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
||||||
|
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Pengangguran Berpendidikan</Text>
|
||||||
|
<ColorSwatch color="#5082EE" size={30} />
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
||||||
|
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Pengangguran Tak Berpendidikan</Text>
|
||||||
|
<ColorSwatch color="#DA524C" size={30} />
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
{!mounted || chartData.length === 0 ? (
|
||||||
|
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||||
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
|
<Title pb={10} order={3}>Data Pengangguran Terdidik dan Tidak Terdidik</Title>
|
||||||
|
<Text c='dimmed'>Belum ada data untuk ditampilkan dalam grafik</Text>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Box style={{ width: '100%', minWidth: 300, height: 550, minHeight: 300 }}>
|
||||||
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
|
<Title pb={10} order={4}>Data Pengangguran Terdidik dan Tidak Terdidik</Title>
|
||||||
|
<Box w={{ base: '100%', md: '70%' }}>
|
||||||
|
<BarChart
|
||||||
|
h={450}
|
||||||
|
data={chartData}
|
||||||
|
dataKey="bulan"
|
||||||
|
series={[
|
||||||
|
{ name: 'berpendidikan', color: '#5082EE', label: 'Terdidik' },
|
||||||
|
{ name: 'takberpendidikan', color: '#DA524C', label: 'Tidak Terdidik' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Paper>
|
||||||
|
<Paper p={'lg'}>
|
||||||
|
<Text fw={'bold'} fz={'h4'}>Detail Data Pengangguran</Text>
|
||||||
|
<Table striped highlightOnHover>
|
||||||
|
<TableThead>
|
||||||
|
<TableTr>
|
||||||
|
<TableTh ta={'center'}>Bulan</TableTh>
|
||||||
|
<TableTh ta={'center'}>Total</TableTh>
|
||||||
|
<TableTh ta={'center'}>Terdidik</TableTh>
|
||||||
|
<TableTh ta={'center'}>Tidak Terdidik</TableTh>
|
||||||
|
<TableTh ta={'center'}>Perubahan</TableTh>
|
||||||
|
</TableTr>
|
||||||
|
</TableThead>
|
||||||
|
<TableTbody>
|
||||||
|
{state.findMany.data?.map((item, index) => (
|
||||||
|
<TableTr key={item?.id ? String(item.id) : `row-${index}`}>
|
||||||
|
<TableTd ta={'center'}>{item.month}</TableTd>
|
||||||
|
<TableTd ta={'center'}>{item.totalUnemployment}</TableTd>
|
||||||
|
<TableTd ta={'center'}>{item.educatedUnemployment}</TableTd>
|
||||||
|
<TableTd ta={'center'}>{item.uneducatedUnemployment}</TableTd>
|
||||||
|
<TableTd ta={'center'}>{item.percentageChange}</TableTd>
|
||||||
|
</TableTr>
|
||||||
|
))}
|
||||||
|
</TableTbody>
|
||||||
|
</Table>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -1,64 +1,52 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import lowonganKerjaState from '@/app/admin/(dashboard)/_state/ekonomi/lowongan-kerja';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Stack, Box, Text, TextInput, Group, SimpleGrid, Paper, Flex, Button } from '@mantine/core';
|
import { Box, Button, Center, Flex, Group, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
||||||
import React from 'react';
|
import { useDebouncedValue } from '@mantine/hooks';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
|
||||||
import { IconBriefcase, IconClock, IconMapPin, IconSearch } from '@tabler/icons-react';
|
import { IconBriefcase, IconClock, IconMapPin, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
const data = [
|
const formatCurrency = (value: string | number) => {
|
||||||
{
|
// Convert to string if it's a number
|
||||||
id: 1,
|
const numStr = typeof value === 'number' ? value.toString() : value;
|
||||||
kerja: 'Kasir',
|
|
||||||
tempat: 'Toko Sumber Rejeki',
|
|
||||||
alamat: 'Desa Munggu , Badung',
|
|
||||||
gaji: 'Rp. 2.500.000 / bulan'
|
|
||||||
|
|
||||||
},
|
// Remove all non-digit characters
|
||||||
{
|
const digitsOnly = numStr.replace(/\D/g, '');
|
||||||
id: 2,
|
|
||||||
kerja: 'Kasir',
|
|
||||||
tempat: 'Toko Sumber Rejeki',
|
|
||||||
alamat: 'Desa Munggu , Badung',
|
|
||||||
gaji: 'Rp. 2.500.000 / bulan'
|
|
||||||
|
|
||||||
},
|
// Format with thousand separators
|
||||||
{
|
const formatted = digitsOnly.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
|
||||||
id: 3,
|
|
||||||
kerja: 'Kasir',
|
|
||||||
tempat: 'Toko Sumber Rejeki',
|
|
||||||
alamat: 'Desa Munggu , Badung',
|
|
||||||
gaji: 'Rp. 2.500.000 / bulan'
|
|
||||||
|
|
||||||
},
|
return `Rp.${formatted}`;
|
||||||
{
|
};
|
||||||
id: 4,
|
|
||||||
kerja: 'Kasir',
|
|
||||||
tempat: 'Toko Sumber Rejeki',
|
|
||||||
alamat: 'Desa Munggu , Badung',
|
|
||||||
gaji: 'Rp. 2.500.000 / bulan'
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
kerja: 'Kasir',
|
|
||||||
tempat: 'Toko Sumber Rejeki',
|
|
||||||
alamat: 'Desa Munggu , Badung',
|
|
||||||
gaji: 'Rp. 2.500.000 / bulan'
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
kerja: 'Kasir',
|
|
||||||
tempat: 'Toko Sumber Rejeki',
|
|
||||||
alamat: 'Desa Munggu , Badung',
|
|
||||||
gaji: 'Rp. 2.500.000 / bulan'
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const state = useProxy(lowonganKerjaState)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const [search, setSearch] = useState('')
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 500); // 500ms delay
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = state.findMany
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
load(page, 6, debouncedSearch)
|
||||||
|
}, [page, debouncedSearch, load])
|
||||||
|
|
||||||
|
if (loading || !data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
@@ -74,6 +62,8 @@ function Page() {
|
|||||||
w={{ base: 500, md: 700 }}
|
w={{ base: 500, md: 700 }}
|
||||||
placeholder='Cari Pekerjaan'
|
placeholder='Cari Pekerjaan'
|
||||||
leftSection={<IconSearch size={20} />}
|
leftSection={<IconSearch size={20} />}
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -93,15 +83,15 @@ function Page() {
|
|||||||
<Flex gap={'xl'} align={'center'}>
|
<Flex gap={'xl'} align={'center'}>
|
||||||
<IconBriefcase color={colors['blue-button']} size={50} />
|
<IconBriefcase color={colors['blue-button']} size={50} />
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={'bold'} fz={'h4'} c={colors['blue-button']}>{v.kerja}</Text>
|
<Text fw={'bold'} fz={'h4'} c={colors['blue-button']}>{v.posisi}</Text>
|
||||||
<Text fz={'h4'}>{v.tempat}</Text>
|
<Text fz={'h4'}>{v.namaPerusahaan}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={'xl'} align={'center'}>
|
<Flex gap={'xl'} align={'center'}>
|
||||||
<IconMapPin color={colors['blue-button']} size={50} />
|
<IconMapPin color={colors['blue-button']} size={50} />
|
||||||
<Text fz={'h4'}>{v.alamat}</Text>
|
<Text fz={'h4'}>{v.lokasi}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -109,7 +99,7 @@ function Page() {
|
|||||||
<IconClock color={colors['blue-button']} size={50} />
|
<IconClock color={colors['blue-button']} size={50} />
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={'bold'} fz={'h4'} c={colors['blue-button']}>Full Time</Text>
|
<Text fw={'bold'} fz={'h4'} c={colors['blue-button']}>Full Time</Text>
|
||||||
<Text fz={'h4'}>{v.gaji}</Text>
|
<Text fz={'h4'}>{formatCurrency(v.gaji)}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -119,6 +109,14 @@ function Page() {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)}
|
||||||
|
total={totalPages}
|
||||||
|
my="md"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box >
|
</Box >
|
||||||
</Stack >
|
</Stack >
|
||||||
|
|||||||
@@ -1,90 +1,76 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import pasarDesaState from '@/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pasar-desa';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Combobox, Flex, Image, InputBase, InputPlaceholder, Paper, SimpleGrid, Stack, Text, TextInput, useCombobox } from '@mantine/core';
|
import { Box, Center, Flex, Grid, GridCol, Image, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconMapPinFilled, IconSearch, IconShoppingCartFilled, IconStarFilled } from '@tabler/icons-react';
|
import { IconMapPinFilled, IconSearch, IconShoppingCartFilled, IconStarFilled } from '@tabler/icons-react';
|
||||||
import { motion } from 'motion/react';
|
import { motion } from 'motion/react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
const groceries = [
|
|
||||||
'Makanan',
|
|
||||||
'Minuman',
|
|
||||||
'Pakaian',
|
|
||||||
'Alat Dapur',
|
|
||||||
'Alat Mandi',
|
|
||||||
'Furniture',
|
|
||||||
];
|
|
||||||
|
|
||||||
const dataBarang = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
image: '/api/img/semat.png',
|
|
||||||
judul: 'Semat Bambu / Semat Banten',
|
|
||||||
harga: 'Rp. 3000 / pcs',
|
|
||||||
bintang: '4.9',
|
|
||||||
alamat: 'Jl. Kecubung no.6'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
image: '/api/img/kerupuk.png',
|
|
||||||
judul: 'Kerupuk Babi',
|
|
||||||
harga: 'Rp. 12000 / pcs',
|
|
||||||
bintang: '4.9',
|
|
||||||
alamat: 'Jl. Kenari no.7'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
image: '/api/img/beras.png',
|
|
||||||
judul: 'beras Merah Organik',
|
|
||||||
harga: 'Rp. 40000 / 1 kg',
|
|
||||||
bintang: '4.9',
|
|
||||||
alamat: 'Jl. Mawar no.8'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
image: '/api/img/genteng.png',
|
|
||||||
judul: 'Genteng',
|
|
||||||
harga: 'Rp. 3600 / pcs',
|
|
||||||
bintang: '4.9',
|
|
||||||
alamat: 'Jl. Kecubung no.16'
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const [search, setSearch] = useState('');
|
|
||||||
const combobox = useCombobox({
|
|
||||||
onDropdownClose: () => {
|
|
||||||
combobox.resetSelectedOption();
|
|
||||||
combobox.focusTarget();
|
|
||||||
setSearch('');
|
|
||||||
},
|
|
||||||
|
|
||||||
onDropdownOpen: () => {
|
|
||||||
combobox.focusSearchInput();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const [value, setValue] = useState<string | null>(null);
|
|
||||||
|
|
||||||
const options = groceries
|
|
||||||
.filter((item) => item.toLowerCase().includes(search.toLowerCase().trim()))
|
|
||||||
.map((item) => (
|
|
||||||
<Combobox.Option value={item} key={item}>
|
|
||||||
{item}
|
|
||||||
</Combobox.Option>
|
|
||||||
));
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const state = useProxy(pasarDesaState.pasarDesa)
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
loading,
|
||||||
|
totalPages,
|
||||||
|
load,
|
||||||
|
} = state.findMany
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
pasarDesaState.kategoriProduk.findMany.load()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Filter data based on selected category
|
||||||
|
const filteredData = selectedCategory
|
||||||
|
? data?.filter(item =>
|
||||||
|
item.KategoriToPasar?.some(kategori => kategori.kategoriId === selectedCategory)
|
||||||
|
)
|
||||||
|
: data;
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
load(page, 4, search, selectedCategory || undefined)
|
||||||
|
}, [page, search, selectedCategory])
|
||||||
|
|
||||||
|
|
||||||
|
if (loading || !data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Grid align='center' px={{ base: 'md', md: 100 }}>
|
||||||
Pasar Desa
|
<GridCol span={{ base: 12, md: 9 }}>
|
||||||
</Text>
|
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
<Text px={{ base: 20, md: 150 }} ta={"center"} fz={{ base: "h4", md: "h3" }} >
|
Pasar Desa
|
||||||
|
</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 3 }}>
|
||||||
|
<TextInput
|
||||||
|
radius={"lg"}
|
||||||
|
placeholder='Cari Produk'
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
|
leftSection={<IconSearch size={20} />}
|
||||||
|
w={{ base: "50%", md: "100%" }}
|
||||||
|
/>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
<Text px={{ base: 'md', md: 100 }} ta={"justify"} fz={{ base: "h4", md: "h3" }} >
|
||||||
Pasar Desa Online merupakan Media Promosi yang bertujuan untuk membantu warga desa dalam memasarkan dan memperkenalkan produknya kepada masyarakat.
|
Pasar Desa Online merupakan Media Promosi yang bertujuan untuk membantu warga desa dalam memasarkan dan memperkenalkan produknya kepada masyarakat.
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -98,48 +84,23 @@ function Page() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box>
|
<Box>
|
||||||
<Combobox
|
<Select
|
||||||
store={combobox}
|
placeholder="Pilih Kategori"
|
||||||
withinPortal={false}
|
data={pasarDesaState.kategoriProduk.findMany.data?.map((v) => ({
|
||||||
onOptionSubmit={(val) => {
|
value: v.id,
|
||||||
setValue(val);
|
label: v.nama
|
||||||
combobox.closeDropdown();
|
})) || []}
|
||||||
}}
|
value={selectedCategory}
|
||||||
>
|
onChange={setSelectedCategory}
|
||||||
<Combobox.Target>
|
clearable
|
||||||
<InputBase
|
searchable
|
||||||
component="button"
|
nothingFoundMessage="Tidak ada kategori ditemukan"
|
||||||
type="button"
|
style={{ width: '100%' }}
|
||||||
pointer
|
|
||||||
rightSection={<Combobox.Chevron />}
|
|
||||||
onClick={() => combobox.toggleDropdown()}
|
|
||||||
rightSectionPointerEvents="none"
|
|
||||||
>
|
|
||||||
{value || <InputPlaceholder>Kategori</InputPlaceholder>}
|
|
||||||
</InputBase>
|
|
||||||
</Combobox.Target>
|
|
||||||
|
|
||||||
<Combobox.Dropdown>
|
|
||||||
<Combobox.Search
|
|
||||||
value={search}
|
|
||||||
onChange={(event) => setSearch(event.currentTarget.value)}
|
|
||||||
placeholder="Search groceries"
|
|
||||||
/>
|
|
||||||
<Combobox.Options>
|
|
||||||
{options.length > 0 ? options : <Combobox.Empty>Nothing found</Combobox.Empty>}
|
|
||||||
</Combobox.Options>
|
|
||||||
</Combobox.Dropdown>
|
|
||||||
</Combobox>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<TextInput
|
|
||||||
placeholder='Cari Produk'
|
|
||||||
leftSection={<IconSearch size={20} />}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<SimpleGrid cols={{ base: 1, md: 4 }}>
|
<SimpleGrid cols={{ base: 1, md: 4 }}>
|
||||||
{dataBarang.map((v, k) => {
|
{filteredData?.map((v, k) => {
|
||||||
return (
|
return (
|
||||||
<Stack key={k}>
|
<Stack key={k}>
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -148,18 +109,25 @@ function Page() {
|
|||||||
whileTap={{ scale: 0.8 }}
|
whileTap={{ scale: 0.8 }}
|
||||||
>
|
>
|
||||||
<Paper p={'lg'}>
|
<Paper p={'lg'}>
|
||||||
<Image radius={'lg'} src={v.image} alt='' />
|
<Image
|
||||||
<Text py={10} fw={'bold'} fz={'lg'}>{v.judul}</Text>
|
radius={'lg'}
|
||||||
<Text fz={'md'}>{v.harga}</Text>
|
src={v.image?.link || '/placeholder-product.jpg'}
|
||||||
|
alt={v.nama}
|
||||||
|
h={200}
|
||||||
|
w='100%'
|
||||||
|
style={{ objectFit: 'cover' }}
|
||||||
|
/>
|
||||||
|
<Text py={10} fw={'bold'} fz={'lg'}>{v.nama}</Text>
|
||||||
|
<Text fz={'md'}>Rp {v.harga.toLocaleString('id-ID')}</Text>
|
||||||
<Flex py={10} gap={'md'}>
|
<Flex py={10} gap={'md'}>
|
||||||
<IconStarFilled size={20} color='#EBCB09' />
|
<IconStarFilled size={20} color='#EBCB09' />
|
||||||
<Text fz={'sm'} ml={2}>{v.bintang}</Text>
|
<Text fz={'sm'} ml={2}>{v.rating}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justify={'space-between'} align={'center'}>
|
<Flex justify={'space-between'} align={'center'}>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={'md'} align={'center'}>
|
<Flex gap={'md'} align={'center'}>
|
||||||
<IconMapPinFilled size={20} color='red' />
|
<IconMapPinFilled size={20} color='red' />
|
||||||
<Text fz={'sm'} ml={2}>{v.alamat}</Text>
|
<Text fz={'sm'} ml={2}>{v.alamatUsaha}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<IconShoppingCartFilled size={20} color={colors['blue-button']} />
|
<IconShoppingCartFilled size={20} color={colors['blue-button']} />
|
||||||
@@ -170,6 +138,14 @@ function Page() {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)} // ini penting!
|
||||||
|
total={totalPages}
|
||||||
|
my="md"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,64 +1,82 @@
|
|||||||
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Stack, Box, Text, SimpleGrid, Paper } from '@mantine/core';
|
import { Stack, Box, Text, SimpleGrid, Paper, Skeleton, Center, Pagination, Grid, GridCol, TextInput } from '@mantine/core';
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
import { LineChart } from '@mantine/charts';
|
import { CartesianGrid, Legend, Line, LineChart as RechartsLineChart, Tooltip, XAxis, YAxis } from 'recharts';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import programKemiskinanState from '@/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
import { IconSearch } from '@tabler/icons-react';
|
||||||
|
|
||||||
|
interface StatistikData {
|
||||||
|
id: string;
|
||||||
|
tahun: number;
|
||||||
|
jumlah: number;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProgramKemiskinanData {
|
||||||
|
id: string;
|
||||||
|
nama: string;
|
||||||
|
deskripsi: string;
|
||||||
|
ikonUrl: string | null;
|
||||||
|
statistik: StatistikData | null;
|
||||||
|
isActive: boolean;
|
||||||
|
statistikId: string | null;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
judul: 'Bantuan Tunai',
|
|
||||||
deskripsi: 'Bantuan keuangan langsung bagi keluarga kurang mampu'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
judul: 'Pelatihan Kerja',
|
|
||||||
deskripsi: 'Program pelatihan keterampilan untuk meningkatkan peluang kerja'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
judul: 'Subsidi Pangan',
|
|
||||||
deskripsi: 'Distribusi bahan pangan bersubsidi bagi masyarakat kurang mampu'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
judul: 'Layanan Kesehatan Gratis',
|
|
||||||
deskripsi: 'Akses kesehatan gratis bagi masyarakat kurang mampu'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const dataStatistik = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
tahun: '2022',
|
|
||||||
Kemiskinan: 400000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
tahun: '2023',
|
|
||||||
Kemiskinan: 450000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
tahun: '2024',
|
|
||||||
Kemiskinan: 500000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
tahun: '2025',
|
|
||||||
Kemiskinan: 400000
|
|
||||||
},
|
|
||||||
]
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const [search, setSearch] = useState('')
|
||||||
|
const state = useProxy(programKemiskinanState)
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load
|
||||||
|
} = state.findMany
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
load(page, 2, search)
|
||||||
|
}, [page, search])
|
||||||
|
|
||||||
|
if (loading || !data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: 'md', md: 100 }} >
|
<Box px={{ base: 'md', md: 100 }} >
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Grid align='center'>
|
||||||
Program Kemiskinan
|
<GridCol span={{ base: 12, md: 9 }}>
|
||||||
</Text>
|
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
<Text ta={'center'} fz={'h4'}>Berbagai program bantuan untuk mengurangi kemiskinan dan meningkatkan kesejahteraan masyarakat</Text>
|
Program Kemiskinan
|
||||||
|
</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 3 }}>
|
||||||
|
<TextInput
|
||||||
|
radius={"lg"}
|
||||||
|
placeholder='Cari Program'
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
|
leftSection={<IconSearch size={20} />}
|
||||||
|
w={{ base: "50%", md: "100%" }}
|
||||||
|
/>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
<Text fz={'h4'}>Berbagai program bantuan untuk mengurangi kemiskinan dan meningkatkan kesejahteraan masyarakat</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap={'lg'} justify='center'>
|
<Stack gap={'lg'} justify='center'>
|
||||||
@@ -69,26 +87,66 @@ function Page() {
|
|||||||
md: 2
|
md: 2
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{data.map((v, k) => {
|
{state.findMany.data.map((v, k) => {
|
||||||
return (
|
return (
|
||||||
<Paper p={'xl'} key={k}>
|
<Paper p={'xl'} key={k}>
|
||||||
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']}>{v.judul}</Text>
|
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']}>{v.nama}</Text>
|
||||||
<Text fz={'lg'} c={'black'}>{v.deskripsi}</Text>
|
<Text fz={'lg'} c={'black'} dangerouslySetInnerHTML={{ __html: v.deskripsi }}></Text>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<Paper p={'xl'}>
|
<Center my={10}>
|
||||||
<Text fz={'h4'} fw={'bold'} c={colors['blue-button']}>Statistik Kemiskinan Masyarakat</Text>
|
<Pagination
|
||||||
<LineChart
|
value={page}
|
||||||
h={300}
|
onChange={(newPage) => load(newPage)}
|
||||||
data={dataStatistik}
|
total={totalPages}
|
||||||
dataKey="tahun"
|
my={"md"}
|
||||||
series={[
|
|
||||||
{ name: 'Kemiskinan', color: colors['blue-button'] },
|
|
||||||
]}
|
|
||||||
curveType="linear"
|
|
||||||
/>
|
/>
|
||||||
|
</Center>
|
||||||
|
<Paper p={'xl'}>
|
||||||
|
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']} mb="md">Statistik Kemiskinan Masyarakat</Text>
|
||||||
|
<Box style={{ width: '100%', height: 'auto' }}>
|
||||||
|
{data.length > 0 && data[0]?.statistik ? (
|
||||||
|
<Box w="100%" style={{ overflowX: 'auto' }}>
|
||||||
|
<Center>
|
||||||
|
<RechartsLineChart
|
||||||
|
width={800}
|
||||||
|
height={300}
|
||||||
|
data={state.findMany.data
|
||||||
|
.filter((item): item is ProgramKemiskinanData & { statistik: StatistikData } =>
|
||||||
|
item.statistik !== null
|
||||||
|
)
|
||||||
|
.map(item => ({
|
||||||
|
tahun: item.statistik.tahun,
|
||||||
|
jumlah: item.statistik.jumlah
|
||||||
|
}))
|
||||||
|
.sort((a, b) => a.tahun - b.tahun)
|
||||||
|
}
|
||||||
|
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
||||||
|
>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="tahun" />
|
||||||
|
<YAxis />
|
||||||
|
<Tooltip
|
||||||
|
formatter={(value: number, name: string) => [`${value} orang`, name]}
|
||||||
|
labelFormatter={(label: number) => `Tahun: ${label}`}
|
||||||
|
/>
|
||||||
|
<Legend />
|
||||||
|
<Line
|
||||||
|
type="monotone"
|
||||||
|
dataKey="jumlah"
|
||||||
|
name="Jumlah Masyarakat Miskin"
|
||||||
|
stroke={colors['blue-button']}
|
||||||
|
activeDot={{ r: 8 }}
|
||||||
|
/>
|
||||||
|
</RechartsLineChart>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Text c="dimmed">Belum ada data statistik yang tersedia</Text>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,23 +1,33 @@
|
|||||||
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Stack, Box, Text, Paper } from '@mantine/core';
|
import { Stack, Box, Text, Paper, Skeleton } from '@mantine/core';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
import { BarChart } from '@mantine/charts';
|
import { BarChart } from '@mantine/charts';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import grafikSektorUnggulan from '@/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
sektor: 'Sektor Pertanian',
|
|
||||||
Ton: 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
sektor: 'Sektor Peternakan',
|
|
||||||
Ton: 5
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const state = useProxy(grafikSektorUnggulan)
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
loading,
|
||||||
|
} = state.findMany
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
state.findMany.load()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (loading || !data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
@@ -31,28 +41,24 @@ function Page() {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap={'lg'} justify='center'>
|
<Stack gap={'lg'} justify='center'>
|
||||||
<Paper p={'xl'}>
|
{data.map((v, k) => {
|
||||||
<Text fw={'bold'} fz={'h4'}>Jumlah Penduduk Miskin Per Tahun</Text>
|
return (
|
||||||
<Text fz={'h4'} ta={'justify'}>
|
<Paper p={'xl'} key={k}>
|
||||||
Pertanian di Darmasaba berfokus pada padi, sayuran, dan hortikultura yang dikembangkan dengan metode pertanian
|
<Text fw={'bold'} fz={'h4'}>{v.name}</Text>
|
||||||
organik serta sistem irigasi tradisional yang efisien. Keberlanjutan dalam pertanian juga didukung dengan pemanfaatan
|
<Text fz={'h4'} ta={'justify'} dangerouslySetInnerHTML={{ __html: v.description || '' }} />
|
||||||
teknologi modern untuk meningkatkan produktivitas hasil panen.
|
</Paper>
|
||||||
</Text>
|
)
|
||||||
</Paper>
|
})}
|
||||||
<Paper p={'xl'}>
|
|
||||||
<Text fw={'bold'} fz={'h4'}>Sektor Peternakan</Text>
|
|
||||||
<Text fz={'h4'} ta={'justify'}>
|
|
||||||
Di bidang peternakan, Desa Darmasaba memiliki potensi besar dalam pengembangan sapi, ayam, dan babi. Sistem
|
|
||||||
peternakan yang diterapkan mengutamakan pengelolaan pakan alami dan perawatan hewan yang sehat, sehingga
|
|
||||||
menghasilkan produk ternak berkualitas tinggi.
|
|
||||||
</Text>
|
|
||||||
</Paper>
|
|
||||||
<Paper p={'xl'}>
|
<Paper p={'xl'}>
|
||||||
<Text pb={10} fw={'bold'} fz={'h4'}>Statistik Sektor Unggulan Darmasaba</Text>
|
<Text pb={10} fw={'bold'} fz={'h4'}>Statistik Sektor Unggulan Darmasaba</Text>
|
||||||
<BarChart
|
<BarChart
|
||||||
p={10}
|
p={10}
|
||||||
h={300}
|
h={300}
|
||||||
data={data}
|
data={data.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
sektor: item.name,
|
||||||
|
Ton: item.value,
|
||||||
|
}))}
|
||||||
dataKey="sektor"
|
dataKey="sektor"
|
||||||
series={[
|
series={[
|
||||||
{ name: 'Ton', color: colors['blue-button'] },
|
{ name: 'Ton', color: colors['blue-button'] },
|
||||||
|
|||||||
@@ -1,83 +1,62 @@
|
|||||||
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Image, List, ListItem, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
import { Box, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import tipsKeamananState from '@/app/admin/(dashboard)/_state/keamanan/tips-keamanan';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { IconSearch } from '@tabler/icons-react';
|
||||||
|
|
||||||
const data1 = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
judul: 'Keamanan Rumah',
|
|
||||||
image: '/api/img/kemanan.png',
|
|
||||||
deskripsi: <List>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Pastikan pintu dan jendela selalu terkunci saat meninggalkan rumah.</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Pasang lampu penerangan di halaman dan area sekitar rumah untuk mencegah tindak kejahatan.</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Jangan mudah memberikan akses masuk ke orang yang tidak dikenal.</ListItem>
|
|
||||||
</List>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
judul: 'Keamanan di Jalan',
|
|
||||||
image: '/api/img/keamananjalan.png',
|
|
||||||
deskripsi: <List>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Hindari berjalan sendirian di tempat sepi, terutama pada malam hari.</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Simpan barang berharga di tempat yang aman saat bepergian.</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Gunakan jalur yang ramai dan terang saat pulang malam.</ListItem>
|
|
||||||
</List>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
judul: 'Keamanan Kendaraan',
|
|
||||||
image: '/api/img/keamanankendaraan.png',
|
|
||||||
deskripsi: <List>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Gunakan kunci ganda saat memarkir kendaraan, terutama di tempat umum.</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Parkir di tempat yang terang dan mudah diawasi.</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Jangan meninggalkan barang berharga di dalam kendaraan.</ListItem>
|
|
||||||
</List>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
judul: 'Keamanan Sosial',
|
|
||||||
image: '/api/img/mencurigakan.png',
|
|
||||||
deskripsi: <List>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Laporkan kejadian mencurigakan kepada Pecalang atau perangkat desa.</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Jangan mudah percaya terhadap informasi yang belum jelas sumbernya.</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Ikuti program sosialisasi keamanan yang diadakan oleh desa.</ListItem>
|
|
||||||
</List>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
judul: 'Sistem Laporan Kejadian',
|
|
||||||
image: '/api/img/securitydigital.png',
|
|
||||||
deskripsi: <List>
|
|
||||||
<ListItem>Jangan mudah membagikan informasi pribadi di media sosial.</ListItem>
|
|
||||||
<ListItem>Waspada terhadap penipuan online dan telepon yang mengatasnamakan instansi resmi.</ListItem>
|
|
||||||
<ListItem>Gunakan kata sandi yang kuat untuk akun digital dan ganti secara berkala.</ListItem>
|
|
||||||
</List>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
judul: 'Nomor Darurat yang Bisa Dihubungi',
|
|
||||||
image: '/api/img/kontakpecalang.png',
|
|
||||||
deskripsi: <List>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Pecalang: 08125651052</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Ambulans: 08125651052</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Pemadam Kebakaran: 113</ListItem>
|
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Polisi: 110</ListItem>
|
|
||||||
</List>
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const state = useProxy(tipsKeamananState)
|
||||||
|
const [search, setSearch] = useState('')
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = state.findMany;
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
load(page, 3, search)
|
||||||
|
}, [page, search])
|
||||||
|
|
||||||
|
if (loading || !data) {
|
||||||
|
return (
|
||||||
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Grid align='center' px={{ base: 'md', md: 100 }}>
|
||||||
Tips Keamanan
|
<GridCol span={{ base: 12, md: 9 }}>
|
||||||
</Text>
|
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
<Text px={{ base: 20, md: 150 }} ta={"center"} fz={{ base: "h4", md: "h3" }} >
|
Tips Keamanan
|
||||||
Desa Darmasaba berkomitmen untuk menjaga keamanan dan kenyamanan seluruh warganya. Berikut beberapa tips yang dapat membantu meningkatkan keamanan di lingkungan desa.
|
</Text>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 3 }}>
|
||||||
|
<TextInput
|
||||||
|
radius={"lg"}
|
||||||
|
placeholder='Cari Tips'
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
|
leftSection={<IconSearch size={20} />}
|
||||||
|
w={{ base: "50%", md: "100%" }}
|
||||||
|
/>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
<Text px={{ base: 'md', md: 100 }} ta={"justify"} fz={{ base: "h4", md: "h3" }} >
|
||||||
|
Keamanan dan ketertiban lingkungan di Desa Darmasaba dijaga melalui peran aktif Pecalang dan Patwal (Patroli Pengawal). Mereka bertugas memastikan desa tetap aman, tertib, dan kondusif bagi seluruh warga.
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
@@ -88,21 +67,21 @@ function Page() {
|
|||||||
base: 1,
|
base: 1,
|
||||||
md: 3,
|
md: 3,
|
||||||
}}>
|
}}>
|
||||||
{data1.map((v, k) => {
|
{data.map((v, k) => {
|
||||||
return (
|
return (
|
||||||
<Paper radius={10} key={k} bg={colors["white-trans-1"]}>
|
<Paper radius={10} key={k} bg={colors["white-trans-1"]}>
|
||||||
<Stack gap={'xs'}>
|
<Stack gap={'xs'}>
|
||||||
<Center p={10}>
|
<Center p={10}>
|
||||||
<Image src={v.image} radius={10}
|
<Image src={v.image?.link} radius={10}
|
||||||
alt='' />
|
alt='' />
|
||||||
</Center>
|
</Center>
|
||||||
<Box px={'xl'}>
|
<Box px={'xl'}>
|
||||||
<Box pb={20}>
|
<Box pb={20}>
|
||||||
<Text pb={10} c={colors["blue-button"]} fw={"bold"} fz={"h3"}>
|
<Text pb={10} c={colors["blue-button"]} fw={"bold"} fz={"h3"}>
|
||||||
{v.judul}
|
{v.judul}
|
||||||
</Text>
|
</Text>
|
||||||
<Box pr={10}>
|
<Box>
|
||||||
{v.deskripsi}
|
<Text pb={10} fz={"md"} dangerouslySetInnerHTML={{ __html: v.deskripsi }} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -113,6 +92,14 @@ function Page() {
|
|||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)} // ini penting!
|
||||||
|
total={totalPages}
|
||||||
|
my="md"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ function ArtikelKesehatanPage() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Paper p={'xl'} h={'112vh'} bg={colors['white-trans-1']}>
|
<Paper p={'xl'} h={'112vh'} bg={colors['white-trans-1']}>
|
||||||
<Stack gap={'xs'}>
|
<Stack gap={'xs'}>
|
||||||
|
<Text ta={'center'} fw={"bold"} fz={'h3'} c={colors['blue-button']}>Artikel Kesehatan</Text>
|
||||||
{state.findMany.data.map((item) => (
|
{state.findMany.data.map((item) => (
|
||||||
<Box key={item.id}>
|
<Box key={item.id}>
|
||||||
<Text ta={'center'} fw={"bold"} fz={'h3'} c={colors['blue-button']}>Artikel Kesehatan</Text>
|
|
||||||
<Image pt={5} src={'/api/img/dbd.png'} alt="" />
|
<Image pt={5} src={'/api/img/dbd.png'} alt="" />
|
||||||
<Text fz={'h4'} fw={'bold'} >
|
<Text fz={'h4'} fw={'bold'} >
|
||||||
{item.title}
|
{item.title}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Divider, Group, List, ListItem, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
import { Box, Divider, List, ListItem, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
@@ -139,14 +139,14 @@ function Page() {
|
|||||||
Email : <Text span fz={'h4'}>puskesmasabiansemal3@gmail.com</Text>
|
Email : <Text span fz={'h4'}>puskesmasabiansemal3@gmail.com</Text>
|
||||||
</Text>
|
</Text>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Paper p={'lg'} w={{ base: "100%", md: "100%" }}>
|
{/* <Paper p={'lg'} w={{ base: "100%", md: "100%" }}>
|
||||||
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3945.272172359321!2d115.21836257533302!3d-8.569807186941553!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x2dd23e9d99b9395f%3A0xb002795fdcb33b30!2sUPTD%20Puskesmas%20Abiansemal%20III!5e0!3m2!1sid!2sid!4v1744792682341!5m2!1sid!2sid" width="600" height="450" style={{ border: 2, width: "100%", borderRadius: 10 }} loading="lazy"></iframe>
|
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3945.272172359321!2d115.21836257533302!3d-8.569807186941553!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x2dd23e9d99b9395f%3A0xb002795fdcb33b30!2sUPTD%20Puskesmas%20Abiansemal%20III!5e0!3m2!1sid!2sid!4v1744792682341!5m2!1sid!2sid" width="600" height="450" style={{ border: 2, width: "100%", borderRadius: 10 }} loading="lazy"></iframe>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Group>
|
<Group>
|
||||||
<Button fz={'lg'} bg={colors['blue-button']}>
|
<Button fz={'lg'} bg={colors['blue-button']}>
|
||||||
Download Brosur Layanan (PDF)
|
Download Brosur Layanan (PDF)
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group> */}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
'use client'
|
|
||||||
import grafikBerdasarkanJenisKelamin from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin';
|
|
||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Center, Flex, Skeleton, Stack, Text, Title } from '@mantine/core';
|
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { Cell, Pie, PieChart } from 'recharts';
|
|
||||||
import { useProxy } from 'valtio/utils';
|
|
||||||
|
|
||||||
function GrafikBerdasarkanJenisKelamin() {
|
|
||||||
const stategrafikBerdasarkanJenisKelamin = useProxy(grafikBerdasarkanJenisKelamin)
|
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
const [donutData, setDonutData] = useState<any[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const updateChartData = (data: any) => {
|
|
||||||
if (data && data.length > 0) {
|
|
||||||
const totalLaki = data.reduce((acc: number, cur: any) => acc + Number(cur.laki || 0), 0);
|
|
||||||
const totalPerempuan = data.reduce((acc: number, cur: any) => acc + Number(cur.perempuan || 0), 0);
|
|
||||||
|
|
||||||
setDonutData([
|
|
||||||
{ name: 'Laki-laki', value: totalLaki, color: colors['blue-button'], key: 'laki-laki' },
|
|
||||||
{ name: 'Perempuan', value: totalPerempuan, color: '#FF6384', key: 'perempuan' }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
|
||||||
await stategrafikBerdasarkanJenisKelamin.findMany.load();
|
|
||||||
if (stategrafikBerdasarkanJenisKelamin.findMany.data) {
|
|
||||||
updateChartData(stategrafikBerdasarkanJenisKelamin.findMany.data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(!stategrafikBerdasarkanJenisKelamin.findMany.data) return <Stack>
|
|
||||||
<Title pb={10} order={3}>Grafik Berdasarkan Jenis Kelamin Responden</Title>
|
|
||||||
<Skeleton h={500} />
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack gap={"xl"}>
|
|
||||||
<Title pb={10} order={3}>Grafik Berdasarkan Jenis Kelamin Responden</Title>
|
|
||||||
{mounted && donutData.length > 0 && (
|
|
||||||
<Box style={{ width: '100%', height: 'auto', minHeight: 300 }}>
|
|
||||||
<Center>
|
|
||||||
<PieChart
|
|
||||||
width={1000} height={530}
|
|
||||||
data={donutData}
|
|
||||||
>
|
|
||||||
|
|
||||||
<Pie
|
|
||||||
dataKey="value"
|
|
||||||
nameKey="name"
|
|
||||||
data={donutData}
|
|
||||||
innerRadius={120}
|
|
||||||
outerRadius={230}
|
|
||||||
label={true}
|
|
||||||
>
|
|
||||||
{donutData.map((entry, index) => (
|
|
||||||
<Cell key={`cell-${index}`} fill={entry.color} />
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
</PieChart>
|
|
||||||
</Center>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={'#FF6384'} w={20} h={20} />
|
|
||||||
<Text>Perempuan: {donutData.find((entry) => entry.name === 'Perempuan')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={colors['blue-button']} w={20} h={20} />
|
|
||||||
<Text>Laki-laki: {donutData.find((entry) => entry.name === 'Laki-laki')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GrafikBerdasarkanJenisKelamin;
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
'use client'
|
|
||||||
import grafikBerdasarkanResponden from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanResponden';
|
|
||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Center, Flex, Skeleton, Stack, Text, Title } from '@mantine/core';
|
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { Cell, Pie, PieChart } from 'recharts';
|
|
||||||
import { useProxy } from 'valtio/utils';
|
|
||||||
|
|
||||||
function GrafikBerdasarkanResponden() {
|
|
||||||
const stategrafikBerdasarkanResponden = useProxy(grafikBerdasarkanResponden)
|
|
||||||
const [donutData, setDonutData] = useState<any[]>([]);
|
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const updateChartData = (data: any) => {
|
|
||||||
if (data && data.length > 0) {
|
|
||||||
const totalSangatBaik = data.reduce((acc: number, cur: any) => acc + Number(cur.sangatbaik || 0), 0);
|
|
||||||
const totalBaik = data.reduce((acc: number, cur: any) => acc + Number(cur.baik || 0), 0);
|
|
||||||
const totalKurangBaik = data.reduce((acc: number, cur: any) => acc + Number(cur.kurangbaik || 0), 0);
|
|
||||||
const totalTidakBaik = data.reduce((acc: number, cur: any) => acc + Number(cur.tidakbaik || 0), 0);
|
|
||||||
setDonutData([
|
|
||||||
{ name: 'sangatbaik', value: totalSangatBaik, color: colors['blue-button'], key: 'sangatbaik' },
|
|
||||||
{ name: 'baik', value: totalBaik, color: '#10A85AFF', key: 'baik' },
|
|
||||||
{ name: 'kurangbaik', value: totalKurangBaik, color: '#B3AA12FF', key: 'kurangbaik' },
|
|
||||||
{ name: 'tidakbaik', value: totalTidakBaik, color: '#B21313FF', key: 'tidakbaik' }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
|
||||||
await stategrafikBerdasarkanResponden.findMany.load();
|
|
||||||
if (stategrafikBerdasarkanResponden.findMany.data) {
|
|
||||||
updateChartData(stategrafikBerdasarkanResponden.findMany.data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!stategrafikBerdasarkanResponden.findMany.data) return <Stack>
|
|
||||||
<Title pb={10} order={3}>Grafik Berdasarkan Responden</Title>
|
|
||||||
<Skeleton h={500} />
|
|
||||||
</Stack>
|
|
||||||
return (
|
|
||||||
<Stack>
|
|
||||||
<Title pb={10} order={3}>Grafik Berdasarkan Responden</Title>
|
|
||||||
{mounted && donutData.length > 0 && (
|
|
||||||
<Box style={{ width: '100%', height: 'auto', minHeight: 300 }}>
|
|
||||||
<Center>
|
|
||||||
<PieChart
|
|
||||||
width={1000} height={530}
|
|
||||||
data={donutData}
|
|
||||||
>
|
|
||||||
<Pie
|
|
||||||
dataKey="value"
|
|
||||||
nameKey="name"
|
|
||||||
data={donutData}
|
|
||||||
innerRadius={120}
|
|
||||||
outerRadius={230}
|
|
||||||
label={true}
|
|
||||||
>
|
|
||||||
{donutData.map((entry, index) => (
|
|
||||||
<Cell key={`cell-${index}`} fill={entry.color} />
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
</PieChart>
|
|
||||||
</Center>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={colors['blue-button']} w={20} h={20} />
|
|
||||||
<Text>Sangat Baik: {donutData.find((entry) => entry.name === 'sangatbaik')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={'#10A85AFF'} w={20} h={20} />
|
|
||||||
<Text>Baik: {donutData.find((entry) => entry.name === 'baik')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={'#B3AA12FF'} w={20} h={20} />
|
|
||||||
<Text>Kurang Baik: {donutData.find((entry) => entry.name === 'kurangbaik')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={'#B21313FF'} w={20} h={20} />
|
|
||||||
<Text>Tidak Baik: {donutData.find((entry) => entry.name === 'tidakbaik')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GrafikBerdasarkanResponden;
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
'use client'
|
|
||||||
import grafikBerdasarkanUmur from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanUmur';
|
|
||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Center, Flex, Skeleton, Stack, Text, Title } from '@mantine/core';
|
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { Cell, Pie, PieChart } from 'recharts';
|
|
||||||
import { useProxy } from 'valtio/utils';
|
|
||||||
|
|
||||||
function GrafikBerdasarakanUmur() {
|
|
||||||
const stategrafikBerdasarkanUmur = useProxy(grafikBerdasarkanUmur)
|
|
||||||
const [donutData, setDonutData] = useState<any[]>([]);
|
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const updateChartData = (data: any) => {
|
|
||||||
if (data && data.length > 0) {
|
|
||||||
const totalRemaja = data.reduce((acc: number, cur: any) => acc + Number(cur.remaja || 0), 0);
|
|
||||||
const totalDewasa = data.reduce((acc: number, cur: any) => acc + Number(cur.dewasa || 0), 0);
|
|
||||||
const totalOrangtua = data.reduce((acc: number, cur: any) => acc + Number(cur.orangtua || 0), 0);
|
|
||||||
const totalLansia = data.reduce((acc: number, cur: any) => acc + Number(cur.lansia || 0), 0);
|
|
||||||
|
|
||||||
setDonutData([
|
|
||||||
{ name: 'Remaja', value: totalRemaja, color: colors['blue-button'], key: 'remaja' },
|
|
||||||
{ name: 'Dewasa', value: totalDewasa, color: '#D32711FF', key: 'dewasa' },
|
|
||||||
{ name: 'Orangtua', value: totalOrangtua, color: '#B46B04FF', key: 'orangtua' },
|
|
||||||
{ name: 'Lansia', value: totalLansia, color: '#038617FF', key: 'lansia' }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
|
||||||
await stategrafikBerdasarkanUmur.findMany.load();
|
|
||||||
if (stategrafikBerdasarkanUmur.findMany.data) {
|
|
||||||
updateChartData(stategrafikBerdasarkanUmur.findMany.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!stategrafikBerdasarkanUmur.findMany.data) return <Stack>
|
|
||||||
<Title pb={10} order={3}>Grafik Berdasarkan Umur Responden</Title>
|
|
||||||
<Skeleton h={500} />
|
|
||||||
</Stack>
|
|
||||||
return (
|
|
||||||
<Stack>
|
|
||||||
<Title pb={10} order={3}>Grafik Berdasarkan Umur Responden</Title>
|
|
||||||
{mounted && donutData.length > 0 && (
|
|
||||||
<Box style={{ width: '100%', height: 'auto', minHeight: 300 }}>
|
|
||||||
<Center>
|
|
||||||
<PieChart
|
|
||||||
width={1000} height={530}
|
|
||||||
data={donutData}
|
|
||||||
>
|
|
||||||
<Pie
|
|
||||||
dataKey="value"
|
|
||||||
nameKey="name"
|
|
||||||
data={donutData}
|
|
||||||
innerRadius={120}
|
|
||||||
outerRadius={230}
|
|
||||||
label={true}
|
|
||||||
>
|
|
||||||
{donutData.map((entry, index) => (
|
|
||||||
<Cell key={`cell-${index}`} fill={entry.color} />
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
</PieChart>
|
|
||||||
</Center>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={colors['blue-button']} w={20} h={20} />
|
|
||||||
<Text>17 - 25 tahun: {donutData.find((entry) => entry.name === 'remaja')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={'#D32711FF'} w={20} h={20} />
|
|
||||||
<Text>26 - 45 tahun: {donutData.find((entry) => entry.name === 'dewasa')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={'#B46B04FF'} w={20} h={20} />
|
|
||||||
<Text>46 - 60 tahun: {donutData.find((entry) => entry.name === 'orangtua')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={"md"} align={"center"}>
|
|
||||||
<Box bg={'#038617FF'} w={20} h={20} />
|
|
||||||
<Text>di atas 60 tahun: {donutData.find((entry) => entry.name === 'lansia')?.value}</Text>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GrafikBerdasarakanUmur;
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
'use client'
|
|
||||||
import grafikHasilKepuasanMasyarakat from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikHasilKepuasan';
|
|
||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Skeleton, Stack, Text, Title } from '@mantine/core';
|
|
||||||
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts';
|
|
||||||
import { useProxy } from 'valtio/utils';
|
|
||||||
|
|
||||||
function GrafikHasilKepuasan() {
|
|
||||||
const grafikHasilKepuasan = useProxy(grafikHasilKepuasanMasyarakat)
|
|
||||||
const [chartData, setChartData] = useState<any[]>([]);
|
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
const isTablet = useMediaQuery('(max-width: 1024px)')
|
|
||||||
const isMobile = useMediaQuery('(max-width: 768px)')
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
|
||||||
const fetchData = async () => {
|
|
||||||
await grafikHasilKepuasan.findMany.load();
|
|
||||||
if (grafikHasilKepuasan.findMany.data && grafikHasilKepuasan.findMany.data.length > 0) {
|
|
||||||
setChartData(grafikHasilKepuasan.findMany.data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if(!grafikHasilKepuasan.findMany.data) return <Stack>
|
|
||||||
<Title pb={10} order={3}>Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik</Title>
|
|
||||||
<Skeleton h={500} />
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack gap={"xl"}>
|
|
||||||
<Text fw={"bold"} fz={{ base: 'h4', md: 'h3' }} ta={"center"}>
|
|
||||||
Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik
|
|
||||||
</Text>
|
|
||||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
|
||||||
{mounted && chartData.length > 0 && (
|
|
||||||
<BarChart width={isMobile ? 300 : isTablet ? 400 : 450} height={380} data={chartData} >
|
|
||||||
<XAxis dataKey="label" />
|
|
||||||
<YAxis />
|
|
||||||
<Tooltip />
|
|
||||||
<Legend style={{justifyContent: 'center'}} />
|
|
||||||
<Bar dataKey="kepuasan" fill={colors['blue-button']} name="Kepuasan" />
|
|
||||||
</BarChart>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GrafikHasilKepuasan;
|
|
||||||
@@ -1,47 +1,674 @@
|
|||||||
import colors from '@/con/colors';
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { Box, Paper, Stack, Text } from '@mantine/core';
|
"use client";
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import indeksKepuasanState from "@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan";
|
||||||
import GrafikBerdasarkanJenisKelamin from './grafik_berdasarkan_jenis_kelamin/page';
|
import colors from "@/con/colors";
|
||||||
import GrafikBerdasarkanResponden from './grafik_berdasarkan_pilihan_responden/page';
|
import { BarChart, PieChart } from '@mantine/charts';
|
||||||
import GrafikBerdasarakanUmur from './grafik_berdasarkan_umur_responden/page';
|
import { Box, Button, Center, Container, Flex, Group, Modal, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from "@mantine/core";
|
||||||
import GrafikHasilKepuasan from './grafik_hasil_kepuasan_masyarakat/page';
|
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useProxy } from "valtio/utils";
|
||||||
|
|
||||||
function Page() {
|
interface ChartDataItem {
|
||||||
|
name: string;
|
||||||
|
value: number;
|
||||||
|
color: string;
|
||||||
|
label?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function Kepuasan() {
|
||||||
|
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 }>>([]);
|
||||||
|
const [opened, { open, close }] = useDisclosure(false)
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
state.create.form = {
|
||||||
|
...state.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 state.create.create();
|
||||||
|
if (typeof id !== 'undefined') {
|
||||||
|
const idStr = String(id);
|
||||||
|
await state.findUnique.load(idStr);
|
||||||
|
}
|
||||||
|
resetForm();
|
||||||
|
close()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error submitting form:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load data on component mount
|
||||||
|
useShallowEffect(() => {
|
||||||
|
if (!data && !loading) {
|
||||||
|
state.findMany.load(1, 1000); // Load first page with a large limit to get all data
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
// 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) || !data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10} px="xl">
|
||||||
|
<Skeleton height={300} mb="md" />
|
||||||
|
<SimpleGrid cols={{ base: 1, md: 3 }}>
|
||||||
|
<Skeleton height={300} />
|
||||||
|
<Skeleton height={300} />
|
||||||
|
<Skeleton height={300} />
|
||||||
|
</SimpleGrid>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
return (
|
||||||
|
<Stack p="sm">
|
||||||
|
<Container w={{ base: "100%", md: "80%" }} p={"xl"}>
|
||||||
|
<Center>
|
||||||
|
<Text ta={"center"} fz={{ base: "2.4rem", md: "3.4rem" }}>Indeks Kepuasan Masyarakat</Text>
|
||||||
|
</Center>
|
||||||
|
<Center mt={10}>
|
||||||
|
<Button radius={"lg"} bg={colors["blue-button"]} onClick={open}>Ajukan Responden</Button>
|
||||||
|
</Center>
|
||||||
|
</Container>
|
||||||
|
<Box px={"xl"}>
|
||||||
|
<Paper p={"lg"} bg={colors.Bg}>
|
||||||
|
<Paper p={"lg"}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Flex justify={"space-between"} align={"center"}>
|
||||||
|
<Text fw={"bold"}>Pelayanan Terhadap Publik Desa Darmasaba</Text>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"sm"} fw={"bold"} c={colors["blue-button"]}>Total Responden</Text>
|
||||||
|
<Text ta={"end"} fz={"h1"} fw={"bold"} c={colors["blue-button"]}>
|
||||||
|
{state.findMany.total.toLocaleString('id-ID')}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
<BarChart
|
||||||
|
h={300}
|
||||||
|
data={barChartData}
|
||||||
|
dataKey="month"
|
||||||
|
series={[{ name: 'count', color: colors['blue-button'] }]}
|
||||||
|
tickLine="y"
|
||||||
|
xAxisLabel="Bulan"
|
||||||
|
yAxisLabel="Jumlah Responden"
|
||||||
|
withTooltip
|
||||||
|
tooltipAnimationDuration={200}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
<Box py={"xl"}>
|
||||||
|
<SimpleGrid
|
||||||
|
cols={{
|
||||||
|
base: 1,
|
||||||
|
md: 1,
|
||||||
|
lg: 1,
|
||||||
|
xl: 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>
|
||||||
|
) : (
|
||||||
|
<Paper p="md" radius="md" withBorder>
|
||||||
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
|
<Center>
|
||||||
|
<PieChart
|
||||||
|
withLabels
|
||||||
|
withTooltip
|
||||||
|
labelsType="percent"
|
||||||
|
size={200}
|
||||||
|
data={donutDataJenisKelamin}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<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>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</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>
|
||||||
|
) : (
|
||||||
|
<Paper p="md" radius="md" withBorder>
|
||||||
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
|
<Center>
|
||||||
|
<PieChart
|
||||||
|
withTooltip
|
||||||
|
tooltipAnimationDuration={200}
|
||||||
|
withLabels
|
||||||
|
labelsPosition="outside"
|
||||||
|
labelsType="percent"
|
||||||
|
withLabelsLine
|
||||||
|
size={200}
|
||||||
|
data={donutDataRating}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<Box mt="md" style={{ width: '100%' }}>
|
||||||
|
<SimpleGrid cols={2} spacing="xs" verticalSpacing="xs">
|
||||||
|
{donutDataRating.map((entry) => (
|
||||||
|
<Flex key={entry.name} gap="sm" align="center" style={{ overflow: 'hidden' }}>
|
||||||
|
<Box bg={entry.color} w={16} h={16} style={{ flexShrink: 0 }} />
|
||||||
|
<Text size="xs" lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||||
|
{entry.name}: {entry.value}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</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>
|
||||||
|
) : (
|
||||||
|
<Paper p="md" radius="md" withBorder>
|
||||||
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
|
<Center>
|
||||||
|
<PieChart
|
||||||
|
withTooltip
|
||||||
|
tooltipAnimationDuration={200}
|
||||||
|
withLabels
|
||||||
|
labelsPosition="outside"
|
||||||
|
labelsType="percent"
|
||||||
|
withLabelsLine
|
||||||
|
size={190}
|
||||||
|
data={donutDataKelompokUmur}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<Box mt="md" style={{ width: '100%' }}>
|
||||||
|
<SimpleGrid cols={2} spacing="xs" verticalSpacing="xs">
|
||||||
|
{donutDataKelompokUmur.map((entry) => (
|
||||||
|
<Flex key={entry.name} gap="sm" align="center" style={{ overflow: 'hidden' }}>
|
||||||
|
<Box bg={entry.color} w={16} h={16} style={{ flexShrink: 0 }} />
|
||||||
|
<Text size="xs" lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||||
|
{entry.name}: {entry.value}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</SimpleGrid>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
{/* Modal */}
|
||||||
|
<Modal opened={opened} onClose={close} title="Ajukan Responden" centered>
|
||||||
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
|
<Stack>
|
||||||
|
<TextInput
|
||||||
|
label="Nama"
|
||||||
|
type='text'
|
||||||
|
placeholder="masukkan nama"
|
||||||
|
value={state.create.form.name}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.create.form.name = val.currentTarget.value;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Tanggal"
|
||||||
|
type="date"
|
||||||
|
placeholder="masukkan tanggal"
|
||||||
|
value={state.create.form.tanggal}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.create.form.tanggal = val.currentTarget.value;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
key={"jenisKelamin"}
|
||||||
|
label={"Jenis Kelamin"}
|
||||||
|
placeholder={indeksKepuasanState.jenisKelaminResponden.findMany.loading ? 'Memuat...' : 'Pilih jenis kelamin'}
|
||||||
|
value={state.create.form.jenisKelaminId || ""}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.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={state.create.form.ratingId || ""}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.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={state.create.form.kelompokUmurId || ""}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.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>
|
||||||
|
</Modal>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack p={"sm"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Container w={{ base: "100%", md: "80%" }} p={"xl"}>
|
||||||
<BackButton />
|
<Stack gap={"xs"}>
|
||||||
</Box>
|
<Text ta={"center"} fz={{ base: "2.4rem", md: "3.4rem" }}>Indeks Kepuasan Masyarakat</Text>
|
||||||
<Box>
|
<Group justify={"center"}>
|
||||||
<Text ta={"center"} fz={{ base: "h2", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Button radius={"lg"} bg={colors["blue-button"]} onClick={open}>Ajukan Responden</Button>
|
||||||
Indeks Kepuasan Masyarakat (IKM)
|
</Group>
|
||||||
</Text>
|
</Stack>
|
||||||
<Text ta={"center"} fz={{ base: "h2", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
</Container>
|
||||||
Desa Darmasaba
|
<Box px={"xl"}>
|
||||||
</Text>
|
<Paper p={"lg"} bg={colors.Bg}>
|
||||||
</Box>
|
<Paper p={"lg"}>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Stack gap={"xs"}>
|
||||||
<Paper bg={colors['white-1']} p={'xl'}>
|
<Flex justify={"space-between"} align={"center"}>
|
||||||
<GrafikHasilKepuasan />
|
<Text fw={"bold"}>Pelayanan Terhadap Publik Desa Darmasaba</Text>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"sm"} fw={"bold"} c={colors["blue-button"]}>Total Responden</Text>
|
||||||
|
<Text ta={"end"} fz={"h1"} fw={"bold"} c={colors["blue-button"]}>
|
||||||
|
{state.findMany.total.toLocaleString('id-ID')}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
<BarChart
|
||||||
|
h={300}
|
||||||
|
data={barChartData}
|
||||||
|
dataKey="month"
|
||||||
|
series={[{ name: 'count', color: colors['blue-button'] }]}
|
||||||
|
tickLine="y"
|
||||||
|
xAxisLabel="Bulan"
|
||||||
|
yAxisLabel="Jumlah Responden"
|
||||||
|
withTooltip
|
||||||
|
tooltipAnimationDuration={200}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
<Box py={"xl"}>
|
||||||
|
<SimpleGrid
|
||||||
|
cols={{
|
||||||
|
base: 1,
|
||||||
|
md: 1,
|
||||||
|
lg: 1,
|
||||||
|
xl: 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>
|
||||||
|
) : (
|
||||||
|
<Paper p="md" radius="md" withBorder>
|
||||||
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
|
<Center>
|
||||||
|
<PieChart
|
||||||
|
withLabels
|
||||||
|
withTooltip
|
||||||
|
labelsType="percent"
|
||||||
|
size={200}
|
||||||
|
data={donutDataJenisKelamin}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<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>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</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>
|
||||||
|
) : (
|
||||||
|
<Paper p="md" radius="md" withBorder>
|
||||||
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
|
<Center>
|
||||||
|
<PieChart
|
||||||
|
withTooltip
|
||||||
|
tooltipAnimationDuration={200}
|
||||||
|
withLabels
|
||||||
|
labelsPosition="outside"
|
||||||
|
labelsType="percent"
|
||||||
|
withLabelsLine
|
||||||
|
size={200}
|
||||||
|
data={donutDataRating}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<Box mt="md" style={{ width: '100%' }}>
|
||||||
|
<SimpleGrid cols={2} spacing="xs" verticalSpacing="xs">
|
||||||
|
{donutDataRating.map((entry) => (
|
||||||
|
<Flex key={entry.name} gap="sm" align="center" style={{ overflow: 'hidden' }}>
|
||||||
|
<Box bg={entry.color} w={16} h={16} style={{ flexShrink: 0 }} />
|
||||||
|
<Text size="xs" lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||||
|
{entry.name}: {entry.value}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</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>
|
||||||
|
) : (
|
||||||
|
<Paper p="md" radius="md" withBorder>
|
||||||
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
|
<Center>
|
||||||
|
<PieChart
|
||||||
|
withTooltip
|
||||||
|
tooltipAnimationDuration={200}
|
||||||
|
withLabels
|
||||||
|
labelsPosition="outside"
|
||||||
|
labelsType="percent"
|
||||||
|
withLabelsLine
|
||||||
|
size={190}
|
||||||
|
data={donutDataKelompokUmur}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<Box mt="md" style={{ width: '100%' }}>
|
||||||
|
<SimpleGrid cols={2} spacing="xs" verticalSpacing="xs">
|
||||||
|
{donutDataKelompokUmur.map((entry) => (
|
||||||
|
<Flex key={entry.name} gap="sm" align="center" style={{ overflow: 'hidden' }}>
|
||||||
|
<Box bg={entry.color} w={16} h={16} style={{ flexShrink: 0 }} />
|
||||||
|
<Text size="xs" lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||||
|
{entry.name}: {entry.value}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</SimpleGrid>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
{/* Modal */}
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
<Modal opened={opened} onClose={close} title="Ajukan Responden" centered>
|
||||||
<GrafikBerdasarkanJenisKelamin/>
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
|
<Stack>
|
||||||
|
<TextInput
|
||||||
|
label="Nama"
|
||||||
|
type='text'
|
||||||
|
placeholder="masukkan nama"
|
||||||
|
value={state.create.form.name}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.create.form.name = val.currentTarget.value;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Tanggal"
|
||||||
|
type="date"
|
||||||
|
placeholder="masukkan tanggal"
|
||||||
|
value={state.create.form.tanggal}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.create.form.tanggal = val.currentTarget.value;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
key={"jenisKelamin"}
|
||||||
|
label={"Jenis Kelamin"}
|
||||||
|
placeholder={indeksKepuasanState.jenisKelaminResponden.findMany.loading ? 'Memuat...' : 'Pilih jenis kelamin'}
|
||||||
|
value={state.create.form.jenisKelaminId || ""}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.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={state.create.form.ratingId || ""}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.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={state.create.form.kelompokUmurId || ""}
|
||||||
|
onChange={(val) => {
|
||||||
|
state.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>
|
</Paper>
|
||||||
</Box>
|
</Modal>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
|
||||||
<GrafikBerdasarkanResponden/>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
|
||||||
<GrafikBerdasarakanUmur/>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Page;
|
export default Kepuasan;
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ const navbarListMenu = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.5",
|
id: "5.5",
|
||||||
name: "Jumlah Pengangguran 2024-2025",
|
name: "Jumlah Pengangguran",
|
||||||
href: "/darmasaba/ekonomi/jumlah-pengangguran-2024-2025"
|
href: "/darmasaba/ekonomi/jumlah-pengangguran"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.6",
|
id: "5.6",
|
||||||
@@ -207,8 +207,8 @@ const navbarListMenu = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.7",
|
id: "5.7",
|
||||||
name: "Jumlah Penduduk Miskin 2024-2025",
|
name: "Jumlah Penduduk Miskin",
|
||||||
href: "/darmasaba/ekonomi/jumlah-penduduk-miskin-2024-2025"
|
href: "/darmasaba/ekonomi/jumlah-penduduk-miskin"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.8",
|
id: "5.8",
|
||||||
|
|||||||
Reference in New Issue
Block a user