Compare commits
35 Commits
nico/18-au
...
nico/16-se
| Author | SHA1 | Date | |
|---|---|---|---|
| 39e1e7b575 | |||
| 4ceea5203f | |||
| a5d841bb6b | |||
| 6a7bd386ae | |||
| a9d98895bb | |||
| 75475dc62e | |||
| b39800a475 | |||
| 797713ef49 | |||
| 8817b937b1 | |||
| 2adf60f9eb | |||
| fa9601e126 | |||
| 7ae83788b4 | |||
| 22ec8d942d | |||
| 9f9a0fb451 | |||
| b6d6583e77 | |||
| a8fd715822 | |||
| f9530c32eb | |||
| f15ef5a275 | |||
| 3a726a3334 | |||
| b21e1f0c2e | |||
| f63249327d | |||
| bb8dab05ba | |||
| 3081e426bd | |||
| 8a275c2a32 | |||
| 8469ebd2e1 | |||
| 760ba4b6d2 | |||
| 20d4c90e60 | |||
| fafbb12a08 | |||
| 01aa0da5cc | |||
| b580978f8e | |||
| 1c01397c0d | |||
| 90a6605efd | |||
| c22d865283 | |||
| 49067f0218 | |||
| d79425d529 |
2
.gitignore
vendored
@@ -48,3 +48,5 @@ next-env.d.ts
|
||||
|
||||
.env.*
|
||||
|
||||
*.tar.gz
|
||||
|
||||
|
||||
15
package.json
@@ -3,11 +3,9 @@
|
||||
"version": "0.1.5",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"prisma:seed": "bun run prisma/seed.ts"
|
||||
"dev": "bun --bun next dev",
|
||||
"build": "bun --bun next build",
|
||||
"start": "bun --bun next start"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "bun run prisma/seed.ts"
|
||||
@@ -57,6 +55,8 @@
|
||||
"form-data": "^4.0.2",
|
||||
"framer-motion": "^12.23.5",
|
||||
"get-port": "^7.1.0",
|
||||
"iron-session": "^8.0.4",
|
||||
"jose": "^6.1.0",
|
||||
"jotai": "^2.12.3",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"leaflet": "^1.9.4",
|
||||
@@ -64,7 +64,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"motion": "^12.4.1",
|
||||
"nanoid": "^5.1.5",
|
||||
"next": "15.1.6",
|
||||
"next": "^15.5.2",
|
||||
"next-view-transitions": "^0.3.4",
|
||||
"node-fetch": "^3.3.2",
|
||||
"p-limit": "^6.2.0",
|
||||
@@ -73,15 +73,18 @@
|
||||
"prisma": "^6.3.1",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-international-phone": "^4.6.0",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-simple-toasts": "^6.1.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"readdirp": "^4.1.1",
|
||||
"recharts": "^2.15.3",
|
||||
"sharp": "^0.34.3",
|
||||
"swr": "^2.3.2",
|
||||
"uuid": "^11.1.0",
|
||||
"valtio": "^2.1.3",
|
||||
"zlib": "^1.0.5",
|
||||
"zod": "^3.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,51 +1,99 @@
|
||||
[
|
||||
{
|
||||
"month": "Jan",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 160,
|
||||
"educatedUnemployment": 95,
|
||||
"uneducatedUnemployment": 65,
|
||||
"percentageChange": null
|
||||
},
|
||||
{
|
||||
"month": "Feb",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 155,
|
||||
"educatedUnemployment": 90,
|
||||
"uneducatedUnemployment": 65,
|
||||
"percentageChange": -3.1
|
||||
},
|
||||
{
|
||||
"month": "Mar",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 150,
|
||||
"educatedUnemployment": 88,
|
||||
"uneducatedUnemployment": 62,
|
||||
"percentageChange": -3.2
|
||||
},
|
||||
{
|
||||
"month": "Apr",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 148,
|
||||
"educatedUnemployment": 85,
|
||||
"uneducatedUnemployment": 63,
|
||||
"percentageChange": -1.3
|
||||
},
|
||||
{
|
||||
"month": "Mei",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 145,
|
||||
"educatedUnemployment": 82,
|
||||
"uneducatedUnemployment": 63,
|
||||
"percentageChange": -2.0
|
||||
},
|
||||
{
|
||||
"month": "Jun",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 140,
|
||||
"educatedUnemployment": 80,
|
||||
"uneducatedUnemployment": 60,
|
||||
"percentageChange": -3.4
|
||||
}
|
||||
]
|
||||
{
|
||||
"month": "Jan",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 160,
|
||||
"educatedUnemployment": 95,
|
||||
"uneducatedUnemployment": 65,
|
||||
"percentageChange": 0.0
|
||||
},
|
||||
{
|
||||
"month": "Feb",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 158,
|
||||
"educatedUnemployment": 93,
|
||||
"uneducatedUnemployment": 65,
|
||||
"percentageChange": -1.25
|
||||
},
|
||||
{
|
||||
"month": "Mar",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 155,
|
||||
"educatedUnemployment": 91,
|
||||
"uneducatedUnemployment": 64,
|
||||
"percentageChange": -1.90
|
||||
},
|
||||
{
|
||||
"month": "Apr",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 152,
|
||||
"educatedUnemployment": 89,
|
||||
"uneducatedUnemployment": 63,
|
||||
"percentageChange": -1.94
|
||||
},
|
||||
{
|
||||
"month": "Mei",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 150,
|
||||
"educatedUnemployment": 88,
|
||||
"uneducatedUnemployment": 62,
|
||||
"percentageChange": -1.32
|
||||
},
|
||||
{
|
||||
"month": "Jun",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 148,
|
||||
"educatedUnemployment": 87,
|
||||
"uneducatedUnemployment": 61,
|
||||
"percentageChange": -1.33
|
||||
},
|
||||
{
|
||||
"month": "Jul",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 145,
|
||||
"educatedUnemployment": 85,
|
||||
"uneducatedUnemployment": 60,
|
||||
"percentageChange": -2.03
|
||||
},
|
||||
{
|
||||
"month": "Agu",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 142,
|
||||
"educatedUnemployment": 84,
|
||||
"uneducatedUnemployment": 58,
|
||||
"percentageChange": -2.07
|
||||
},
|
||||
{
|
||||
"month": "Sep",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 140,
|
||||
"educatedUnemployment": 83,
|
||||
"uneducatedUnemployment": 57,
|
||||
"percentageChange": -1.41
|
||||
},
|
||||
{
|
||||
"month": "Okt",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 138,
|
||||
"educatedUnemployment": 82,
|
||||
"uneducatedUnemployment": 56,
|
||||
"percentageChange": -1.43
|
||||
},
|
||||
{
|
||||
"month": "Nov",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 135,
|
||||
"educatedUnemployment": 80,
|
||||
"uneducatedUnemployment": 55,
|
||||
"percentageChange": -2.17
|
||||
},
|
||||
{
|
||||
"month": "Des",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 132,
|
||||
"educatedUnemployment": 78,
|
||||
"uneducatedUnemployment": 54,
|
||||
"percentageChange": -2.22
|
||||
}
|
||||
]
|
||||
|
||||
137
prisma/data/file-storage.json
Normal file
@@ -0,0 +1,137 @@
|
||||
[
|
||||
{
|
||||
"id": "cmff0rr4z0002vn0twp333m2",
|
||||
"name": "S6RIjFaPvdQm3oq4rM4X9-desktop.webp",
|
||||
"realName": "bares.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/S6RIjFaPvdQm3oq4rM4X9-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff0tnf00003vn0t3kgzi0u0",
|
||||
"name": "_pVNEmThU5ICGa8gv3gh_-desktop.webp",
|
||||
"realName": "bicara-darma.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/_pVNEmThU5ICGa8gv3gh_-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff0uykf0004vn0trmmxpgfh",
|
||||
"name": "bv6rdKvjxkkjUSGLQ0lvB-desktop.webp",
|
||||
"realName": "daves.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/bv6rdKvjxkkjUSGLQ0lvB-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff0z34f0005vn0tjtvq519p",
|
||||
"name": "Z4hWaV04CvoE20MjccQsV-desktop.webp",
|
||||
"realName": "mangan.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/Z4hWaV04CvoE20MjccQsV-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff38cyq000bvn0t9f01cz3f",
|
||||
"name": "LvLAtOqWojx4sn6NjJWB9-desktop.webp",
|
||||
"realName": "gelah-melah.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/LvLAtOqWojx4sn6NjJWB9-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff0zqvd0007vn0tv6o5hjcq",
|
||||
"name": "gR2mcvAQVgJ2-rM5coYJj-desktop.webp",
|
||||
"realName": "inovasi-desa-darmasaba.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/gR2mcvAQVgJ2-rM5coYJj-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff1013m0008vn0th7t0d64d",
|
||||
"name": "JpL-9F8-IGztMn8E2ce02-desktop.webp",
|
||||
"realName": "pdkt.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/JpL-9F8-IGztMn8E2ce02-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff10cwq0009vn0tse8dzu3j",
|
||||
"name": "bxAk4AsGbJTC705_IVdes-desktop.webp",
|
||||
"realName": "sajjiana-dharma-raksaka.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/bxAk4AsGbJTC705_IVdes-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff2w5ly000avn0telhct71k",
|
||||
"name": "Vbj_osnMJUkGEQGDTLwV--desktop.webp",
|
||||
"realName": "perbekel.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/Vbj_osnMJUkGEQGDTLwV--desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff3joae0000vn6h8sgs0ilg",
|
||||
"name": "7hox9spUxj56hY_EBYLnj-desktop.webp",
|
||||
"realName": "youtube.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/7hox9spUxj56hY_EBYLnj-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff3ll130001vn6hkhls3f5y",
|
||||
"name": "ChihV7_1eS-AGtSg9UwMv-desktop.webp",
|
||||
"realName": "gmail.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/ChihV7_1eS-AGtSg9UwMv-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff3mtat0002vn6hs8vyyhdd",
|
||||
"name": "z8v9ZREwOJHKGIRYauROt-desktop.webp",
|
||||
"realName": "facebook.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/z8v9ZREwOJHKGIRYauROt-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff3nv180003vn6h5jvedidq",
|
||||
"name": "BLjMxTKoCNE31uOURR3IU-desktop.webp",
|
||||
"realName": "telephone-call.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/BLjMxTKoCNE31uOURR3IU-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff3oouh0004vn6hd94brzv9",
|
||||
"name": "hkJYAeTNWK_vYaYS20w3I-desktop.webp",
|
||||
"realName": "instagram.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/hkJYAeTNWK_vYaYS20w3I-desktop.webp",
|
||||
"category": "image"
|
||||
},
|
||||
{
|
||||
"id": "cmff3q12g0005vn6h5ojov2qa",
|
||||
"name": "6XEoZ9SFu59COpil03Gya-desktop.webp",
|
||||
"realName": "tiktok.png",
|
||||
"path": "uploads/images",
|
||||
"mimeType": "image/webp",
|
||||
"link": "/api/fileStorage/findUnique/6XEoZ9SFu59COpil03Gya-desktop.webp",
|
||||
"category": "image"
|
||||
}
|
||||
]
|
||||
@@ -3,126 +3,108 @@
|
||||
"id": "cmds9h9ko000pvnberdjnx64b",
|
||||
"name": "1.1 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmds9sjmz000svnbesv2133of",
|
||||
"name": "1.2 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmds9tcpi000vvnbev3ebtlnt",
|
||||
"name": "1.3 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmds9twvj000yvnbep0pq8dzf",
|
||||
"name": "1.4 PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA",
|
||||
"deskripsi": "<p>PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmds9ugap0011vnbe118yv871",
|
||||
"name": "1.5 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa35310014vnbe6qy6l1rz",
|
||||
"name": "2.1 ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA",
|
||||
"deskripsi": "<p>ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa46590017vnbepp3noso1",
|
||||
"name": "2.2 ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH",
|
||||
"deskripsi": "<p>ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa5m7z001avnbe4cvfrcz0",
|
||||
"name": "2.3 TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI",
|
||||
"deskripsi": "<p>TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa8q5q001dvnbemch8j24x",
|
||||
"name": "3.1 ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT",
|
||||
"deskripsi": "<p>ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsa9lbi001gvnbequn2ba7m",
|
||||
"name": "3.2 ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA",
|
||||
"deskripsi": "<p>ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsaa7aq001jvnbeizh04e67",
|
||||
"name": "3.3 ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA",
|
||||
"deskripsi": "<p>ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsaaw8d001mvnbek3tfefrk",
|
||||
"name": "3.4 ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT",
|
||||
"deskripsi": "<p>ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsabhif001pvnbepm06hry6",
|
||||
"name": "3.5 ADANYA MAKLUMAT PELAYANAN",
|
||||
"deskripsi": "<p>ADANYA MAKLUMAT PELAYANAN</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||
},
|
||||
{
|
||||
"id": "cmdsag40b001svnbe7krq9khc",
|
||||
"name": "4.1 ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA",
|
||||
"deskripsi": "<p>ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||
},
|
||||
{
|
||||
"id": "cmdsagkaf001vvnbejo26w8sa",
|
||||
"name": "4.2 ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
"deskripsi": "<p>ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||
},
|
||||
{
|
||||
"id": "cmdsah4qe001yvnbeiy3mwrvb",
|
||||
"name": "4.3 ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA",
|
||||
"deskripsi": "<p>ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||
},
|
||||
{
|
||||
"id": "cmdsak5vn0021vnbemg86aab4",
|
||||
"name": "5.1 ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||
"deskripsi": "<p>ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99"
|
||||
},
|
||||
{
|
||||
"id": "cmdsalc800024vnbezgulhgrb",
|
||||
"name": "5.2 ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||
"deskripsi": "<p>ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
||||
"fileId": ""
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99"
|
||||
}
|
||||
]
|
||||
@@ -2,31 +2,37 @@
|
||||
{
|
||||
"id": "cmds8w2q60002vnbe6i8qhkuo",
|
||||
"name": "Telephone Desa Darmasaba",
|
||||
"iconUrl": "081239580000"
|
||||
"iconUrl": "081239580000",
|
||||
"imageId": "cmff3nv180003vn6h5jvedidq"
|
||||
},
|
||||
{
|
||||
"id": "cmds8z7u20005vnbegyyvnbk0",
|
||||
"name": "Email Desa Darmasaba",
|
||||
"iconUrl": "desadarmasaba@badungkab.go.id"
|
||||
"iconUrl": "desadarmasaba@badungkab.go.id",
|
||||
"imageId": "cmff3ll130001vn6hkhls3f5y"
|
||||
},
|
||||
{
|
||||
"id": "cmds9023u0008vnbe3oxmhwyf",
|
||||
"name": "Desa Darmasaba",
|
||||
"iconUrl": "https://www.youtube.com/channel/UCtPw9WOQO7d2HIKzKgel4Xg"
|
||||
"iconUrl": "https://www.youtube.com/channel/UCtPw9WOQO7d2HIKzKgel4Xg",
|
||||
"imageId": "cmff3joae0000vn6h8sgs0ilg"
|
||||
},
|
||||
{
|
||||
"id": "cmds90oul000bvnbe2bqkptoi",
|
||||
"name": "Pemerintah Desa Darmasaba",
|
||||
"iconUrl": "https://www.facebook.com/DarmasabaDesaku"
|
||||
"iconUrl": "https://www.facebook.com/DarmasabaDesaku",
|
||||
"imageId": "cmff3mtat0002vn6hs8vyyhdd"
|
||||
},
|
||||
{
|
||||
"id": "cmds91i4e000evnbe8gtf1gub",
|
||||
"name": "ddarmasaba",
|
||||
"iconUrl": "https://www.instagram.com/ddarmasaba/"
|
||||
"iconUrl": "https://www.instagram.com/ddarmasaba/",
|
||||
"imageId": "cmff3oouh0004vn6hd94brzv9"
|
||||
},
|
||||
{
|
||||
"id": "cmds92de5000hvnbemlu6sq5x",
|
||||
"name": "desa.darmasaba",
|
||||
"iconUrl": "https://www.tiktok.com/@desa.darmasaba?is_from_webapp=1&sender_device=pc"
|
||||
"iconUrl": "https://www.tiktok.com/@desa.darmasaba?is_from_webapp=1&sender_device=pc",
|
||||
"imageId": "cmff3q12g0005vn6h5ojov2qa"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
{
|
||||
"id": "edit",
|
||||
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
||||
"position": "Perbekel Darmasaba periode 2021-2027"
|
||||
"position": "Perbekel Darmasaba periode 2021-2027",
|
||||
"imageId": "cmff2w5ly000avn0telhct71k"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,50 +1,51 @@
|
||||
[
|
||||
{
|
||||
"id": "cmdr7039z0002vn5rttctt9hn",
|
||||
"name": "Davest",
|
||||
"description": "Darmasaba Village Festval",
|
||||
"link": "https://darmasaba.desa.id/berita/55862-rakor-davest-2024"
|
||||
},
|
||||
{
|
||||
"id": "cmdr755pf0005vn5rp8tyuubw",
|
||||
"name": "Dmangan",
|
||||
"description": "Darmasaba Aman Pangan",
|
||||
"link": "https://darmasaba.desa.id/berita/61452-kader-d-mangan-berhasil-meraih-prestasi-dalam-ajang-lomba-banjar-bali-quis-bbq-tahun-2024"
|
||||
"link": "https://darmasaba.desa.id/berita/61452-kader-d-mangan-berhasil-meraih-prestasi-dalam-ajang-lomba-banjar-bali-quis-bbq-tahun-2024",
|
||||
"imageId" : "cmff0z34f0005vn0tjtvq519p"
|
||||
},
|
||||
{
|
||||
"id": "cmdr76nqk0008vn5rdddvcxnr",
|
||||
"name": "Bicara Darmasaba",
|
||||
"description": "Bicara Darmasaba",
|
||||
"link": "https://darmasaba.desa.id/berita/42506-bicara-darmasaba"
|
||||
"link": "https://darmasaba.desa.id/berita/42506-bicara-darmasaba",
|
||||
"imageId" : "cmff0tnf00003vn0t3kgzi0u0"
|
||||
},
|
||||
{
|
||||
"id": "cmdr77vbw000bvn5rvpmoq31s",
|
||||
"name": "Bares",
|
||||
"description": "Darmasaba Recycling Stock/Exchange",
|
||||
"link": "http://darmasaba.desa.id/berita/56722-bares"
|
||||
"link": "http://darmasaba.desa.id/berita/56722-bares",
|
||||
"imageId" : "cmff0rr4z0002vn0twp333m2"
|
||||
},
|
||||
{
|
||||
"id": "cmdr7bxtp000evn5rmy85wihx",
|
||||
"name": "Sajjana Dharma Raksaka",
|
||||
"description": "Sajjana Dharma Raksaka",
|
||||
"link": "https://ppid.badungkab.go.id/storage/dokumen/5RS9dldGkrgzMQq6bKdZsqsVRHI8gffWv4PGfb3r.pdf"
|
||||
"link": "https://ppid.badungkab.go.id/storage/dokumen/5RS9dldGkrgzMQq6bKdZsqsVRHI8gffWv4PGfb3r.pdf",
|
||||
"imageId" : "cmff10cwq0009vn0tse8dzu3j"
|
||||
},
|
||||
{
|
||||
"id": "cmdr7dlnk000hvn5r9lur3z35",
|
||||
"name": "PDKT",
|
||||
"description": "Perangkat Desa Kuat Teknologi",
|
||||
"link": "https://darmasaba.desa.id/berita/53752-p-d-k-t"
|
||||
"link": "https://darmasaba.desa.id/berita/53752-p-d-k-t",
|
||||
"imageId" : "cmff1013m0008vn0th7t0d64d"
|
||||
},
|
||||
{
|
||||
"id": "cmdr7ftob000mvn5rfhgdtg8v",
|
||||
"name": "GM",
|
||||
"description": "Galah Melah",
|
||||
"link": "https://darmasaba.desa.id/berita/52880-galah-melah"
|
||||
"link": "https://darmasaba.desa.id/berita/52880-galah-melah",
|
||||
"imageId" : "cmff38cyq000bvn0t9f01cz3f"
|
||||
},
|
||||
{
|
||||
"id": "cmdr7glue000pvn5r6onzslju",
|
||||
"name": "Inovasi Desa Darmasaba",
|
||||
"description": "Inovasi Desa Darmasaba",
|
||||
"link": "https://darmasaba.desa.id/produk-lokal-desa"
|
||||
"link": "https://darmasaba.desa.id/produk-lokal-desa",
|
||||
"imageId" : "cmff0zqvd0007vn0tv6o5hjcq"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"jenisInformasi": "Peraturan Desa",
|
||||
"deskripsi": "Dokumen yang berisi kebijakan dan regulasi desa",
|
||||
"tanggal": "15 Januari 2024"
|
||||
"id": "cmeppcwzk0000vn5exmudcipd",
|
||||
"jenisInformasi": "Potensi Desa",
|
||||
"deskripsi": "<p>“Potensi desa adalah segenap sumber daya alam dan sumber daya manusia yang dimiliki desa sebagai modal dasar yang perlu dikelola dan dikembangkan bagi kelangsungan dan perkembangan desa. Adapun potensi yang dimiliki Desa Darmasaba yaitu:</p><ol><li><p>TPS3R Pudak Mesari</p></li><li><p>Bumdes Pudak Mesari</p></li><li><p>Pertanian</p></li><li><p>Jogging Track Tegeh Aban, Karang Gadon dan Munduk Uma Desa</p></li><li><p>Taman Beji Cengana</p></li><li><p>Dam Tanah Putih</p></li><li><p>Gumuh Sari Water Park</p></li><li><p>UMKM</p></li><li><p>Kawasan Kuliner</p></li><li><p>IKM berbasis Pengolahan Pangan</p></li><li><p>Genteng</p></li><li><p>Peternakan Ikan Lele</p></li><li><p>Pemotongan Daging”</p></li></ol>",
|
||||
"tanggal": "2021-05-25"
|
||||
},
|
||||
{
|
||||
"id": "cmeppieay0001vn5e8qe658ub",
|
||||
"jenisInformasi": "Layanan Surat Keterangan Desa",
|
||||
"deskripsi": "<p>“Desa Darmasaba menyediakan berbagai jenis layanan surat keterangan untuk kebutuhan administratif, antara lain:</p><ul><li><p>Surat Keterangan Domisili Organisasi</p></li><li><p>Surat Keterangan Penghasilan</p></li><li><p>Surat Keterangan Tidak Mampu</p></li><li><p>Surat Keterangan Kelahiran</p></li><li><p>Surat Keterangan Usaha</p></li><li><p>Surat Keterangan Tempat Usaha</p></li><li><p>Surat Keterangan Belum Kawin</p></li><li><p>Surat Keterangan Kelakuan Baik (Pengantar SKCK)</p></li><li><p>Surat Keterangan Kematian</p></li><li><p>Surat Keterangan Perbedaan Biodata Diri</p></li><li><p>Surat Keterangan Yatim/Piatu/Yatim Piatu<br>Untuk surat keterangan lainnya, masyarakat dapat berkonsultasi langsung ke kantor Perbekel Darmasaba.”<br><em>(Sumber: Laman Layanan Desa Darmasaba)</em></p></li></ul>",
|
||||
"tanggal": "2025-02-21"
|
||||
}
|
||||
]
|
||||
@@ -1,6 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": "cmdpm429r0000vnndkcwslt0h",
|
||||
"name": "warga"
|
||||
}
|
||||
]
|
||||
29
prisma/data/user/roles.json
Normal file
@@ -0,0 +1,29 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"name": "ADMIN DESA",
|
||||
"description": "Administrator Desa",
|
||||
"permissions": ["manage_users", "manage_content", "view_reports"],
|
||||
"isActive": true,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "ADMIN KESEHATAN",
|
||||
"description": "Administrator Bidang Kesehatan",
|
||||
"permissions": ["manage_health_data", "view_reports"],
|
||||
"isActive": true,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"name": "ADMIN SEKOLAH",
|
||||
"description": "Administrator Sekolah",
|
||||
"permissions": ["manage_school_data", "view_reports"],
|
||||
"isActive": true,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
}
|
||||
]
|
||||
32
prisma/data/user/users.json
Normal file
@@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"nama": "Admin Desa",
|
||||
"nomor": "089647037426",
|
||||
"roleId": "1",
|
||||
"isActive": true,
|
||||
"lastLogin": "2025-08-31T10:00:00.000Z",
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"nama": "Admin Kesehatan",
|
||||
"nomor": "082339004198",
|
||||
"roleId": "2",
|
||||
"isActive": true,
|
||||
"lastLogin": null,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"nama": "Admin Sekolah",
|
||||
"nomor": "085237157222",
|
||||
"roleId": "3",
|
||||
"isActive": true,
|
||||
"lastLogin": null,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
}
|
||||
]
|
||||
@@ -85,7 +85,6 @@ model FileStorage {
|
||||
KontakItem KontakItem[]
|
||||
Pegawai Pegawai[]
|
||||
DesaDigital DesaDigital[]
|
||||
KolaborasiInovasi KolaborasiInovasi[]
|
||||
InfoTekno InfoTekno[]
|
||||
PengaduanMasyarakat PengaduanMasyarakat[]
|
||||
KegiatanDesa KegiatanDesa[]
|
||||
@@ -93,13 +92,15 @@ model FileStorage {
|
||||
PejabatDesa PejabatDesa[]
|
||||
MediaSosial MediaSosial[]
|
||||
DesaAntiKorupsi DesaAntiKorupsi[]
|
||||
SDGSDesa SDGSDesa[]
|
||||
SDGSDesa SdgsDesa[]
|
||||
APBDesImage APBDes[] @relation("APBDesImage")
|
||||
APBDesFile APBDes[] @relation("APBDesFile")
|
||||
PrestasiDesa PrestasiDesa[]
|
||||
DataPerpustakaan DataPerpustakaan[]
|
||||
PegawaiPPID PegawaiPPID[]
|
||||
PerbekelDariMasaKeMasa PerbekelDariMasaKeMasa[]
|
||||
|
||||
MitraKolaborasi MitraKolaborasi[]
|
||||
}
|
||||
|
||||
//========================================= MENU LANDING PAGE ========================================= //
|
||||
@@ -167,9 +168,9 @@ model KategoriDesaAntiKorupsi {
|
||||
}
|
||||
|
||||
//========================================= SDGS Desa ========================================= //
|
||||
model SDGSDesa {
|
||||
model SdgsDesa {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
name String
|
||||
jumlah String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
@@ -182,7 +183,7 @@ model SDGSDesa {
|
||||
//========================================= APBDes ========================================= //
|
||||
model APBDes {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
name String
|
||||
jumlah String
|
||||
image FileStorage? @relation("APBDesImage", fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
@@ -197,12 +198,12 @@ model APBDes {
|
||||
//========================================= PRESTASI DESA ========================================= //
|
||||
model PrestasiDesa {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
name String
|
||||
deskripsi String @db.Text
|
||||
kategori KategoriPrestasiDesa @relation(fields: [kategoriId], references: [id])
|
||||
kategoriId String
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
@@ -223,7 +224,7 @@ model KategoriPrestasiDesa {
|
||||
model Responden {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
tanggal DateTime // misal: 2025-05-01
|
||||
tanggal DateTime @db.Date // misal: 2025-05-01
|
||||
jenisKelamin JenisKelaminResponden @relation(fields: [jenisKelaminId], references: [id])
|
||||
jenisKelaminId String
|
||||
rating PilihanRatingResponden @relation(fields: [ratingId], references: [id])
|
||||
@@ -292,6 +293,9 @@ model PosisiOrganisasiPPID {
|
||||
pegawai PegawaiPPID[]
|
||||
strukturOrganisasi StrukturPPID[] // Relasi balik
|
||||
parentId String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
||||
children PosisiOrganisasiPPID[] @relation("Parent")
|
||||
}
|
||||
@@ -1212,25 +1216,40 @@ model LayananPolsek {
|
||||
|
||||
// ========================================= KONTAK DARURAT ========================================= //
|
||||
model KontakDaruratKeamanan {
|
||||
id String @id @default(uuid())
|
||||
nama String // contoh: "Layanan Darurat", "Fasilitas Kesehatan"
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
id String @id @default(uuid())
|
||||
nama String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
kontakItems KontakItem[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
kategori KontakItem @relation(fields: [kategoriId], references: [id])
|
||||
kategoriId String
|
||||
kontakItems KontakDaruratToItem[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model KontakItem {
|
||||
id String @id @default(uuid())
|
||||
nama String // contoh: "Polisi", "Ambulans", "Puskesmas Darmasaba"
|
||||
nomorTelepon String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
kategori KontakDaruratKeamanan @relation(fields: [kategoriId], references: [id])
|
||||
kategoriId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
id String @id @default(uuid())
|
||||
nama String
|
||||
nomorTelepon String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
KontakDaruratToItem KontakDaruratToItem[]
|
||||
KontakDaruratKeamanan KontakDaruratKeamanan[]
|
||||
}
|
||||
|
||||
model KontakDaruratToItem {
|
||||
id String @id @default(uuid())
|
||||
kontakDaruratId String
|
||||
kontakItemId String
|
||||
kontakDarurat KontakDaruratKeamanan @relation(fields: [kontakDaruratId], references: [id])
|
||||
kontakItem KontakItem @relation(fields: [kontakItemId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
// ========================================= PENCEGAHAN KRIMINALITAS ========================================= //
|
||||
@@ -1397,6 +1416,9 @@ model PosisiOrganisasi {
|
||||
pegawai Pegawai[]
|
||||
strukturOrganisasi StrukturOrganisasi[] // Relasi balik
|
||||
StrukturOrganisasiPPID StrukturOrganisasiPPID[]
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("posisi_organisasi")
|
||||
}
|
||||
@@ -1465,7 +1487,7 @@ model ProgramKemiskinan {
|
||||
id String @id @default(uuid())
|
||||
nama String
|
||||
deskripsi String
|
||||
ikonUrl String?
|
||||
icon String
|
||||
isActive Boolean @default(true)
|
||||
statistikId String? @unique
|
||||
statistik StatistikKemiskinan? @relation(fields: [statistikId], references: [id])
|
||||
@@ -1635,18 +1657,27 @@ model ProgramKreatif {
|
||||
|
||||
// ========================================= KOLABORASI INOVASI ========================================= //
|
||||
model KolaborasiInovasi {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
tahun Int
|
||||
slug String @db.Text //deskripsi singkat
|
||||
deskripsi String @db.Text //deskripsi panjang
|
||||
slug String @db.Text //deskripsi singkat
|
||||
deskripsi String @db.Text //deskripsi panjang
|
||||
kolaborator String
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model MitraKolaborasi {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
// ========================================= INFO TEKHNOLOGI TEPAT GUNA ========================================= //
|
||||
@@ -2090,26 +2121,66 @@ model KategoriBuku {
|
||||
DataPerpustakaan DataPerpustakaan[]
|
||||
}
|
||||
|
||||
// ========================================= USER ========================================= //
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
nama String
|
||||
email String @unique
|
||||
password String
|
||||
role Role @relation(fields: [roleId], references: [id])
|
||||
roleId String
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
id String @id @default(cuid())
|
||||
username String
|
||||
nomor String @unique
|
||||
role Role @relation(fields: [roleId], references: [id])
|
||||
roleId String @default("1")
|
||||
instansi String?
|
||||
UserSession UserSession? // Nama instansi (Puskesmas, Sekolah, dll)
|
||||
isActive Boolean @default(true)
|
||||
lastLogin DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
}
|
||||
|
||||
model Role {
|
||||
id String @id @default(cuid())
|
||||
name String @unique // ADMIN_DESA, ADMIN_KESEHATAN, ADMIN_SEKOLAH
|
||||
description String?
|
||||
permissions Json // Menyimpan permission dalam format JSON
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
users User[]
|
||||
|
||||
@@map("roles")
|
||||
}
|
||||
|
||||
model KodeOtp {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
User User[]
|
||||
nomor String
|
||||
otp Int
|
||||
}
|
||||
|
||||
// Tabel untuk menyimpan permission
|
||||
model Permission {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
description String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("permissions")
|
||||
}
|
||||
|
||||
model UserSession {
|
||||
id String @id @default(cuid())
|
||||
token String
|
||||
expires DateTime?
|
||||
active Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
User User @relation(fields: [userId], references: [id])
|
||||
userId String @unique
|
||||
}
|
||||
|
||||
// ========================================= DATA PENDIDIKAN ========================================= //
|
||||
|
||||
441
prisma/seed.ts
@@ -1,68 +1,160 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import prisma from "@/lib/prisma";
|
||||
import profilePejabatDesa from "./data/landing-page/profile/profile.json";
|
||||
import penghargaan from "./data/landing-page/penghargaan/penghargaan.json";
|
||||
import programInovasi from "./data/landing-page/profile/programInovasi.json";
|
||||
import mediaSosial from "./data/landing-page/profile/mediaSosial.json";
|
||||
import desaAntiKorupsi from "./data/landing-page/desa-anti-korupsi/desaantiKorpusi.json";
|
||||
import kategoriDesaAntiKorupsi from "./data/landing-page/desa-anti-korupsi/kategoriDesaAntiKorupsi.json";
|
||||
import sdgsDesa from "./data/landing-page/sdgs-desa/sdgs-desa.json";
|
||||
import apbdes from "./data/landing-page/apbdes/apbdes.json";
|
||||
import pelayananSuratKeterangan from "./data/desa/layanan/pelayananSuratKeterangan.json";
|
||||
import categoryPengumuman from "./data/category-pengumuman.json";
|
||||
import kategoriBerita from "./data/kategori-berita.json";
|
||||
import caraMemperolehInformasi from "./data/list-caraMemperolehInformasi.json";
|
||||
import caraMemperolehSalinanInformasi from "./data/list-caraMemperolehSalinanInformasi.json";
|
||||
import jenisInformasiDiminta from "./data/list-jenisInfromasi.json";
|
||||
import layanan from "./data/list-layanan.json";
|
||||
import potensi from "./data/list-potensi.json";
|
||||
import dasarHukumPPID from "./data/ppid/dasar-hukum-ppid/dasarhukumPPID.json";
|
||||
import kategoriPrestasiDesa from "./data/landing-page/prestasi-desa/kategori-prestasi.json";
|
||||
import prestasiDesa from "./data/landing-page/prestasi-desa/prestasi-desa.json";
|
||||
import penghargaan from "./data/landing-page/penghargaan/penghargaan.json";
|
||||
import profilePPID from "./data/ppid/profile-ppid/profilePPid.json";
|
||||
import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
import posisiOrganisasiPPID from "./data/ppid/struktur-ppid/posisi-organisasi-PPID.json";
|
||||
import visiMisiPPID from "./data/ppid/visi-misi-ppid/visimisiPPID.json";
|
||||
import dasarHukumPPID from "./data/ppid/dasar-hukum-ppid/dasarhukumPPID.json";
|
||||
import jenisKelamin from "./data/ppid/ikm/jenis-kelamin/jenis-kelamin.json";
|
||||
import daftarInformasiPublik from "./data/ppid/daftar-informasi-publik-desa-darmasaba/daftarInformasi.json";
|
||||
import pilihanRatingResponden from "./data/ppid/ikm/pilihan-rating-responden/rating-responden.json";
|
||||
import umurResponden from "./data/ppid/ikm/umur-responden/umur-responden.json";
|
||||
import categoryPengumuman from "./data/category-pengumuman.json";
|
||||
import pelayananPerizinanBerusaha from "./data/desa/layanan/pelayananPerizinanBerusaha.json";
|
||||
import pelayananSuratKeterangan from "./data/desa/layanan/pelayananSuratKeterangan.json";
|
||||
import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSaktiDesa.json";
|
||||
import pelayananPendudukNonPermanen from "./data/desa/layanan/pelayanaPendudukNonPermanen.json";
|
||||
import sejarahDesa from "./data/desa/profile/sejarah_desa.json";
|
||||
import visiMisiDesa from "./data/desa/profile/visi_misi_desa.json";
|
||||
import lambangDesa from "./data/desa/profile/lambang_desa.json";
|
||||
import maskotDesa from "./data/desa/profile/maskot_desa.json";
|
||||
import profilPerbekel from "./data/desa/profile/profil_perbekel.json";
|
||||
import sejarahDesa from "./data/desa/profile/sejarah_desa.json";
|
||||
import visiMisiDesa from "./data/desa/profile/visi_misi_desa.json";
|
||||
import detailDataPengangguran from "./data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json";
|
||||
import kategoriProduk from "./data/ekonomi/pasar-desa/kategori-produk.json";
|
||||
import hubunganOrganisasi from "./data/ekonomi/struktur-organisasi/hubungan-organisasi.json";
|
||||
import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json";
|
||||
import pegawai from "./data/ekonomi/struktur-organisasi/pegawai.json";
|
||||
import detailDataPengangguran from "./data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json";
|
||||
import tujuanEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
|
||||
import materiEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
|
||||
import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json";
|
||||
import kategoriBerita from "./data/kategori-berita.json";
|
||||
import contohEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/contoh-kegiatan-di-desa-darmasaba.json";
|
||||
import nilaiKonservasiAdat from "./data/lingkungan/konservasi-adat-bali/nilai-konservasi-adat.json";
|
||||
import materiEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
|
||||
import tujuanEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
|
||||
import bentukKonservasiBerdasarkanAdat from "./data/lingkungan/konservasi-adat-bali/bentuk-konservasi.json";
|
||||
import filosofiTriHita from "./data/lingkungan/konservasi-adat-bali/filosofi-tri-hita.json";
|
||||
import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
||||
import nilaiKonservasiAdat from "./data/lingkungan/konservasi-adat-bali/nilai-konservasi-adat.json";
|
||||
import caraMemperolehInformasi from "./data/list-caraMemperolehInformasi.json";
|
||||
import caraMemperolehSalinanInformasi from "./data/list-caraMemperolehSalinanInformasi.json";
|
||||
import jenisInformasiDiminta from "./data/list-jenisInfromasi.json";
|
||||
import potensi from "./data/list-potensi.json";
|
||||
import fasilitasBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json";
|
||||
import lokasiJadwalBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json";
|
||||
import tujuanBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json";
|
||||
import jenisProgramYangDiselenggarakan from "./data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json";
|
||||
import tempatKegiatan from "./data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json";
|
||||
import tujuanProgram2 from "./data/pendidikan/pendidikan-non-formal/tujuan-program2.json";
|
||||
import programUnggulan from "./data/pendidikan/program-pendidikan-anak/program-unggulan.json";
|
||||
import tujuanBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json";
|
||||
import lokasiJadwalBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json";
|
||||
import fasilitasBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json";
|
||||
import tempatKegiatan from "./data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json";
|
||||
import jenisProgramYangDiselenggarakan from "./data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json";
|
||||
import posisiOrganisasiPPID from "./data/ppid/struktur-ppid/posisi-organisasi-PPID.json";
|
||||
import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSaktiDesa.json";
|
||||
import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
||||
import roles from "./data/user/roles.json";
|
||||
import users from "./data/user/users.json";
|
||||
import fileStorage from "./data/file-storage.json";
|
||||
|
||||
(async () => {
|
||||
// =========== USER & ROLE ===========
|
||||
// In your seed.ts
|
||||
// =========== ROLES ===========
|
||||
console.log("🔄 Seeding roles...");
|
||||
for (const r of roles) {
|
||||
await prisma.role.upsert({
|
||||
where: { id: r.id },
|
||||
update: {
|
||||
name: r.name,
|
||||
description: r.description,
|
||||
permissions: r.permissions,
|
||||
isActive: r.isActive,
|
||||
},
|
||||
create: {
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
description: r.description,
|
||||
permissions: r.permissions,
|
||||
isActive: r.isActive,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Roles seeded");
|
||||
|
||||
// =========== USERS ===========
|
||||
console.log("🔄 Seeding users...");
|
||||
for (const u of users) {
|
||||
// First verify the role exists
|
||||
const roleExists = await prisma.role.findUnique({
|
||||
where: { id: u.roleId },
|
||||
});
|
||||
|
||||
if (!roleExists) {
|
||||
console.error(`❌ Role with id ${u.roleId} not found for user ${u.nama}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await prisma.user.upsert({
|
||||
where: { id: u.id },
|
||||
update: {
|
||||
username: u.nama,
|
||||
nomor: u.nomor,
|
||||
roleId: u.roleId,
|
||||
isActive: u.isActive,
|
||||
},
|
||||
create: {
|
||||
id: u.id,
|
||||
username: u.nama,
|
||||
nomor: u.nomor,
|
||||
roleId: u.roleId,
|
||||
isActive: u.isActive,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Users seeded");
|
||||
|
||||
// =========== FILE STORAGE ===========
|
||||
console.log("🔄 Seeding file storage...");
|
||||
for (const f of fileStorage) {
|
||||
await prisma.fileStorage.upsert({
|
||||
where: { id: f.id },
|
||||
update: {
|
||||
name: f.name,
|
||||
realName: f.realName,
|
||||
path: f.path,
|
||||
mimeType: f.mimeType,
|
||||
link: f.link,
|
||||
category: f.category,
|
||||
},
|
||||
create: {
|
||||
id: f.id,
|
||||
name: f.name,
|
||||
realName: f.realName,
|
||||
path: f.path,
|
||||
mimeType: f.mimeType,
|
||||
link: f.link,
|
||||
category: f.category,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ File storage seeded");
|
||||
// =========== LANDING PAGE ===========
|
||||
// =========== PROFILE ===========
|
||||
// =========== SUBMENU PROFILE ===========
|
||||
// =========== PROFILE PEJABAT DESA ===========
|
||||
for (const p of profilePejabatDesa) {
|
||||
await prisma.pejabatDesa.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
position: p.position,
|
||||
imageId: p.imageId,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
position: p.position,
|
||||
imageId: p.imageId,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -72,18 +164,35 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
// =========== PROGRAM INOVASI ===========
|
||||
for (const p of programInovasi) {
|
||||
let imageId: string | null = null;
|
||||
|
||||
if (p.imageId) {
|
||||
const imageExists = await prisma.fileStorage.findUnique({
|
||||
where: { id: p.imageId },
|
||||
});
|
||||
|
||||
if (imageExists) {
|
||||
imageId = p.imageId;
|
||||
} else {
|
||||
console.warn(
|
||||
`⚠️ imageId ${p.imageId} tidak ditemukan untuk ProgramInovasi ${p.name}`
|
||||
);
|
||||
}
|
||||
}
|
||||
await prisma.programInovasi.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
description: p.description,
|
||||
link: p.link,
|
||||
imageId: p.imageId,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
description: p.description,
|
||||
link: p.link,
|
||||
imageId: p.imageId,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -96,16 +205,102 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
update: {
|
||||
name: p.name,
|
||||
iconUrl: p.iconUrl,
|
||||
imageId: p.imageId,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
iconUrl: p.iconUrl,
|
||||
imageId: p.imageId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("media sosial success ...");
|
||||
|
||||
// =========== SUBMENU DESA ANTI KORUPSI ===========
|
||||
// =========== KATEGORI DESA ANTI KORUPSI ===========
|
||||
for (const k of kategoriDesaAntiKorupsi) {
|
||||
await prisma.kategoriDesaAntiKorupsi.upsert({
|
||||
where: { id: k.id },
|
||||
update: {
|
||||
name: k.name,
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
name: k.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("kategori desa anti korupsi success ...");
|
||||
|
||||
// =========== DESA ANTI KORUPSI ===========
|
||||
for (const p of desaAntiKorupsi) {
|
||||
await prisma.desaAntiKorupsi.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
deskripsi: p.deskripsi,
|
||||
kategoriId: p.kategoriId,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
deskripsi: p.deskripsi,
|
||||
kategoriId: p.kategoriId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("desa anti korupsi success ...");
|
||||
|
||||
// =========== KATEGORI DESA ANTI KORUPSI ===========
|
||||
for (const p of kategoriDesaAntiKorupsi) {
|
||||
await prisma.kategoriDesaAntiKorupsi.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("desa anti korupsi success ...");
|
||||
|
||||
// =========== KATEGORI PRESTASI DESA===========
|
||||
for (const c of kategoriPrestasiDesa) {
|
||||
await prisma.kategoriPrestasiDesa.upsert({
|
||||
where: { id: c.id },
|
||||
update: {
|
||||
name: c.name,
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("kategori prestasi desa success ...");
|
||||
|
||||
// =========== PRESTASI DESA===========
|
||||
for (const p of prestasiDesa) {
|
||||
await prisma.prestasiDesa.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
deskripsi: p.deskripsi,
|
||||
kategoriId: p.kategoriId,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
deskripsi: p.deskripsi,
|
||||
kategoriId: p.kategoriId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("prestasi desa success ...");
|
||||
|
||||
// =========== PENGHARGAAN ===========
|
||||
for (const p of penghargaan) {
|
||||
await prisma.penghargaan.upsert({
|
||||
@@ -160,30 +355,10 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
}
|
||||
console.log("pelayanan surat keterangan success ...");
|
||||
|
||||
// =========== LAYANAN ===========
|
||||
for (const l of layanan) {
|
||||
await prisma.layanan.upsert({
|
||||
where: {
|
||||
name: l.name,
|
||||
},
|
||||
update: {
|
||||
name: l.name,
|
||||
},
|
||||
create: {
|
||||
name: l.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("layanan success ...");
|
||||
|
||||
// =========== SDGSDesa ===========
|
||||
for (const l of sdgsDesa) {
|
||||
await prisma.sDGSDesa.upsert({
|
||||
where: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
await prisma.sdgsDesa.upsert({
|
||||
where: { id: l.id },
|
||||
update: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
@@ -201,8 +376,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
for (const l of apbdes) {
|
||||
await prisma.aPBDes.upsert({
|
||||
where: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
id: l.id,
|
||||
},
|
||||
update: {
|
||||
name: l.name,
|
||||
@@ -217,6 +391,9 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("sdgs desa success ...");
|
||||
|
||||
// =========== MENU DESA ===========
|
||||
// =========== SUBMENU PROFILE ===========
|
||||
// =========== SEJARAH DESA ===========
|
||||
for (const l of sejarahDesa) {
|
||||
await prisma.sejarahDesa.upsert({
|
||||
where: {
|
||||
@@ -236,6 +413,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("sejarah desa success ...");
|
||||
|
||||
// =========== MASKOT DESA ===========
|
||||
for (const l of maskotDesa) {
|
||||
await prisma.maskotDesa.upsert({
|
||||
where: {
|
||||
@@ -255,6 +433,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("maskot desa success ...");
|
||||
|
||||
// =========== LAMBANG DESA ===========
|
||||
for (const l of lambangDesa) {
|
||||
await prisma.lambangDesa.upsert({
|
||||
where: {
|
||||
@@ -274,6 +453,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("lambang desa success ...");
|
||||
|
||||
// =========== PROFIL PERBEKEL ===========
|
||||
for (const c of profilPerbekel) {
|
||||
await prisma.profilPerbekel.upsert({
|
||||
where: { id: c.id },
|
||||
@@ -298,6 +478,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
"✅ profilePerbekel seeded without imageId (editable later via UI)"
|
||||
);
|
||||
|
||||
// =========== VISI MISI DESA ===========
|
||||
for (const l of visiMisiDesa) {
|
||||
await prisma.visiMisiDesa.upsert({
|
||||
where: {
|
||||
@@ -317,6 +498,35 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
|
||||
console.log("visi misi desa success ...");
|
||||
|
||||
// =========== MENU PPID ===========
|
||||
// =========== SUBMENU PROFILE PPID ===========
|
||||
for (const c of profilePPID) {
|
||||
await prisma.profilePPID.upsert({
|
||||
where: { id: c.id },
|
||||
update: {
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
// imageId tidak di-update
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
// imageId tidak di-create
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ profilePPID seeded without imageId (editable later via UI)");
|
||||
|
||||
// =========== SUBMENU STRUKTUR PPID ===========
|
||||
// =========== POSISI ORGANISASI PPID ===========
|
||||
|
||||
const flattenedPosisi = posisiOrganisasiPPID.flat();
|
||||
|
||||
// ✅ Urutkan berdasarkan hierarki
|
||||
@@ -341,9 +551,9 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
create: p,
|
||||
});
|
||||
}
|
||||
console.log("✅ Posisi organisasi berhasil");
|
||||
console.log("posisi organisasi berhasil");
|
||||
|
||||
// 2. Seed Pegawai
|
||||
// =========== PEGAWAI PPID ===========
|
||||
const flattenedPegawai = pegawaiPPID.flat();
|
||||
for (const p of flattenedPegawai) {
|
||||
await prisma.pegawaiPPID.upsert({
|
||||
@@ -352,7 +562,70 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
create: p,
|
||||
});
|
||||
}
|
||||
console.log("✅ Pegawai berhasil");
|
||||
console.log("pegawai berhasil");
|
||||
|
||||
// =========== SUBMENU VISI MISI PPID ===========
|
||||
|
||||
for (const v of visiMisiPPID) {
|
||||
await prisma.visiMisiPPID.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
misi: v.misi,
|
||||
visi: v.visi,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
misi: v.misi,
|
||||
visi: v.visi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("visi misi PPID success ...");
|
||||
|
||||
// =========== SUBMENU DASAR HUKUM PPID ===========
|
||||
for (const v of dasarHukumPPID) {
|
||||
await prisma.dasarHukumPPID.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
judul: v.judul,
|
||||
content: v.content,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
judul: v.judul,
|
||||
content: v.content,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("dasar hukum PPID success ...");
|
||||
|
||||
// =========== SUBMENU DAFTAR INFORMASI PUBLIK PPID ===========
|
||||
for (const v of daftarInformasiPublik) {
|
||||
// Convert string date to Date object
|
||||
const tanggal = new Date(v.tanggal);
|
||||
|
||||
await prisma.daftarInformasiPublik.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
jenisInformasi: v.jenisInformasi,
|
||||
deskripsi: v.deskripsi,
|
||||
tanggal: tanggal,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
jenisInformasi: v.jenisInformasi,
|
||||
deskripsi: v.deskripsi,
|
||||
tanggal: tanggal,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("daftar informasi publik PPID success ...");
|
||||
|
||||
for (const l of pelayananPerizinanBerusaha) {
|
||||
await prisma.pelayananPerizinanBerusaha.upsert({
|
||||
@@ -486,48 +759,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
}
|
||||
console.log("cara memperoleh salinan informasi success ...");
|
||||
|
||||
for (const c of profilePPID) {
|
||||
await prisma.profilePPID.upsert({
|
||||
where: { id: c.id },
|
||||
update: {
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
// imageId tidak di-update
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
// imageId tidak di-create
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ profilePPID seeded without imageId (editable later via UI)");
|
||||
|
||||
for (const v of visiMisiPPID) {
|
||||
await prisma.visiMisiPPID.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
misi: v.misi,
|
||||
visi: v.visi,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
misi: v.misi,
|
||||
visi: v.visi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("visi misi PPID success ...");
|
||||
|
||||
for (const j of jenisKelamin) {
|
||||
await prisma.jenisKelaminResponden.upsert({
|
||||
where: {
|
||||
@@ -576,24 +807,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
||||
}
|
||||
console.log("umur responden success ...");
|
||||
|
||||
for (const v of dasarHukumPPID) {
|
||||
await prisma.dasarHukumPPID.upsert({
|
||||
where: {
|
||||
id: v.id,
|
||||
},
|
||||
update: {
|
||||
judul: v.judul,
|
||||
content: v.content,
|
||||
},
|
||||
create: {
|
||||
id: v.id,
|
||||
judul: v.judul,
|
||||
content: v.content,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("dasar hukum PPID success ...");
|
||||
|
||||
for (const k of kategoriProduk) {
|
||||
await prisma.kategoriProduk.upsert({
|
||||
where: {
|
||||
|
||||
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
BIN
public/chatbot-removebg-preview.png
Normal file
|
After Width: | Height: | Size: 303 KiB |
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 266 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 275 KiB |
@@ -23,6 +23,7 @@ export default function SpashScreen() {
|
||||
<Paper p={"md"} miw={320}>
|
||||
<Flex>
|
||||
<Image
|
||||
loading="lazy"
|
||||
src={images["darmasaba-icon"]}
|
||||
alt="darmasaba"
|
||||
w={100}
|
||||
|
||||
62
src/app/admin/(dashboard)/_com/LeafletMultiMarkerMap.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client';
|
||||
|
||||
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
|
||||
import { LatLngExpression } from 'leaflet';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import L from 'leaflet';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
type MarkerData = {
|
||||
position: [number, number];
|
||||
popup: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
center: [number, number];
|
||||
markers: MarkerData[];
|
||||
zoom?: number;
|
||||
scrollWheelZoom?: boolean;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
};
|
||||
|
||||
export default function LeafletMultiMarkerMap({
|
||||
center,
|
||||
markers,
|
||||
zoom = 13,
|
||||
scrollWheelZoom = true,
|
||||
className = '',
|
||||
style = { height: '100%', width: '100%', zIndex: 0 },
|
||||
}: Props) {
|
||||
// Fix for default marker icons in Next.js
|
||||
useEffect(() => {
|
||||
delete (L.Icon.Default.prototype as any)._getIconUrl;
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png',
|
||||
iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png',
|
||||
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
<MapContainer
|
||||
center={center as LatLngExpression}
|
||||
zoom={zoom}
|
||||
scrollWheelZoom={scrollWheelZoom}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
/>
|
||||
{markers.map((marker, index) => (
|
||||
<Marker key={index} position={marker.position as LatLngExpression}>
|
||||
<Popup>{marker.popup}</Popup>
|
||||
</Marker>
|
||||
))}
|
||||
</MapContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
83
src/app/admin/(dashboard)/_com/iconMap.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import {
|
||||
IconLeaf,
|
||||
IconTrophy,
|
||||
IconTent,
|
||||
IconChartLine,
|
||||
IconRecycle,
|
||||
IconTruck,
|
||||
IconScale,
|
||||
IconClipboard,
|
||||
IconTrash,
|
||||
IconHomeEco,
|
||||
IconChristmasTreeFilled,
|
||||
IconTrendingUp,
|
||||
IconShieldFilled,
|
||||
IconHome,
|
||||
IconTree,
|
||||
IconDroplet,
|
||||
IconCash,
|
||||
IconSchool,
|
||||
IconShoppingCart,
|
||||
IconHospital,
|
||||
} from '@tabler/icons-react'
|
||||
|
||||
export type IconKey =
|
||||
| 'ekowisata'
|
||||
| 'kompetisi'
|
||||
| 'wisata'
|
||||
| 'ekonomi'
|
||||
| 'sampah'
|
||||
| 'truck'
|
||||
| 'scale'
|
||||
| 'clipboard'
|
||||
| 'trash'
|
||||
| 'lingkunganSehat'
|
||||
| 'sumberOksigen'
|
||||
| 'ekonomiBerkelanjutan'
|
||||
| 'mencegahBencana'
|
||||
| 'rumah'
|
||||
| 'pohon'
|
||||
| 'air'
|
||||
| 'bantuan'
|
||||
| 'pelatihan'
|
||||
| 'subsidi'
|
||||
| 'layananKesehatan'
|
||||
|
||||
const iconMap: Record<IconKey, React.FC<any>> = {
|
||||
ekowisata: IconLeaf,
|
||||
kompetisi: IconTrophy,
|
||||
wisata: IconTent,
|
||||
ekonomi: IconChartLine,
|
||||
sampah: IconRecycle,
|
||||
truck: IconTruck,
|
||||
scale: IconScale,
|
||||
clipboard: IconClipboard,
|
||||
trash: IconTrash,
|
||||
lingkunganSehat: IconHomeEco,
|
||||
sumberOksigen: IconChristmasTreeFilled,
|
||||
ekonomiBerkelanjutan: IconTrendingUp,
|
||||
mencegahBencana: IconShieldFilled,
|
||||
rumah: IconHome,
|
||||
pohon: IconTree,
|
||||
air: IconDroplet,
|
||||
bantuan: IconCash,
|
||||
pelatihan: IconSchool,
|
||||
subsidi: IconShoppingCart,
|
||||
layananKesehatan: IconHospital,
|
||||
}
|
||||
|
||||
type Props = {
|
||||
name: IconKey
|
||||
size?: number
|
||||
color?: string
|
||||
}
|
||||
|
||||
export const IconMapper: React.FC<Props> = ({ name, size = 24, color }) => {
|
||||
const IconComponent = iconMap[name]
|
||||
if (!IconComponent) return null
|
||||
return <IconComponent size={size} color={color} />
|
||||
}
|
||||
@@ -3,16 +3,20 @@
|
||||
|
||||
import { Box, rem, Select } from '@mantine/core';
|
||||
import {
|
||||
IconCash,
|
||||
IconChartLine,
|
||||
IconChristmasTreeFilled,
|
||||
IconClipboardTextFilled,
|
||||
IconDroplet,
|
||||
IconHome,
|
||||
IconHomeEco,
|
||||
IconHospital,
|
||||
IconLeaf,
|
||||
IconRecycle,
|
||||
IconScale,
|
||||
IconSchool,
|
||||
IconShieldFilled,
|
||||
IconShoppingCart,
|
||||
IconTent,
|
||||
IconTrashFilled,
|
||||
IconTree,
|
||||
@@ -32,13 +36,17 @@ const iconMap = {
|
||||
scale: { label: 'Scale', icon: IconScale },
|
||||
clipboard: { label: 'Clipboard', icon: IconClipboardTextFilled },
|
||||
trash: { label: 'Trash', icon: IconTrashFilled },
|
||||
lingkunganSehat: {label: 'Lingkungan Sehat', icon: IconHomeEco},
|
||||
sumberOksigen: {label: 'Sumber Oksigen', icon: IconChristmasTreeFilled},
|
||||
ekonomiBerkelanjutan: {label: 'Ekonomi Berkelanjutan', icon: IconTrendingUp},
|
||||
mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled},
|
||||
rumah: {label: 'Rumah', icon: IconHome},
|
||||
pohon: {label: 'Pohon', icon: IconTree},
|
||||
air: {label: 'Air', icon: IconDroplet}
|
||||
lingkunganSehat: { label: 'Lingkungan Sehat', icon: IconHomeEco },
|
||||
sumberOksigen: { label: 'Sumber Oksigen', icon: IconChristmasTreeFilled },
|
||||
ekonomiBerkelanjutan: { label: 'Ekonomi Berkelanjutan', icon: IconTrendingUp },
|
||||
mencegahBencana: { label: 'Mencegah Bencana', icon: IconShieldFilled },
|
||||
rumah: { label: 'Rumah', icon: IconHome },
|
||||
pohon: { label: 'Pohon', icon: IconTree },
|
||||
air: { label: 'Air', icon: IconDroplet },
|
||||
bantuan: { label: 'Bantuan', icon: IconCash },
|
||||
pelatihan: { label: 'Pelatihan', icon: IconSchool },
|
||||
subsidi: { label: 'Subsidi', icon: IconShoppingCart },
|
||||
layananKesehatan: { label: 'Layanan Kesehatan', icon: IconHospital },
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -2,16 +2,20 @@
|
||||
|
||||
import { Box, rem, Select } from '@mantine/core';
|
||||
import {
|
||||
IconCash,
|
||||
IconChartLine,
|
||||
IconChristmasTreeFilled,
|
||||
IconClipboardTextFilled,
|
||||
IconDroplet,
|
||||
IconHome,
|
||||
IconHomeEco,
|
||||
IconHospital,
|
||||
IconLeaf,
|
||||
IconRecycle,
|
||||
IconScale,
|
||||
IconSchool,
|
||||
IconShieldFilled,
|
||||
IconShoppingCart,
|
||||
IconTent,
|
||||
IconTrashFilled,
|
||||
IconTree,
|
||||
@@ -36,7 +40,11 @@ const iconMap = {
|
||||
mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled},
|
||||
rumah: {label: 'Rumah', icon: IconHome},
|
||||
pohon: {label: 'Pohon', icon: IconTree},
|
||||
air: {label: 'Air', icon: IconDroplet}
|
||||
air: {label: 'Air', icon: IconDroplet},
|
||||
bantuan: {label: 'Bantuan', icon: IconCash},
|
||||
pelatihan: {label: 'Pelatihan', icon: IconSchool},
|
||||
subsidi: {label: 'Subsidi', icon: IconShoppingCart},
|
||||
layananKesehatan: {label: 'Layanan Kesehatan', icon: IconHospital},
|
||||
};
|
||||
|
||||
type IconKey = keyof typeof iconMap;
|
||||
|
||||
@@ -74,18 +74,18 @@ const berita = proxy({
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "", kategori = "") => {
|
||||
load: async (page = 1, limit = 10, search = "", kategori = "") => {
|
||||
berita.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
berita.findMany.page = page;
|
||||
berita.findMany.search = search;
|
||||
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
if (kategori) query.kategori = kategori;
|
||||
|
||||
|
||||
const res = await ApiFetch.api.desa.berita["find-many"].get({ query });
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
berita.findMany.data = res.data.data ?? [];
|
||||
berita.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
@@ -368,11 +368,37 @@ const kategoriBerita = proxy({
|
||||
isActive: true;
|
||||
};
|
||||
}>[],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.desa.kategoriberita["findMany"].get();
|
||||
if (res.status === 200) {
|
||||
kategoriBerita.findMany.data = res.data?.data ?? [];
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kategoriBerita.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kategoriBerita.findMany.page = page;
|
||||
kategoriBerita.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.desa.kategoriberita[
|
||||
"findMany"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriBerita.findMany.data = res.data.data ?? [];
|
||||
kategoriBerita.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kategoriBerita.findMany.data = [];
|
||||
kategoriBerita.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kategori berita paginated:", err);
|
||||
kategoriBerita.findMany.data = [];
|
||||
kategoriBerita.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriBerita.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -30,7 +30,6 @@ const templateTelunjukSaktiDesaForm = z.object({
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
|
||||
const templatePelayananPerizinanBerusaha = z.object({
|
||||
name: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
@@ -72,7 +71,6 @@ const pelayananPendudukNonPermanenForm = {
|
||||
deskripsi: "",
|
||||
};
|
||||
|
||||
|
||||
const suratKeterangan = proxy({
|
||||
create: {
|
||||
form: { ...suratKeteranganForm },
|
||||
@@ -113,16 +111,21 @@ const suratKeterangan = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
suratKeterangan.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
suratKeterangan.findMany.loading = true; // Use the full path to access the property
|
||||
suratKeterangan.findMany.page = page;
|
||||
suratKeterangan.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res = await ApiFetch.api.desa.layanan.pelayanansuratketerangan[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
suratKeterangan.findMany.data = res.data.data || [];
|
||||
suratKeterangan.findMany.total = res.data.total || 0;
|
||||
@@ -341,28 +344,34 @@ const pelayananTelunjukSaktiDesa = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
pelayananTelunjukSaktiDesa.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
pelayananTelunjukSaktiDesa.findMany.loading = true; // Use the full path to access the property
|
||||
pelayananTelunjukSaktiDesa.findMany.page = page;
|
||||
pelayananTelunjukSaktiDesa.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res = await ApiFetch.api.desa.layanan.pelayanantelunjuksaktidesa[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pelayananTelunjukSaktiDesa.findMany.data = res.data.data || [];
|
||||
pelayananTelunjukSaktiDesa.findMany.total = res.data.total || 0;
|
||||
pelayananTelunjukSaktiDesa.findMany.totalPages = res.data.totalPages || 1;
|
||||
pelayananTelunjukSaktiDesa.findMany.totalPages =
|
||||
res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load telunjuk sakti desa:", res.data?.message);
|
||||
console.error("Failed to load surat keterangan:", res.data?.message);
|
||||
pelayananTelunjukSaktiDesa.findMany.data = [];
|
||||
pelayananTelunjukSaktiDesa.findMany.total = 0;
|
||||
pelayananTelunjukSaktiDesa.findMany.totalPages = 1;
|
||||
suratKeterangan.findMany.total = 0;
|
||||
suratKeterangan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading telunjuk sakti desa:", error);
|
||||
console.error("Error loading surat keterangan:", error);
|
||||
pelayananTelunjukSaktiDesa.findMany.data = [];
|
||||
pelayananTelunjukSaktiDesa.findMany.total = 0;
|
||||
pelayananTelunjukSaktiDesa.findMany.totalPages = 1;
|
||||
@@ -410,7 +419,9 @@ const pelayananTelunjukSaktiDesa = proxy({
|
||||
);
|
||||
const result = await response.json();
|
||||
if (response.ok) {
|
||||
toast.success(result.message || "Telunjuk Sakti Desa berhasil dihapus");
|
||||
toast.success(
|
||||
result.message || "Telunjuk Sakti Desa berhasil dihapus"
|
||||
);
|
||||
await pelayananTelunjukSaktiDesa.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result.message || "Gagal menghapus telunjuk sakti desa");
|
||||
@@ -501,7 +512,9 @@ const pelayananTelunjukSaktiDesa = proxy({
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success(result.message || "Telunjuk Sakti Desa berhasil diupdate");
|
||||
toast.success(
|
||||
result.message || "Telunjuk Sakti Desa berhasil diupdate"
|
||||
);
|
||||
await pelayananTelunjukSaktiDesa.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
@@ -522,7 +535,7 @@ const pelayananTelunjukSaktiDesa = proxy({
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
const pelayananPerizinanBerusaha = proxy({
|
||||
findById: {
|
||||
@@ -596,9 +609,7 @@ const pelayananPerizinanBerusaha = proxy({
|
||||
} catch (error) {
|
||||
console.error("Error fetching pelayanan perizinan berusaha:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal memuat data"
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
@@ -713,9 +724,7 @@ const pelayananPendudukNonPermanen = proxy({
|
||||
} catch (error) {
|
||||
console.error("Error fetching pelayanan penduduk non permanen:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal memuat data"
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -56,16 +56,21 @@ const penghargaanState = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
penghargaanState.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
penghargaanState.findMany.loading = true; // Use the full path to access the property
|
||||
penghargaanState.findMany.page = page;
|
||||
penghargaanState.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res = await ApiFetch.api.desa.penghargaan[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
penghargaanState.findMany.data = res.data.data || [];
|
||||
penghargaanState.findMany.total = res.data.total || 0;
|
||||
|
||||
@@ -55,11 +55,39 @@ const category = proxy({
|
||||
pengumumans: number;
|
||||
};
|
||||
})[],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.desa.kategoripengumuman["findMany"].get();
|
||||
if (res.status === 200) {
|
||||
category.findMany.data = res.data?.data ?? [];
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
category.findMany.loading = true; // Use the full path to access the property
|
||||
category.findMany.page = page;
|
||||
category.findMany.search = search;
|
||||
try {
|
||||
const res = await ApiFetch.api.desa.kategoripengumuman[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
category.findMany.data = res.data.data || [];
|
||||
category.findMany.total = res.data.total || 0;
|
||||
category.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load potensi desa:", res.data?.message);
|
||||
category.findMany.data = [];
|
||||
category.findMany.total = 0;
|
||||
category.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading potensi desa:", error);
|
||||
category.findMany.data = [];
|
||||
category.findMany.total = 0;
|
||||
category.findMany.totalPages = 1;
|
||||
} finally {
|
||||
category.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -56,9 +56,11 @@ const potensiDesa = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
potensiDesa.findMany.loading = true; // Use the full path to access the property
|
||||
potensiDesa.findMany.page = page;
|
||||
potensiDesa.findMany.search = search;
|
||||
try {
|
||||
const res = await ApiFetch.api.desa.potensi[
|
||||
"find-many"
|
||||
@@ -298,11 +300,34 @@ const kategoriPotensi = proxy({
|
||||
isActive: true;
|
||||
};
|
||||
}>[],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.desa.kategoripotensi["findMany"].get();
|
||||
if (res.status === 200) {
|
||||
kategoriPotensi.findMany.data = res.data?.data ?? [];
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kategoriPotensi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kategoriPotensi.findMany.page = page;
|
||||
kategoriPotensi.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.desa.kategoripotensi["findMany"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriPotensi.findMany.data = res.data.data ?? [];
|
||||
kategoriPotensi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kategoriPotensi.findMany.data = [];
|
||||
kategoriPotensi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kategori potensi paginated:", err);
|
||||
kategoriPotensi.findMany.data = [];
|
||||
kategoriPotensi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriPotensi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -7,9 +7,13 @@ import { z } from "zod";
|
||||
|
||||
const templateApbDesa = z.object({
|
||||
tahun: z.number().min(4, "Tahun minimal 4 karakter"),
|
||||
pembiayaanIds: z.array(z.string().uuid()).nonempty("Pilih minimal 1 pembiayaan"),
|
||||
pembiayaanIds: z
|
||||
.array(z.string().uuid())
|
||||
.nonempty("Pilih minimal 1 pembiayaan"),
|
||||
belanjaIds: z.array(z.string().uuid()).nonempty("Pilih minimal 1 belanja"),
|
||||
pendapatanIds: z.array(z.string().uuid()).nonempty("Pilih minimal 1 pendapatan"),
|
||||
pendapatanIds: z
|
||||
.array(z.string().uuid())
|
||||
.nonempty("Pilih minimal 1 pendapatan"),
|
||||
});
|
||||
|
||||
const ApbDesaDefaultForm = {
|
||||
@@ -54,32 +58,46 @@ const ApbDesa = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.ApbDesaGetPayload<{
|
||||
include: {
|
||||
pendapatan: true;
|
||||
belanja: true;
|
||||
pembiayaan: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
data: null as
|
||||
| Prisma.ApbDesaGetPayload<{
|
||||
include: {
|
||||
pendapatan: true;
|
||||
belanja: true;
|
||||
pembiayaan: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
ApbDesa.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
ApbDesa.findMany.page = page;
|
||||
ApbDesa.findMany.search = search;
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.apbdesa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
ApbDesa.findMany.data = res.data.data ?? [];
|
||||
ApbDesa.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal mengambil APB Desa");
|
||||
ApbDesa.findMany.data = [];
|
||||
ApbDesa.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
toast.error("Gagal mengambil APB Desa");
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch APB Desa paginated:", err);
|
||||
ApbDesa.findMany.data = [];
|
||||
ApbDesa.findMany.totalPages = 1;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
ApbDesa.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -106,13 +124,13 @@ const ApbDesa = proxy({
|
||||
throw new Error("Gagal mengambil APB Desa");
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.message || "Gagal memuat APB Desa");
|
||||
}
|
||||
|
||||
|
||||
const data = result.data;
|
||||
|
||||
|
||||
this.id = id;
|
||||
this.form = {
|
||||
tahun: data.tahun || 0,
|
||||
@@ -120,7 +138,7 @@ const ApbDesa = proxy({
|
||||
belanjaIds: data.belanja?.map((b: any) => b.id) || [],
|
||||
pembiayaanIds: data.pembiayaan?.map((p: any) => p.id) || [],
|
||||
};
|
||||
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error loading APB Desa:", error);
|
||||
@@ -189,7 +207,7 @@ const ApbDesa = proxy({
|
||||
data: null as Prisma.ApbDesaGetPayload<{
|
||||
include: { pendapatan: true; belanja: true; pembiayaan: true };
|
||||
}> | null,
|
||||
|
||||
|
||||
async load(id: string) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
@@ -199,11 +217,11 @@ const ApbDesa = proxy({
|
||||
throw new Error("Gagal mengambil detail APB Desa");
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.message || "Gagal mengambil data");
|
||||
}
|
||||
|
||||
|
||||
this.data = result.data; // ✅ fix utama di sini
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
@@ -264,34 +282,32 @@ const pendapatan = proxy({
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
// Change to arrow function
|
||||
pendapatan.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
pendapatan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
pendapatan.findMany.page = page;
|
||||
pendapatan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const res =
|
||||
await ApiFetch.api.ekonomi.pendapatanaslidesa.pendapatanasli[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.pendapatanasli[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pendapatan.findMany.data = res.data.data || [];
|
||||
pendapatan.findMany.total = res.data.total || 0;
|
||||
pendapatan.findMany.totalPages = res.data.totalPages || 1;
|
||||
pendapatan.findMany.data = res.data.data ?? [];
|
||||
pendapatan.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
console.error("Failed to load pendapatan:", res.data?.message);
|
||||
pendapatan.findMany.data = [];
|
||||
pendapatan.findMany.total = 0;
|
||||
pendapatan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pendapatan:", error);
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch pendapatan asli desa paginated:", err);
|
||||
pendapatan.findMany.data = [];
|
||||
pendapatan.findMany.total = 0;
|
||||
pendapatan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pendapatan.findMany.loading = false;
|
||||
@@ -308,12 +324,15 @@ const pendapatan = proxy({
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
@@ -349,16 +368,19 @@ const pendapatan = proxy({
|
||||
|
||||
try {
|
||||
pendapatan.update.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
@@ -495,23 +517,37 @@ const belanja = proxy({
|
||||
name: string;
|
||||
value: number;
|
||||
}>,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
belanja.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
belanja.findMany.page = page;
|
||||
belanja.findMany.search = search;
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.belanja[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
belanja.findMany.data = res.data.data ?? [];
|
||||
belanja.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal mengambil Belanja");
|
||||
belanja.findMany.data = [];
|
||||
belanja.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
toast.error("Gagal mengambil Belanja");
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch Belanja paginated:", err);
|
||||
belanja.findMany.data = [];
|
||||
belanja.findMany.totalPages = 1;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
belanja.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -525,12 +561,15 @@ const belanja = proxy({
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/belanja/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/belanja/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
@@ -566,16 +605,19 @@ const belanja = proxy({
|
||||
|
||||
try {
|
||||
belanja.update.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/belanja/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/belanja/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
@@ -710,23 +752,37 @@ const pembiayaan = proxy({
|
||||
name: string;
|
||||
value: number;
|
||||
}>,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
pembiayaan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
pembiayaan.findMany.page = page;
|
||||
pembiayaan.findMany.search = search;
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.pembiayaan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pembiayaan.findMany.data = res.data.data ?? [];
|
||||
pembiayaan.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal mengambil Pembiayaan");
|
||||
pembiayaan.findMany.data = [];
|
||||
pembiayaan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
toast.error("Gagal mengambil Pembiayaan");
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch Pembiayaan paginated:", err);
|
||||
pembiayaan.findMany.data = [];
|
||||
pembiayaan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
pembiayaan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -740,12 +796,15 @@ const pembiayaan = proxy({
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pembiayaan/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/pembiayaan/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
@@ -781,16 +840,19 @@ const pembiayaan = proxy({
|
||||
|
||||
try {
|
||||
pembiayaan.update.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pembiayaan/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/pembiayaan/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -71,12 +72,37 @@ const demografiPekerjaan = proxy({
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.demografipekerjaan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
demografiPekerjaan.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
demografiPekerjaan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
demografiPekerjaan.findMany.page = page;
|
||||
demografiPekerjaan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.demografipekerjaan[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
demografiPekerjaan.findMany.data = res.data.data ?? [];
|
||||
demografiPekerjaan.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
demografiPekerjaan.findMany.data = [];
|
||||
demografiPekerjaan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch demografi pekerjaan paginated:", err);
|
||||
demografiPekerjaan.findMany.data = [];
|
||||
demografiPekerjaan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
demografiPekerjaan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -194,4 +220,4 @@ const demografiPekerjaan = proxy({
|
||||
},
|
||||
},
|
||||
});
|
||||
export default demografiPekerjaan
|
||||
export default demografiPekerjaan;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -69,16 +70,37 @@ const jumlahPendudukMiskin = proxy({
|
||||
select: { id: true; year: true; totalPoorPopulation: true };
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.jumlahpendudukmiskin[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
jumlahPendudukMiskin.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
jumlahPendudukMiskin.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
jumlahPendudukMiskin.findMany.page = page;
|
||||
jumlahPendudukMiskin.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.jumlahpendudukmiskin["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
jumlahPendudukMiskin.findMany.data = res.data.data ?? [];
|
||||
jumlahPendudukMiskin.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
jumlahPendudukMiskin.findMany.data = [];
|
||||
jumlahPendudukMiskin.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch jumlah penduduk miskin paginated:", err);
|
||||
jumlahPendudukMiskin.findMany.data = [];
|
||||
jumlahPendudukMiskin.findMany.totalPages = 1;
|
||||
} finally {
|
||||
jumlahPendudukMiskin.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.GrafikJumlahPendudukMiskinGetPayload<{
|
||||
select: { id: true; year: true; totalPoorPopulation: true };
|
||||
|
||||
@@ -15,7 +15,8 @@ const templateJumlahPengngguran = z.object({
|
||||
uneducatedUnemployment: z
|
||||
.number()
|
||||
.min(1, "Pengangguran tidak pendidikan harus diisi"),
|
||||
percentageChange: z.number().min(0, "Persentase perubahan harus diisi"),
|
||||
percentageChange: z.number({ invalid_type_error: "Persentase perubahan harus angka" }),
|
||||
|
||||
});
|
||||
|
||||
type JumlahPengangguran = {
|
||||
@@ -29,7 +30,7 @@ type JumlahPengangguran = {
|
||||
|
||||
const jumlahPengangguranForm: JumlahPengangguran = {
|
||||
month: "",
|
||||
year: 0,
|
||||
year: new Date().getFullYear(), // Default to current year
|
||||
totalUnemployment: 0,
|
||||
educatedUnemployment: 0,
|
||||
uneducatedUnemployment: 0,
|
||||
@@ -60,13 +61,21 @@ const jumlahPengangguran = proxy({
|
||||
form: jumlahPengangguranForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateJumlahPengngguran.safeParse(
|
||||
jumlahPengangguran.create.form
|
||||
);
|
||||
// Ensure all number fields are actual numbers
|
||||
const formData = {
|
||||
...jumlahPengangguran.create.form,
|
||||
year: Number(jumlahPengangguran.create.form.year) || new Date().getFullYear(),
|
||||
totalUnemployment: Number(jumlahPengangguran.create.form.totalUnemployment) || 0,
|
||||
educatedUnemployment: Number(jumlahPengangguran.create.form.educatedUnemployment) || 0,
|
||||
uneducatedUnemployment: Number(jumlahPengangguran.create.form.uneducatedUnemployment) || 0,
|
||||
percentageChange: Number(jumlahPengangguran.create.form.percentageChange) || 0,
|
||||
};
|
||||
|
||||
const cek = templateJumlahPengngguran.safeParse(formData);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
.map((v) => `${v.path.join(".")} (${v.message})`)
|
||||
.join("\n")}]`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
@@ -78,7 +87,7 @@ const jumlahPengangguran = proxy({
|
||||
].post(jumlahPengangguran.create.form);
|
||||
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
const id = res.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
jumlahPengangguran.create.form = { ...jumlahPengangguranForm };
|
||||
@@ -103,16 +112,40 @@ const jumlahPengangguran = proxy({
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.ekonomi.jumlahpengangguran.detaildatapengangguran[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
jumlahPengangguran.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
jumlahPengangguran.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
jumlahPengangguran.findMany.page = page;
|
||||
jumlahPengangguran.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.jumlahpengangguran.detaildatapengangguran[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
jumlahPengangguran.findMany.data = res.data.data ?? [];
|
||||
jumlahPengangguran.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
jumlahPengangguran.findMany.data = [];
|
||||
jumlahPengangguran.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch jumlah pengangguran paginated:", err);
|
||||
jumlahPengangguran.findMany.data = [];
|
||||
jumlahPengangguran.findMany.totalPages = 1;
|
||||
} finally {
|
||||
jumlahPengangguran.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
findUnique: {
|
||||
data: null as Prisma.DetailDataPengangguranGetPayload<{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -61,13 +62,39 @@ const lowonganKerjaState = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.LowonganPekerjaanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.lowongankerja["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
lowonganKerjaState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
lowonganKerjaState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
lowonganKerjaState.findMany.page = page;
|
||||
lowonganKerjaState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.lowongankerja["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
lowonganKerjaState.findMany.data = res.data.data ?? [];
|
||||
lowonganKerjaState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
lowonganKerjaState.findMany.data = [];
|
||||
lowonganKerjaState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch lowongan kerja paginated:", err);
|
||||
lowonganKerjaState.findMany.data = [];
|
||||
lowonganKerjaState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
lowonganKerjaState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -53,22 +54,47 @@ const pasarDesa = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.PasarDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
KategoriToPasar: {
|
||||
include: {
|
||||
kategori: true;
|
||||
data: null as
|
||||
| Prisma.PasarDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
KategoriToPasar: {
|
||||
include: {
|
||||
kategori: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.pasardesa["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
pasarDesa.findMany.data = res.data?.data ?? [];
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "", categoryId?: string) => {
|
||||
pasarDesa.findMany.loading = true;
|
||||
pasarDesa.findMany.page = page;
|
||||
pasarDesa.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
if (categoryId) query.categoryId = categoryId;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.pasardesa["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pasarDesa.findMany.data = res.data.data ?? [];
|
||||
pasarDesa.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
pasarDesa.findMany.data = [];
|
||||
pasarDesa.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch keamanan lingkungan paginated:", err);
|
||||
pasarDesa.findMany.data = [];
|
||||
pasarDesa.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pasarDesa.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -272,14 +298,41 @@ const kategoriProduk = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
nama: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
kategoriProduk.findMany.data = res.data?.data ?? [];
|
||||
data: null as
|
||||
| Prisma.KategoriProdukGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search2: "",
|
||||
load: async (page = 1, limit = 10, search2 = "") => {
|
||||
kategoriProduk.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kategoriProduk.findMany.page = page;
|
||||
kategoriProduk.findMany.search2 = search2;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search2) query.search2 = search2;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriProduk.findMany.data = res.data.data ?? [];
|
||||
kategoriProduk.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kategoriProduk.findMany.data = [];
|
||||
kategoriProduk.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kategori produk paginated:", err);
|
||||
kategoriProduk.findMany.data = [];
|
||||
kategoriProduk.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriProduk.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -7,22 +8,21 @@ import { z } from "zod";
|
||||
const templateForm = z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
ikonUrl: z.string().optional(),
|
||||
icon: z.string().min(1, "Icon minimal 1 karakter"),
|
||||
statistik: z.object({
|
||||
tahun: z.string().min(1, "Tahun minimal 1 karakter"),
|
||||
jumlah: z.string().min(1, "Jumlah minimal 1 karakter"),
|
||||
})
|
||||
|
||||
}),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
nama: "",
|
||||
deskripsi: "",
|
||||
ikonUrl: "",
|
||||
icon: "",
|
||||
statistik: {
|
||||
tahun: "",
|
||||
jumlah: ""
|
||||
}
|
||||
jumlah: "",
|
||||
},
|
||||
};
|
||||
|
||||
const programKemiskinanState = proxy({
|
||||
@@ -64,12 +64,35 @@ const programKemiskinanState = proxy({
|
||||
};
|
||||
}>[],
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.programkemiskinan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
programKemiskinanState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
programKemiskinanState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
programKemiskinanState.findMany.page = page;
|
||||
programKemiskinanState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.programkemiskinan[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
programKemiskinanState.findMany.data = res.data.data ?? [];
|
||||
programKemiskinanState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
programKemiskinanState.findMany.data = [];
|
||||
programKemiskinanState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch program kemiskinan paginated:", err);
|
||||
programKemiskinanState.findMany.data = [];
|
||||
programKemiskinanState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
programKemiskinanState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -125,7 +148,7 @@ const programKemiskinanState = proxy({
|
||||
this.form = {
|
||||
nama: data.nama,
|
||||
deskripsi: data.deskripsi,
|
||||
ikonUrl: data.ikonUrl || "",
|
||||
icon: data.icon,
|
||||
statistik: {
|
||||
tahun: data.statistik.tahun,
|
||||
jumlah: data.statistik.jumlah,
|
||||
@@ -166,7 +189,7 @@ const programKemiskinanState = proxy({
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
deskripsi: this.form.deskripsi,
|
||||
ikonUrl: this.form.ikonUrl,
|
||||
icon: this.form.icon,
|
||||
statistik: {
|
||||
tahun: this.form.statistik.tahun,
|
||||
jumlah: this.form.statistik.jumlah,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -76,13 +77,37 @@ const grafikSektorUnggulan = proxy({
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.sektourunggulandesa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
grafikSektorUnggulan.findMany.data = res.data?.data ?? [];
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
grafikSektorUnggulan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
grafikSektorUnggulan.findMany.page = page;
|
||||
grafikSektorUnggulan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.sektourunggulandesa[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
grafikSektorUnggulan.findMany.data = res.data.data ?? [];
|
||||
grafikSektorUnggulan.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
grafikSektorUnggulan.findMany.data = [];
|
||||
grafikSektorUnggulan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch sektor unggulan desa paginated:", err);
|
||||
grafikSektorUnggulan.findMany.data = [];
|
||||
grafikSektorUnggulan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
grafikSektorUnggulan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -161,18 +161,34 @@ const posisiOrganisasi = proxy({
|
||||
deskripsi: string | null;
|
||||
hierarki: number;
|
||||
}>,
|
||||
async load() {
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
posisiOrganisasi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
posisiOrganisasi.findMany.page = page;
|
||||
posisiOrganisasi.findMany.search = search;
|
||||
|
||||
try {
|
||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||
"posisi-organisasi"
|
||||
]["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
// The API now returns the id field, so we can use it directly
|
||||
this.data = res.data?.data ?? [];
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["posisi-organisasi"]["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
posisiOrganisasi.findMany.data = res.data.data ?? [];
|
||||
posisiOrganisasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
posisiOrganisasi.findMany.data = [];
|
||||
posisiOrganisasi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
this.data = [];
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch posisi organisasi paginated:", err);
|
||||
posisiOrganisasi.findMany.data = [];
|
||||
posisiOrganisasi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
posisiOrganisasi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -75,16 +76,37 @@ const grafikBerdasarkanUsiaKerjaNganggur = proxy({
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.grafikusiakerjayangmenganggur[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.page = page;
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.grafikusiakerjayangmenganggur["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.data = res.data.data ?? [];
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.data = [];
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch grafik berdasarkan usia kerja yang menganggur paginated:", err);
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.data = [];
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.totalPages = 1;
|
||||
} finally {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.GrafikMenganggurBerdasarkanUsiaGetPayload<{
|
||||
omit: { isActive: true };
|
||||
@@ -259,15 +281,36 @@ const grafikBerdasarkanPendidikan = proxy({
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.grafikmenganggurberdasarkanpendidikan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
grafikBerdasarkanPendidikan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
grafikBerdasarkanPendidikan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
grafikBerdasarkanPendidikan.findMany.page = page;
|
||||
grafikBerdasarkanPendidikan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ekonomi.grafikmenganggurberdasarkanpendidikan["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
grafikBerdasarkanPendidikan.findMany.data = res.data.data ?? [];
|
||||
grafikBerdasarkanPendidikan.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
grafikBerdasarkanPendidikan.findMany.data = [];
|
||||
grafikBerdasarkanPendidikan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch grafik berdasarkan pendidikan paginated:", err);
|
||||
grafikBerdasarkanPendidikan.findMany.data = [];
|
||||
grafikBerdasarkanPendidikan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
grafikBerdasarkanPendidikan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.GrafikMenganggurBerdasarkanPendidikanGetPayload<{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -55,10 +56,34 @@ const desaDigitalState = proxy({
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.inovasi.desadigital["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
desaDigitalState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
desaDigitalState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
desaDigitalState.findMany.page = page;
|
||||
desaDigitalState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.inovasi.desadigital["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
desaDigitalState.findMany.data = res.data.data ?? [];
|
||||
desaDigitalState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
desaDigitalState.findMany.data = [];
|
||||
desaDigitalState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch desa digital paginated:", err);
|
||||
desaDigitalState.findMany.data = [];
|
||||
desaDigitalState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
desaDigitalState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -55,10 +56,34 @@ const infoTeknoState = proxy({
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.inovasi.infotekno["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
infoTeknoState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
infoTeknoState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
infoTeknoState.findMany.page = page;
|
||||
infoTeknoState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.inovasi.infotekno["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
infoTeknoState.findMany.data = res.data.data ?? [];
|
||||
infoTeknoState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
infoTeknoState.findMany.data = [];
|
||||
infoTeknoState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch info teknologi paginated:", err);
|
||||
infoTeknoState.findMany.data = [];
|
||||
infoTeknoState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
infoTeknoState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,12 +6,11 @@ import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
const templateForm = z.object({
|
||||
name: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
tahun: z.number().min(4, "Tahun minimal 4 karakter"),
|
||||
slug: z.string().min(1, "Deskripsi singkat minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
kolaborator: z.string().min(1, "Kolaborator minimal 1 karakter"),
|
||||
imageId: z.string().min(1, "Image ID minimal 1 karakter"),
|
||||
name: z.string().min(1, "Nama kolaborasi inovasi harus diisi"),
|
||||
tahun: z.number().min(1900, "Tahun tidak valid").max(new Date().getFullYear() + 1, "Tahun tidak boleh lebih dari tahun depan"),
|
||||
slug: z.string().min(1, "Slug harus dihasilkan otomatis"),
|
||||
deskripsi: z.string().min(1, "Deskripsi harus diisi"),
|
||||
kolaborator: z.string().min(1, "Kolaborator harus diisi"),
|
||||
})
|
||||
|
||||
const defaultForm = {
|
||||
@@ -20,7 +19,6 @@ const defaultForm = {
|
||||
slug: "",
|
||||
deskripsi: "",
|
||||
kolaborator: "",
|
||||
imageId: "",
|
||||
}
|
||||
|
||||
const kolaborasiInovasiState = proxy({
|
||||
@@ -28,27 +26,37 @@ const kolaborasiInovasiState = proxy({
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(kolaborasiInovasiState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
// Validate form
|
||||
const validation = templateForm.safeParse(kolaborasiInovasiState.create.form);
|
||||
if (!validation.success) {
|
||||
const errorMessages = validation.error.issues
|
||||
.map(issue => `- ${issue.path.join('.')}: ${issue.message}`)
|
||||
.join('\n');
|
||||
return toast.error(`Validasi gagal:\n${errorMessages}`);
|
||||
}
|
||||
|
||||
kolaborasiInovasiState.create.loading = true;
|
||||
|
||||
const res = await ApiFetch.api.inovasi.kolaborasiinovasi["create"].post(
|
||||
kolaborasiInovasiState.create.form
|
||||
);
|
||||
|
||||
if (res.status === 200) {
|
||||
kolaborasiInovasiState.findMany.load();
|
||||
return toast.success("success create");
|
||||
await kolaborasiInovasiState.findMany.load();
|
||||
return { success: true, data: res.data };
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
|
||||
console.error('Create failed:', res);
|
||||
toast.error(res.data?.message || "Gagal menyimpan data");
|
||||
return { success: false, error: res.data };
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
console.error('Error in create:', error);
|
||||
toast.error("Terjadi kesalahan saat menyimpan data");
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
} finally {
|
||||
kolaborasiInovasiState.create.loading = false;
|
||||
}
|
||||
@@ -60,13 +68,21 @@ const kolaborasiInovasiState = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
// Change to arrow function
|
||||
kolaborasiInovasiState.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
year: "",
|
||||
load: async (page = 1, limit = 10, search = "", year?: string) => {
|
||||
kolaborasiInovasiState.findMany.loading = true;
|
||||
kolaborasiInovasiState.findMany.page = page;
|
||||
kolaborasiInovasiState.findMany.search = search;
|
||||
kolaborasiInovasiState.findMany.year = year || "";
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
if (year) query.year = year;
|
||||
|
||||
const res = await ApiFetch.api.inovasi.kolaborasiinovasi["find-many"].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
@@ -124,7 +140,6 @@ const kolaborasiInovasiState = proxy({
|
||||
slug: data.slug,
|
||||
deskripsi: data.deskripsi,
|
||||
kolaborator: data.kolaborator,
|
||||
imageId: data.imageId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
@@ -179,7 +194,7 @@ const kolaborasiInovasiState = proxy({
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KolaborasiInovasiGetPayload<{
|
||||
include: { image: true };
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
|
||||
229
src/app/admin/(dashboard)/_state/inovasi/mitra-kolaborasi.ts
Normal file
@@ -0,0 +1,229 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
const mitraKolaborasiForm = z.object({
|
||||
name: z.string().min(1, { message: "Name is required" }),
|
||||
imageId: z.string().nonempty(),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const mitraKolaborasi = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = mitraKolaborasiForm.safeParse(mitraKolaborasi.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
mitraKolaborasi.create.loading = true;
|
||||
const res = await ApiFetch.api.inovasi.mitrakolaborasi["create"].post(
|
||||
mitraKolaborasi.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
mitraKolaborasi.findMany.load();
|
||||
return toast.success("mitraKolaborasi berhasil disimpan!");
|
||||
}
|
||||
return toast.error("Gagal menyimpan mitraKolaborasi");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
mitraKolaborasi.create.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
mitraKolaborasi.create.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.MitraKolaborasiGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
mitraKolaborasi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
mitraKolaborasi.findMany.page = page;
|
||||
mitraKolaborasi.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.inovasi.mitrakolaborasi["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
mitraKolaborasi.findMany.data = res.data.data ?? [];
|
||||
mitraKolaborasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
mitraKolaborasi.findMany.data = [];
|
||||
mitraKolaborasi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch mitraKolaborasi paginated:", err);
|
||||
mitraKolaborasi.findMany.data = [];
|
||||
mitraKolaborasi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
mitraKolaborasi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.MitraKolaborasiGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/inovasi/mitrakolaborasi/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
mitraKolaborasi.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch mitraKolaborasi:", res.statusText);
|
||||
mitraKolaborasi.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching mitraKolaborasi:", error);
|
||||
mitraKolaborasi.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
mitraKolaborasi.delete.loading = true;
|
||||
const response = await fetch(`/api/inovasi/mitrakolaborasi/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const result = await response.json();
|
||||
if (response.ok) {
|
||||
toast.success(result.message || "mitraKolaborasi berhasil dihapus");
|
||||
await mitraKolaborasi.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result.message || "Gagal menghapus mitraKolaborasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus mitraKolaborasi");
|
||||
} finally {
|
||||
mitraKolaborasi.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(`/api/inovasi/mitrakolaborasi/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
imageId: data.imageId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading mitraKolaborasi:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = mitraKolaborasiForm.safeParse(mitraKolaborasi.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
mitraKolaborasi.update.loading = true;
|
||||
const response = await fetch(`/api/inovasi/mitrakolaborasi/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success(result.message || "mitraKolaborasi berhasil diupdate");
|
||||
await mitraKolaborasi.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate mitraKolaborasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating mitraKolaborasi:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal mengupdate mitraKolaborasi"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
mitraKolaborasi.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
mitraKolaborasi.update.id = "";
|
||||
mitraKolaborasi.update.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default mitraKolaborasi;
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -53,15 +54,39 @@ const keamananLingkunganState = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.KeamananLingkunganGetPayload<{
|
||||
include: { image: true };
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.keamananlingkungan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
keamananLingkunganState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
keamananLingkunganState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
keamananLingkunganState.findMany.page = page;
|
||||
keamananLingkunganState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.keamananlingkungan["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
keamananLingkunganState.findMany.data = res.data.data ?? [];
|
||||
keamananLingkunganState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
keamananLingkunganState.findMany.data = [];
|
||||
keamananLingkunganState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch keamanan lingkungan paginated:", err);
|
||||
keamananLingkunganState.findMany.data = [];
|
||||
keamananLingkunganState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
keamananLingkunganState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -7,25 +8,13 @@ import { z } from "zod";
|
||||
const templateForm = z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
kontakItems: z.array(
|
||||
z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
nomorTelepon: z.string().min(1, "Nomor Telepon minimal 1 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
})
|
||||
),
|
||||
kategoriId: z.array(z.string()).min(1, "Minimal pilih satu kategori"),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
nama: "",
|
||||
imageId: "",
|
||||
kontakItems: [
|
||||
{
|
||||
nama: "",
|
||||
nomorTelepon: "",
|
||||
imageId: "",
|
||||
},
|
||||
],
|
||||
kategoriId: [] as string[],
|
||||
};
|
||||
|
||||
const kontakDaruratKeamananState = proxy({
|
||||
@@ -61,20 +50,50 @@ const kontakDaruratKeamananState = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.KontakDaruratKeamananGetPayload<{
|
||||
include: {
|
||||
kontakItems: true;
|
||||
image: true;
|
||||
data: null as Array<
|
||||
Prisma.KontakDaruratKeamananGetPayload<{
|
||||
include: {
|
||||
kategori: true;
|
||||
image: true;
|
||||
kontakItems: {
|
||||
include: {
|
||||
kontakItem: true;
|
||||
};
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.kontakdaruratkeamanan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
kontakDaruratKeamananState.findMany.data = res.data?.data ?? [];
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kontakDaruratKeamananState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kontakDaruratKeamananState.findMany.page = page;
|
||||
kontakDaruratKeamananState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.kontakdaruratkeamanan[
|
||||
"findMany"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kontakDaruratKeamananState.findMany.data = res.data.data ?? [];
|
||||
kontakDaruratKeamananState.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kontakDaruratKeamananState.findMany.data = [];
|
||||
kontakDaruratKeamananState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kontak darurat paginated:", err);
|
||||
kontakDaruratKeamananState.findMany.data = [];
|
||||
kontakDaruratKeamananState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kontakDaruratKeamananState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -83,10 +102,15 @@ const kontakDaruratKeamananState = proxy({
|
||||
include: {
|
||||
kontakItems: {
|
||||
include: {
|
||||
image: true;
|
||||
kontakItem: {
|
||||
include: {
|
||||
image: true;
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
image: true;
|
||||
kategori: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
@@ -168,14 +192,8 @@ const kontakDaruratKeamananState = proxy({
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
nama: data.nama,
|
||||
imageId: data.imageId,
|
||||
kontakItems: [
|
||||
{
|
||||
nama: data.kontakItems.nama,
|
||||
nomorTelepon: data.kontakItems.nomorTelepon,
|
||||
imageId: data.kontakItems.imageId,
|
||||
},
|
||||
],
|
||||
imageId: data.imageId || '',
|
||||
kategoriId: data.kontakItems?.map((item: any) => item.kontakItemId) || []
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
@@ -213,13 +231,7 @@ const kontakDaruratKeamananState = proxy({
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
imageId: this.form.imageId,
|
||||
kontakItems: [
|
||||
{
|
||||
nama: this.form.kontakItems[0].nama,
|
||||
nomorTelepon: this.form.kontakItems[0].nomorTelepon,
|
||||
imageId: this.form.kontakItems[0].imageId,
|
||||
},
|
||||
],
|
||||
kategoriId: this.form.kategoriId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
@@ -256,4 +268,257 @@ const kontakDaruratKeamananState = proxy({
|
||||
},
|
||||
});
|
||||
|
||||
export default kontakDaruratKeamananState;
|
||||
const templateFormItem = z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
nomorTelepon: z.string().min(1, "Nomor Telepon minimal 1 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
});
|
||||
|
||||
const defaultFormItem = {
|
||||
nama: "",
|
||||
nomorTelepon: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const kontakDaruratItem = proxy({
|
||||
create: {
|
||||
form: { ...defaultFormItem },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateFormItem.safeParse(
|
||||
kontakDaruratItem.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
kontakDaruratItem.create.loading = true;
|
||||
const res = await ApiFetch.api.keamanan.kontakitem[
|
||||
"create"
|
||||
].post(kontakDaruratItem.create.form);
|
||||
if (res.status === 200) {
|
||||
kontakDaruratItem.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
kontakDaruratItem.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.KontakItemGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kontakDaruratItem.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kontakDaruratItem.findMany.page = page;
|
||||
kontakDaruratItem.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.kontakitem[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kontakDaruratItem.findMany.data = res.data.data ?? [];
|
||||
kontakDaruratItem.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kontakDaruratItem.findMany.data = [];
|
||||
kontakDaruratItem.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kontak darurat paginated:", err);
|
||||
kontakDaruratItem.findMany.data = [];
|
||||
kontakDaruratItem.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kontakDaruratItem.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KontakItemGetPayload<{
|
||||
include: {
|
||||
kategori: true;
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/keamanan/kontakitem/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kontakDaruratItem.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
kontakDaruratItem.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
kontakDaruratItem.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
kontakDaruratItem.delete.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/kontakitem/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kontak item berhasil dihapus");
|
||||
await kontakDaruratItem.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kontak item");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kontak item");
|
||||
} finally {
|
||||
kontakDaruratItem.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultFormItem },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/keamanan/kontakitem/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
nama: data.nama,
|
||||
nomorTelepon: data.nomorTelepon,
|
||||
imageId: data.imageId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kontak darurat:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateFormItem.safeParse(
|
||||
kontakDaruratItem.update.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
kontakDaruratItem.update.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/kontakitem/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
nomorTelepon: this.form.nomorTelepon,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success("Berhasil update kontak item");
|
||||
await kontakDaruratItem.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate kontak item");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating kontak item:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate kontak item"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
kontakDaruratItem.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
kontakDaruratItem.update.id = "";
|
||||
kontakDaruratItem.update.form = { ...defaultFormItem };
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const kontakDarurat = proxy({
|
||||
kontakDaruratKeamananState,
|
||||
kontakDaruratItem,
|
||||
});
|
||||
|
||||
export default kontakDarurat;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -97,13 +98,37 @@ const laporanPublikState = proxy({
|
||||
include: { penanganan: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.laporanpublik["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
laporanPublikState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
laporanPublikState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
laporanPublikState.findMany.page = page;
|
||||
laporanPublikState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.laporanpublik["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
laporanPublikState.findMany.data = res.data.data ?? [];
|
||||
laporanPublikState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
laporanPublikState.findMany.data = [];
|
||||
laporanPublikState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch laporan publik paginated:", err);
|
||||
laporanPublikState.findMany.data = [];
|
||||
laporanPublikState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
laporanPublikState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.LaporanPublikGetPayload<{
|
||||
include: { penanganan: true };
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -88,12 +89,37 @@ const pencegahanKriminalitasState = proxy({
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.pencegahankriminalitas[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
pencegahanKriminalitasState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
pencegahanKriminalitasState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
pencegahanKriminalitasState.findMany.page = page;
|
||||
pencegahanKriminalitasState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.pencegahankriminalitas[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pencegahanKriminalitasState.findMany.data = res.data.data ?? [];
|
||||
pencegahanKriminalitasState.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
pencegahanKriminalitasState.findMany.data = [];
|
||||
pencegahanKriminalitasState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch pencegahan kriminalitas paginated:", err);
|
||||
pencegahanKriminalitasState.findMany.data = [];
|
||||
pencegahanKriminalitasState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pencegahanKriminalitasState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -311,4 +337,4 @@ const pencegahanKriminalitasState = proxy({
|
||||
},
|
||||
},
|
||||
});
|
||||
export default pencegahanKriminalitasState;
|
||||
export default pencegahanKriminalitasState;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -63,13 +64,41 @@ const polsekTerdekatState = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PolsekTerdekatGetPayload<{
|
||||
include: { layananPolsek: true };
|
||||
include: {
|
||||
layananPolsek: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.polsekterdekat["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
polsekTerdekatState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
polsekTerdekatState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
polsekTerdekatState.findMany.page = page;
|
||||
polsekTerdekatState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.polsekterdekat["find-many"].get(
|
||||
{ query }
|
||||
);
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
polsekTerdekatState.findMany.data = res.data.data ?? [];
|
||||
polsekTerdekatState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
polsekTerdekatState.findMany.data = [];
|
||||
polsekTerdekatState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch polsek terdekat paginated:", err);
|
||||
polsekTerdekatState.findMany.data = [];
|
||||
polsekTerdekatState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
polsekTerdekatState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -237,6 +266,29 @@ const polsekTerdekatState = proxy({
|
||||
polsekTerdekatState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findFirst: {
|
||||
data: null as Prisma.PolsekTerdekatGetPayload<{
|
||||
include: {
|
||||
layananPolsek: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
load: async () => { // Changed to arrow function
|
||||
polsekTerdekatState.findFirst.loading = true;
|
||||
try {
|
||||
const res = await ApiFetch.api.keamanan.polsekterdekat["find-first"].get();
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
polsekTerdekatState.findFirst.data = res.data.data || null;
|
||||
} else {
|
||||
polsekTerdekatState.findFirst.data = null;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch polsek terdekat terbaru:", err);
|
||||
} finally {
|
||||
polsekTerdekatState.findFirst.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default polsekTerdekatState;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -53,15 +54,39 @@ const tipsKeamananState = proxy({
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.MenuTipsKeamananGetPayload<{
|
||||
include: { image: true };
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.menutipskeamanan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
tipsKeamananState.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
tipsKeamananState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
tipsKeamananState.findMany.page = page;
|
||||
tipsKeamananState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.keamanan.menutipskeamanan["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
tipsKeamananState.findMany.data = res.data.data ?? [];
|
||||
tipsKeamananState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
tipsKeamananState.findMany.data = [];
|
||||
tipsKeamananState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch menu tips keamanan paginated:", err);
|
||||
tipsKeamananState.findMany.data = [];
|
||||
tipsKeamananState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
tipsKeamananState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -115,27 +115,38 @@ const artikelKesehatanState = proxy({
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
artikelKesehatanState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
artikelKesehatanState.findMany.page = page;
|
||||
artikelKesehatanState.findMany.search = search;
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await (ApiFetch.api.kesehatan as any)["artikel-kesehatan"][
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.kesehatan["artikel-kesehatan"][
|
||||
"find-many"
|
||||
].get();
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
artikelKesehatanState.findMany.data =
|
||||
res.data.data ?? [];
|
||||
artikelKesehatanState.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
toast.error("Gagal memuat data artikel kesehatan");
|
||||
artikelKesehatanState.findMany.data = [];
|
||||
artikelKesehatanState.findMany.totalPages = 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
toast.error("Terjadi error saat load data");
|
||||
console.error("LOAD ERROR:", err);
|
||||
throw err;
|
||||
console.error("Gagal fetch artikel kesehatan paginated:", err);
|
||||
artikelKesehatanState.findMany.data = [];
|
||||
artikelKesehatanState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
artikelKesehatanState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -280,12 +291,9 @@ const artikelKesehatanState = proxy({
|
||||
async byId(id: string) {
|
||||
try {
|
||||
artikelKesehatanState.delete.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/kesehatan/artikel-kesehatan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
const res = await fetch(`/api/kesehatan/artikel-kesehatan/del/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
if (res.ok && result.success) {
|
||||
|
||||
@@ -116,27 +116,38 @@ const fasilitasKesehatan = proxy({
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.page = page;
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.search = search;
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await (ApiFetch.api.kesehatan as any)[
|
||||
"fasilitas-kesehatan"
|
||||
]["find-many"].get();
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
const res = await ApiFetch.api.kesehatan["fasilitas-kesehatan"][
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.data =
|
||||
res.data.data ?? [];
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.totalPages =
|
||||
res.data.totalPages ?? 1;
|
||||
} else {
|
||||
toast.error("Gagal memuat data fasilitas kesehatan");
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.data = [];
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.totalPages = 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
toast.error("Terjadi error saat load data");
|
||||
console.error("LOAD ERROR:", err);
|
||||
throw err;
|
||||
console.error("Gagal fetch fasilitas kesehatan paginated:", err);
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.data = [];
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
fasilitasKesehatanState.fasilitasKesehatan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -558,7 +569,7 @@ const dokter = proxy({
|
||||
|
||||
const fasilitasKesehatanState = proxy({
|
||||
fasilitasKesehatan,
|
||||
dokter
|
||||
dokter,
|
||||
});
|
||||
|
||||
export default fasilitasKesehatanState;
|
||||
|
||||
@@ -120,27 +120,36 @@ const jadwalkegiatanState = proxy({
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
jadwalkegiatanState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
jadwalkegiatanState.findMany.page = page;
|
||||
jadwalkegiatanState.findMany.search = search;
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await (ApiFetch.api.kesehatan as any)[
|
||||
"jadwal-kegiatan"
|
||||
]["find-many"].get();
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
const res = await ApiFetch.api.kesehatan["jadwal-kegiatan"][
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
jadwalkegiatanState.findMany.data = res.data.data ?? [];
|
||||
jadwalkegiatanState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
toast.error("Gagal memuat data jadwal kegiatan");
|
||||
jadwalkegiatanState.findMany.data = [];
|
||||
jadwalkegiatanState.findMany.totalPages = 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
toast.error("Terjadi error saat load data");
|
||||
console.error("LOAD ERROR:", err);
|
||||
throw err;
|
||||
console.error("Gagal fetch jadwal kegiatan paginated:", err);
|
||||
jadwalkegiatanState.findMany.data = [];
|
||||
jadwalkegiatanState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
jadwalkegiatanState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -227,29 +236,42 @@ const jadwalkegiatanState = proxy({
|
||||
content: jadwalkegiatanState.edit.form.content,
|
||||
informasiJadwalKegiatan: {
|
||||
name: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.name,
|
||||
tanggal: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.tanggal,
|
||||
tanggal:
|
||||
jadwalkegiatanState.edit.form.informasiJadwalKegiatan.tanggal,
|
||||
waktu: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.waktu,
|
||||
lokasi: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.lokasi,
|
||||
lokasi:
|
||||
jadwalkegiatanState.edit.form.informasiJadwalKegiatan.lokasi,
|
||||
},
|
||||
layananJadwalKegiatan: {
|
||||
content: jadwalkegiatanState.edit.form.layananJadwalKegiatan.content,
|
||||
content:
|
||||
jadwalkegiatanState.edit.form.layananJadwalKegiatan.content,
|
||||
},
|
||||
deskripsiJadwalKegiatan: {
|
||||
deskripsi: jadwalkegiatanState.edit.form.deskripsiJadwalKegiatan.deskripsi,
|
||||
deskripsi:
|
||||
jadwalkegiatanState.edit.form.deskripsiJadwalKegiatan.deskripsi,
|
||||
},
|
||||
syaratKetentuanJadwalKegiatan: {
|
||||
content: jadwalkegiatanState.edit.form.syaratKetentuanJadwalKegiatan.content,
|
||||
content:
|
||||
jadwalkegiatanState.edit.form.syaratKetentuanJadwalKegiatan
|
||||
.content,
|
||||
},
|
||||
dokumenJadwalKegiatan: {
|
||||
content: jadwalkegiatanState.edit.form.dokumenJadwalKegiatan.content,
|
||||
content:
|
||||
jadwalkegiatanState.edit.form.dokumenJadwalKegiatan.content,
|
||||
},
|
||||
pendaftaranJadwalKegiatan: {
|
||||
name: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.name,
|
||||
tanggal: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.tanggal,
|
||||
namaOrangtua: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.namaOrangtua,
|
||||
nomor: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.nomor,
|
||||
alamat: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.alamat,
|
||||
catatan: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.catatan,
|
||||
tanggal:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.tanggal,
|
||||
namaOrangtua:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan
|
||||
.namaOrangtua,
|
||||
nomor:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.nomor,
|
||||
alamat:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.alamat,
|
||||
catatan:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.catatan,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -286,7 +308,7 @@ const jadwalkegiatanState = proxy({
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string){
|
||||
async byId(id: string) {
|
||||
try {
|
||||
jadwalkegiatanState.delete.loading = true;
|
||||
const res = await fetch(`/api/kesehatan/jadwal-kegiatan/del/${id}`, {
|
||||
@@ -305,7 +327,7 @@ const jadwalkegiatanState = proxy({
|
||||
} finally {
|
||||
jadwalkegiatanState.delete.loading = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -50,18 +51,50 @@ const apbdes = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.APBDesGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
file: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.apbdes["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
apbdes.findMany.data = res.data?.data ?? [];
|
||||
data: null as
|
||||
| Prisma.APBDesGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
file: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
apbdes.findMany.loading = true; // Use the full path to access the property
|
||||
apbdes.findMany.page = page;
|
||||
apbdes.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.apbdes[
|
||||
"findMany"
|
||||
].get({
|
||||
query
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
apbdes.findMany.data = res.data.data || [];
|
||||
apbdes.findMany.total = res.data.total || 0;
|
||||
apbdes.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pegawai:", res.data?.message);
|
||||
apbdes.findMany.data = [];
|
||||
apbdes.findMany.total = 0;
|
||||
apbdes.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pegawai:", error);
|
||||
apbdes.findMany.data = [];
|
||||
apbdes.findMany.total = 0;
|
||||
apbdes.findMany.totalPages = 1;
|
||||
} finally {
|
||||
apbdes.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -60,16 +60,22 @@ const desaAntikorupsi = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
desaAntikorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
desaAntikorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
desaAntikorupsi.findMany.page = page;
|
||||
desaAntikorupsi.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
desaAntikorupsi.findMany.data = res.data.data || [];
|
||||
desaAntikorupsi.findMany.total = res.data.total || 0;
|
||||
@@ -305,20 +311,25 @@ const kategoriDesaAntiKorupsi = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
kategoriDesaAntiKorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
kategoriDesaAntiKorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
kategoriDesaAntiKorupsi.findMany.page = page;
|
||||
kategoriDesaAntiKorupsi.findMany.search = search;
|
||||
try {
|
||||
const res = await ApiFetch.api.landingpage.kategoridak[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.kategoridak["findMany"].get({
|
||||
query,
|
||||
});
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriDesaAntiKorupsi.findMany.data = res.data.data || [];
|
||||
kategoriDesaAntiKorupsi.findMany.total = res.data.total || 0;
|
||||
kategoriDesaAntiKorupsi.findMany.totalPages = res.data.totalPages || 1;
|
||||
kategoriDesaAntiKorupsi.findMany.totalPages =
|
||||
res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load media sosial:", res.data?.message);
|
||||
kategoriDesaAntiKorupsi.findMany.data = [];
|
||||
@@ -363,27 +374,30 @@ const kategoriDesaAntiKorupsi = proxy({
|
||||
try {
|
||||
kategoriDesaAntiKorupsi.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/kategoridak/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/landingpage/kategoridak/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kategori desa anti korupsi berhasil dihapus");
|
||||
toast.success(
|
||||
result.message || "Kategori desa anti korupsi berhasil dihapus"
|
||||
);
|
||||
await kategoriDesaAntiKorupsi.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kategori desa anti korupsi");
|
||||
toast.error(
|
||||
result?.message || "Gagal menghapus kategori desa anti korupsi"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kategori desa anti korupsi");
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat menghapus kategori desa anti korupsi"
|
||||
);
|
||||
} finally {
|
||||
kategoriDesaAntiKorupsi.delete.loading = false;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,13 @@ const responden = proxy({
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
tanggal: this.form.tanggal,
|
||||
jenisKelaminId: this.form.jenisKelaminId,
|
||||
ratingId: this.form.ratingId,
|
||||
kelompokUmurId: this.form.kelompokUmurId,
|
||||
}),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -58,16 +59,43 @@ const prestasiDesa = proxy({
|
||||
Prisma.PrestasiDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategori: true;
|
||||
kategori: {
|
||||
select: {
|
||||
id: true;
|
||||
name: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.prestasidesa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
prestasiDesa.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
prestasiDesa.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
prestasiDesa.findMany.page = page;
|
||||
prestasiDesa.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.prestasidesa["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
prestasiDesa.findMany.data = res.data.data ?? [];
|
||||
prestasiDesa.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
prestasiDesa.findMany.data = [];
|
||||
prestasiDesa.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch prestasi desa paginated:", err);
|
||||
prestasiDesa.findMany.data = [];
|
||||
prestasiDesa.findMany.totalPages = 1;
|
||||
} finally {
|
||||
prestasiDesa.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -283,12 +311,34 @@ const kategoriPrestasi = proxy({
|
||||
id: string;
|
||||
name: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.kategoriprestasi[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
kategoriPrestasi.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kategoriPrestasi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kategoriPrestasi.findMany.page = page;
|
||||
kategoriPrestasi.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.kategoriprestasi["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriPrestasi.findMany.data = res.data.data ?? [];
|
||||
kategoriPrestasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kategoriPrestasi.findMany.data = [];
|
||||
kategoriPrestasi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kategori prestasi paginated:", err);
|
||||
kategoriPrestasi.findMany.data = [];
|
||||
kategoriPrestasi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriPrestasi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -23,7 +23,12 @@ type ProgramInovasiForm = Prisma.ProgramInovasiGetPayload<{
|
||||
|
||||
const programInovasi = proxy({
|
||||
create: {
|
||||
form: {} as ProgramInovasiForm,
|
||||
form: {
|
||||
name: "",
|
||||
description: "",
|
||||
imageId: "",
|
||||
link: ""
|
||||
} as ProgramInovasiForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
// Ensure all required fields are non-null
|
||||
@@ -65,14 +70,19 @@ const programInovasi = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
programInovasi.findMany.loading = true; // Use the full path to access the property
|
||||
programInovasi.findMany.page = page;
|
||||
programInovasi.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.programinovasi[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
@@ -482,14 +492,19 @@ const mediaSosial = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
mediaSosial.findMany.loading = true; // Use the full path to access the property
|
||||
mediaSosial.findMany.page = page;
|
||||
try {
|
||||
mediaSosial.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.mediasosial[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
|
||||
@@ -58,16 +58,21 @@ const sdgsDesa = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||
sdgsDesa.findMany.loading = true; // Use the full path to access the property
|
||||
sdgsDesa.findMany.page = page;
|
||||
sdgsDesa.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
sdgsDesa.findMany.data = res.data.data || [];
|
||||
sdgsDesa.findMany.total = res.data.total || 0;
|
||||
@@ -89,7 +94,7 @@ const sdgsDesa = proxy({
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.SDGSDesaGetPayload<{
|
||||
data: null as Prisma.SdgsDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
|
||||
@@ -56,13 +56,17 @@ const dataLingkunganDesaState = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
dataLingkunganDesaState.findMany.loading = true; // Use the full path to access the property
|
||||
dataLingkunganDesaState.findMany.page = page;
|
||||
dataLingkunganDesaState.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res = await ApiFetch.api.lingkungan.datalingkungandesa["find-many"].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -67,10 +68,46 @@ const kegiatanDesa = proxy({
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.lingkungan.kegiatandesa["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
kegiatanDesa.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "", kategori = "") => {
|
||||
// Change to arrow function
|
||||
kegiatanDesa.findMany.loading = true; // Use the full path to access the property
|
||||
kegiatanDesa.findMany.page = page;
|
||||
kegiatanDesa.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
if (kategori) query.kategori = kategori;
|
||||
const res = await ApiFetch.api.lingkungan.kegiatandesa[
|
||||
"find-many"
|
||||
].get({
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kegiatanDesa.findMany.data = res.data.data || [];
|
||||
kegiatanDesa.findMany.total = res.data.total || 0;
|
||||
kegiatanDesa.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load kegiatan desa:",
|
||||
res.data?.message
|
||||
);
|
||||
kegiatanDesa.findMany.data = [];
|
||||
kegiatanDesa.findMany.total = 0;
|
||||
kegiatanDesa.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kegiatan desa:", error);
|
||||
kegiatanDesa.findMany.data = [];
|
||||
kegiatanDesa.findMany.total = 0;
|
||||
kegiatanDesa.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kegiatanDesa.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -244,6 +281,35 @@ const kegiatanDesa = proxy({
|
||||
kegiatanDesa.edit.form = { ...defaultKegiatanDesaForm };
|
||||
},
|
||||
},
|
||||
findFirst: {
|
||||
data: null as Prisma.KegiatanDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategoriKegiatan: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
// findFirst.load()
|
||||
async load(kategori?: string) {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await ApiFetch.api.lingkungan.kegiatandesa["find-first"].get({
|
||||
query: kategori ? { kategori } : {},
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
this.data = res.data.data || null;
|
||||
} else {
|
||||
this.data = null;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kegiatan desa terbaru:", err);
|
||||
this.data = null;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= KATEGORI kegiatan ========================================= //
|
||||
@@ -269,9 +335,7 @@ const kategoriKegiatan = proxy({
|
||||
}
|
||||
try {
|
||||
kategoriKegiatan.create.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.kategorikegiatan[
|
||||
"create"
|
||||
].post(kategoriKegiatan.create.form);
|
||||
const res = await ApiFetch.api.lingkungan.kategorikegiatan["create"].post(kategoriKegiatan.create.form);
|
||||
if (res.status === 200) {
|
||||
kategoriKegiatan.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
@@ -305,9 +369,7 @@ const kategoriKegiatan = proxy({
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/lingkungan/kategorikegiatan/${id}`
|
||||
);
|
||||
const res = await fetch(`/api/lingkungan/kategorikegiatan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kategoriKegiatan.findUnique.data = data.data ?? null;
|
||||
@@ -367,15 +429,12 @@ const kategoriKegiatan = proxy({
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/kategorikegiatan/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/lingkungan/kategorikegiatan/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
@@ -52,15 +52,19 @@ const pengelolaanSampah = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
pengelolaanSampah.findMany.loading = true; // Use the full path to access the property
|
||||
pengelolaanSampah.findMany.page = page;
|
||||
pengelolaanSampah.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res = await ApiFetch.api.lingkungan.pengelolaansampah[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
@@ -265,7 +269,7 @@ const keteranganSampah = proxy({
|
||||
try {
|
||||
keteranganSampah.create.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.pengelolaansampah.keteranganbankterdekat[
|
||||
await ApiFetch.api.lingkungan.keteranganbankterdekat[
|
||||
"create"
|
||||
].post(keteranganSampah.create.form);
|
||||
if (res.status === 200) {
|
||||
@@ -287,14 +291,47 @@ const keteranganSampah = proxy({
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.lingkungan.pengelolaansampah.keteranganbankterdekat[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
keteranganSampah.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
keteranganSampah.findMany.loading = true; // Use the full path to access the property
|
||||
keteranganSampah.findMany.page = page;
|
||||
keteranganSampah.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res = await ApiFetch.api.lingkungan.keteranganbankterdekat[
|
||||
"find-many"
|
||||
].get({
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
keteranganSampah.findMany.data = res.data.data || [];
|
||||
keteranganSampah.findMany.total = res.data.total || 0;
|
||||
keteranganSampah.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load keterangan bank sampah terdekat:",
|
||||
res.data?.message
|
||||
);
|
||||
keteranganSampah.findMany.data = [];
|
||||
keteranganSampah.findMany.total = 0;
|
||||
keteranganSampah.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading keterangan bank sampah terdekat:", error);
|
||||
keteranganSampah.findMany.data = [];
|
||||
keteranganSampah.findMany.total = 0;
|
||||
keteranganSampah.findMany.totalPages = 1;
|
||||
} finally {
|
||||
keteranganSampah.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KeteranganBankSampahTerdekatGetPayload<{
|
||||
@@ -302,7 +339,7 @@ const keteranganSampah = proxy({
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${id}`);
|
||||
const res = await fetch(`/api/lingkungan/keteranganbankterdekat/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
keteranganSampah.findUnique.data = data.data ?? null;
|
||||
@@ -324,7 +361,7 @@ const keteranganSampah = proxy({
|
||||
try {
|
||||
keteranganSampah.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/del/${id}`, {
|
||||
const response = await fetch(`/api/lingkungan/keteranganbankterdekat/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -359,7 +396,7 @@ const keteranganSampah = proxy({
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${id}`, {
|
||||
const response = await fetch(`/api/lingkungan/keteranganbankterdekat/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -404,7 +441,7 @@ const keteranganSampah = proxy({
|
||||
try {
|
||||
keteranganSampah.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${this.id}`,
|
||||
`/api/lingkungan/keteranganbankterdekat/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
|
||||
@@ -56,13 +56,17 @@ const programPenghijauanState = proxy({
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
programPenghijauanState.findMany.loading = true; // Use the full path to access the property
|
||||
programPenghijauanState.findMany.page = page;
|
||||
programPenghijauanState.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res = await ApiFetch.api.lingkungan.programpenghijauan["find-many"].get({
|
||||
query: { page, limit },
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
// ========================================= BEASISWA PENDAFTAR ========================================= //
|
||||
|
||||
const templateBeasiswaPendaftar = z.object({
|
||||
namaLengkap: z.string().min(1, "Nama harus diisi"),
|
||||
nik: z.string().min(1, "NIK harus diisi"),
|
||||
@@ -76,13 +79,34 @@ const beasiswaPendaftar = proxy({
|
||||
isActive: true;
|
||||
};
|
||||
}>[],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.pendidikan.beasiswa.beasiswapendaftar[
|
||||
"findMany"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
beasiswaPendaftar.findMany.data = res.data?.data ?? [];
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
beasiswaPendaftar.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
beasiswaPendaftar.findMany.page = page;
|
||||
beasiswaPendaftar.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.pendidikan.beasiswa.beasiswapendaftar["findMany"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
beasiswaPendaftar.findMany.data = res.data.data ?? [];
|
||||
beasiswaPendaftar.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
beasiswaPendaftar.findMany.data = [];
|
||||
beasiswaPendaftar.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch beasiswa pendaftar paginated:", err);
|
||||
beasiswaPendaftar.findMany.data = [];
|
||||
beasiswaPendaftar.findMany.totalPages = 1;
|
||||
} finally {
|
||||
beasiswaPendaftar.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -275,8 +299,260 @@ const beasiswaPendaftar = proxy({
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= KEUNGGULAN PROGRAM ========================================= //
|
||||
const templateKeunggulanProgram = z.object({
|
||||
judul: z.string().min(1, "Judul harus diisi"),
|
||||
deskripsi: z.string().min(1, "Deskripsi harus diisi"),
|
||||
});
|
||||
|
||||
const defaultKeunggulanProgram = {
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
};
|
||||
|
||||
const keunggulanProgram = proxy({
|
||||
create: {
|
||||
form: { ...defaultKeunggulanProgram },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateKeunggulanProgram.safeParse(
|
||||
keunggulanProgram.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
keunggulanProgram.create.loading = true;
|
||||
const res = await ApiFetch.api.pendidikan.beasiswa.keunggulanprogram[
|
||||
"create"
|
||||
].post(keunggulanProgram.create.form);
|
||||
if (res.status === 200) {
|
||||
keunggulanProgram.findMany.load();
|
||||
return toast.success("Data Berhasil Dibuat, Silahkan Menunggu Konfirmasi dari Admin di WhatsApp");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return toast.error("failed create");
|
||||
} finally {
|
||||
keunggulanProgram.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: [] as Prisma.KeunggulanProgramGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
keunggulanProgram.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
keunggulanProgram.findMany.page = page;
|
||||
keunggulanProgram.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.pendidikan.beasiswa.keunggulanprogram["findMany"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
keunggulanProgram.findMany.data = res.data.data ?? [];
|
||||
keunggulanProgram.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
keunggulanProgram.findMany.data = [];
|
||||
keunggulanProgram.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch keunggulan program paginated:", err);
|
||||
keunggulanProgram.findMany.data = [];
|
||||
keunggulanProgram.findMany.totalPages = 1;
|
||||
} finally {
|
||||
keunggulanProgram.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KeunggulanProgramGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/pendidikan/beasiswa/keunggulanprogram/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
keunggulanProgram.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
keunggulanProgram.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
keunggulanProgram.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async delete(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
keunggulanProgram.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/pendidikan/beasiswa/keunggulanprogram/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Keunggulan Program berhasil dihapus");
|
||||
await keunggulanProgram.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus keunggulan program");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus keunggulan program");
|
||||
} finally {
|
||||
keunggulanProgram.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultKeunggulanProgram },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/pendidikan/beasiswa/keunggulanprogram/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
judul: data.judul,
|
||||
deskripsi: data.deskripsi,
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading keunggulan program:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templateKeunggulanProgram.safeParse(
|
||||
keunggulanProgram.update.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
keunggulanProgram.update.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/pendidikan/beasiswa/keunggulanprogram/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
judul: this.form.judul,
|
||||
deskripsi: this.form.deskripsi,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
toast.success("Berhasil update keunggulan program");
|
||||
await keunggulanProgram.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update keunggulan program");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating keunggulan program:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update keunggulan program"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
keunggulanProgram.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
keunggulanProgram.update.id = "";
|
||||
keunggulanProgram.update.form = { ...defaultKeunggulanProgram };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const beasiswaDesaState = proxy({
|
||||
beasiswaPendaftar,
|
||||
keunggulanProgram
|
||||
});
|
||||
|
||||
export default beasiswaDesaState;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -51,13 +52,46 @@ const jenjangPendidikan = proxy({
|
||||
id: string;
|
||||
nama: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.infosekolahpaud.jenjangpendidikan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
jenjangPendidikan.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
jenjangPendidikan.findMany.loading = true; // Use the full path to access the property
|
||||
jenjangPendidikan.findMany.page = page;
|
||||
jenjangPendidikan.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.infosekolahpaud.jenjangpendidikan[
|
||||
"find-many"
|
||||
].get({
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
jenjangPendidikan.findMany.data = res.data.data || [];
|
||||
jenjangPendidikan.findMany.total = res.data.total || 0;
|
||||
jenjangPendidikan.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load jenjang pendidikan:",
|
||||
res.data?.message
|
||||
);
|
||||
jenjangPendidikan.findMany.data = [];
|
||||
jenjangPendidikan.findMany.total = 0;
|
||||
jenjangPendidikan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading jenjang pendidikan:", error);
|
||||
jenjangPendidikan.findMany.data = [];
|
||||
jenjangPendidikan.findMany.total = 0;
|
||||
jenjangPendidikan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
jenjangPendidikan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -299,18 +333,64 @@ const lembagaPendidikan = proxy({
|
||||
Prisma.LembagaGetPayload<{
|
||||
include: {
|
||||
jenjangPendidikan: true;
|
||||
siswa: true;
|
||||
pengajar: true;
|
||||
};
|
||||
}>
|
||||
}> & {
|
||||
siswa?: [];
|
||||
pengajar?: [];
|
||||
}
|
||||
> | null,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.infosekolahpaud.lembagapendidikan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
lembagaPendidikan.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "", jenjangPendidikan = "") => {
|
||||
lembagaPendidikan.findMany.loading = true;
|
||||
lembagaPendidikan.findMany.page = page;
|
||||
lembagaPendidikan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = {
|
||||
page,
|
||||
limit,
|
||||
...(search && { search }),
|
||||
...(jenjangPendidikan && { jenjangPendidikanId: jenjangPendidikan })
|
||||
};
|
||||
|
||||
console.log('Fetching lembaga with query:', query);
|
||||
|
||||
const res = await ApiFetch.api.pendidikan.infosekolahpaud.lembagapendidikan["find-many"].get({ query });
|
||||
|
||||
console.log('API Response:', res);
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
const data = Array.isArray(res.data.data) ? res.data.data : [];
|
||||
const total = typeof res.data.total === 'number' ? res.data.total : 0;
|
||||
const totalPages = typeof res.data.totalPages === 'number' ? res.data.totalPages : 1;
|
||||
|
||||
lembagaPendidikan.findMany.data = data;
|
||||
lembagaPendidikan.findMany.total = total;
|
||||
lembagaPendidikan.findMany.totalPages = totalPages;
|
||||
|
||||
console.log('Successfully loaded lembaga data:', {
|
||||
count: data.length,
|
||||
total,
|
||||
totalPages
|
||||
});
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load lembaga pendidikan:",
|
||||
res.data?.message || 'No error message provided'
|
||||
);
|
||||
throw new Error(res.data?.message || 'Failed to load lembaga pendidikan');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading lembaga pendidikan:", error);
|
||||
lembagaPendidikan.findMany.data = [];
|
||||
lembagaPendidikan.findMany.total = 0;
|
||||
lembagaPendidikan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
lembagaPendidikan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -554,16 +634,55 @@ const siswa = proxy({
|
||||
data: null as Array<
|
||||
Prisma.SiswaGetPayload<{
|
||||
include: {
|
||||
lembaga: true;
|
||||
lembaga: {
|
||||
include: {
|
||||
jenjangPendidikan: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.pendidikan.infosekolahpaud.siswa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
siswa.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
jenjangPendidikan: "",
|
||||
load: async (page = 1, limit = 10, search = "", jenjangPendidikan = "") => {
|
||||
siswa.findMany.loading = true;
|
||||
siswa.findMany.page = page;
|
||||
siswa.findMany.search = search;
|
||||
siswa.findMany.jenjangPendidikan = jenjangPendidikan;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
if (jenjangPendidikan) query.jenjangPendidikanName = jenjangPendidikan;
|
||||
const res = await ApiFetch.api.pendidikan.infosekolahpaud.siswa[
|
||||
"find-many"
|
||||
].get({
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
siswa.findMany.data = res.data.data || [];
|
||||
siswa.findMany.total = res.data.total || 0;
|
||||
siswa.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load siswa:",
|
||||
res.data?.message
|
||||
);
|
||||
siswa.findMany.data = [];
|
||||
siswa.findMany.total = 0;
|
||||
siswa.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading siswa:", error);
|
||||
siswa.findMany.data = [];
|
||||
siswa.findMany.total = 0;
|
||||
siswa.findMany.totalPages = 1;
|
||||
} finally {
|
||||
siswa.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -794,16 +913,56 @@ const pengajar = proxy({
|
||||
data: null as Array<
|
||||
Prisma.PengajarGetPayload<{
|
||||
include: {
|
||||
lembaga: true;
|
||||
lembaga: {
|
||||
include: {
|
||||
jenjangPendidikan: true
|
||||
}
|
||||
}
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.pendidikan.infosekolahpaud.pengajar[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
pengajar.findMany.data = res.data?.data ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
jenjangPendidikan: "",
|
||||
load: async (page = 1, limit = 10, search = "", jenjangPendidikan = "") => {
|
||||
// Change to arrow function
|
||||
pengajar.findMany.loading = true; // Use the full path to access the property
|
||||
pengajar.findMany.page = page;
|
||||
pengajar.findMany.search = search;
|
||||
pengajar.findMany.jenjangPendidikan = jenjangPendidikan;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
if (jenjangPendidikan) query.jenjangPendidikanId = jenjangPendidikan;
|
||||
const res = await ApiFetch.api.pendidikan.infosekolahpaud.pengajar[
|
||||
"find-many"
|
||||
].get({
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pengajar.findMany.data = res.data.data || [];
|
||||
pengajar.findMany.total = res.data.total || 0;
|
||||
pengajar.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load pengajar:",
|
||||
res.data?.message
|
||||
);
|
||||
pengajar.findMany.data = [];
|
||||
pengajar.findMany.total = 0;
|
||||
pengajar.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pengajar:", error);
|
||||
pengajar.findMany.data = [];
|
||||
pengajar.findMany.total = 0;
|
||||
pengajar.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pengajar.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -815,7 +974,9 @@ const pengajar = proxy({
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/pendidikan/infosekolahpaud/pengajar/${id}`);
|
||||
const res = await fetch(
|
||||
`/api/pendidikan/infosekolahpaud/pengajar/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
pengajar.findUnique.data = data.data ?? null;
|
||||
@@ -948,7 +1109,8 @@ const pengajar = proxy({
|
||||
result
|
||||
);
|
||||
throw new Error(
|
||||
result?.message || `Gagal mengupdate pengajar (${response.status})`
|
||||
result?.message ||
|
||||
`Gagal mengupdate pengajar (${response.status})`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -54,23 +55,46 @@ const dataPerpustakaan = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: [] as Prisma.DataPerpustakaanGetPayload<{
|
||||
include: {
|
||||
kategori: true;
|
||||
image: true;
|
||||
};
|
||||
}>[],
|
||||
loading: false,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.perpustakaandigital.dataperpustakaan[
|
||||
"findMany"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
dataPerpustakaan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
data: null as
|
||||
| Prisma.DataPerpustakaanGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategori: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "", kategori = "") => {
|
||||
dataPerpustakaan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
dataPerpustakaan.findMany.page = page;
|
||||
dataPerpustakaan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
if (kategori) query.kategori = kategori;
|
||||
|
||||
const res = await ApiFetch.api.pendidikan.perpustakaandigital.dataperpustakaan["findMany"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
dataPerpustakaan.findMany.data = res.data.data ?? [];
|
||||
dataPerpustakaan.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
dataPerpustakaan.findMany.data = [];
|
||||
dataPerpustakaan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch data perpustakaan paginated:", err);
|
||||
dataPerpustakaan.findMany.data = [];
|
||||
dataPerpustakaan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
dataPerpustakaan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.DataPerpustakaanGetPayload<{
|
||||
include: {
|
||||
@@ -293,14 +317,34 @@ const kategoriBuku = proxy({
|
||||
isActive: true;
|
||||
};
|
||||
}>[],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.perpustakaandigital.kategoribuku[
|
||||
"findMany"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
kategoriBuku.findMany.data = res.data?.data ?? [];
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kategoriBuku.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kategoriBuku.findMany.page = page;
|
||||
kategoriBuku.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.pendidikan.perpustakaandigital.kategoribuku["findMany"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriBuku.findMany.data = res.data.data ?? [];
|
||||
kategoriBuku.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kategoriBuku.findMany.data = [];
|
||||
kategoriBuku.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch data kategori buku paginated:", err);
|
||||
kategoriBuku.findMany.data = [];
|
||||
kategoriBuku.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriBuku.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -49,35 +49,38 @@ const daftarInformasiPublik = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
data: null as
|
||||
| Prisma.DaftarInformasiPublikGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
daftarInformasiPublik.findMany.loading = true; // Use the full path to access the property
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
daftarInformasiPublik.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
daftarInformasiPublik.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.ppid.daftarinformasipublik[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
daftarInformasiPublik.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ppid.daftarinformasipublik["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
daftarInformasiPublik.findMany.data = res.data.data || [];
|
||||
daftarInformasiPublik.findMany.total = res.data.total || 0;
|
||||
daftarInformasiPublik.findMany.totalPages = res.data.totalPages || 1;
|
||||
daftarInformasiPublik.findMany.data = res.data.data ?? [];
|
||||
daftarInformasiPublik.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
console.error("Failed to load daftar informasi publik:", res.data?.message);
|
||||
daftarInformasiPublik.findMany.data = [];
|
||||
daftarInformasiPublik.findMany.total = 0;
|
||||
daftarInformasiPublik.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading daftar informasi publik:", error);
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch daftar informasi publik paginated:", err);
|
||||
daftarInformasiPublik.findMany.data = [];
|
||||
daftarInformasiPublik.findMany.total = 0;
|
||||
daftarInformasiPublik.findMany.totalPages = 1;
|
||||
} finally {
|
||||
daftarInformasiPublik.findMany.loading = false;
|
||||
|
||||
@@ -348,18 +348,34 @@ const posisiOrganisasi = proxy({
|
||||
deskripsi: string | null;
|
||||
hierarki: number;
|
||||
}>,
|
||||
async load() {
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
posisiOrganisasi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
posisiOrganisasi.findMany.page = page;
|
||||
posisiOrganisasi.findMany.search = search;
|
||||
|
||||
try {
|
||||
const res = await ApiFetch.api.ppid.strukturppid.posisiorganisasi[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
// The API now returns the id field, so we can use it directly
|
||||
this.data = res.data?.data ?? [];
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.ppid.strukturppid.posisiorganisasi["find-many"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
posisiOrganisasi.findMany.data = res.data.data ?? [];
|
||||
posisiOrganisasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
posisiOrganisasi.findMany.data = [];
|
||||
posisiOrganisasi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
this.data = [];
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch posisi organisasi paginated:", err);
|
||||
posisiOrganisasi.findMany.data = [];
|
||||
posisiOrganisasi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
posisiOrganisasi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -438,9 +454,9 @@ const pegawai = proxy({
|
||||
|
||||
try {
|
||||
pegawai.create.loading = true;
|
||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
||||
"create"
|
||||
].post(pegawai.create.form);
|
||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai["create"].post(
|
||||
pegawai.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
toast.success("Pegawai berhasil ditambahkan");
|
||||
await pegawai.findMany.load();
|
||||
@@ -457,42 +473,55 @@ const pegawai = proxy({
|
||||
},
|
||||
|
||||
// In struktur-organisasi.ts
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
pegawai.findMany.loading = true; // Use the full path to access the property
|
||||
pegawai.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PegawaiPPIDGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
posisi: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
pegawai.findMany.loading = true; // Use the full path to access the property
|
||||
pegawai.findMany.page = page;
|
||||
pegawai.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pegawai.findMany.data = res.data.data || [];
|
||||
pegawai.findMany.total = res.data.total || 0;
|
||||
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pegawai:", res.data?.message);
|
||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
||||
"find-many"
|
||||
].get({
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pegawai.findMany.data = res.data.data || [];
|
||||
pegawai.findMany.total = res.data.total || 0;
|
||||
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pegawai:", res.data?.message);
|
||||
pegawai.findMany.data = [];
|
||||
pegawai.findMany.total = 0;
|
||||
pegawai.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pegawai:", error);
|
||||
pegawai.findMany.data = [];
|
||||
pegawai.findMany.total = 0;
|
||||
pegawai.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pegawai.findMany.loading = false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pegawai:", error);
|
||||
pegawai.findMany.data = [];
|
||||
pegawai.findMany.total = 0;
|
||||
pegawai.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pegawai.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as
|
||||
| (Prisma.PegawaiGetPayload<{
|
||||
@@ -521,12 +550,9 @@ findMany: {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
pegawai.delete.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/ppid/strukturppid/pegawai/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
const res = await fetch(`/api/ppid/strukturppid/pegawai/del/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
const json = await res.json();
|
||||
if (res.ok) {
|
||||
toast.success(json.message ?? "Berhasil hapus pegawai");
|
||||
@@ -555,15 +581,12 @@ findMany: {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ppid/strukturppid/pegawai/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/ppid/strukturppid/pegawai/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
@@ -677,7 +700,7 @@ findMany: {
|
||||
const stateStrukturPPID = proxy({
|
||||
stateStruktur,
|
||||
posisiOrganisasi,
|
||||
pegawai
|
||||
pegawai,
|
||||
});
|
||||
|
||||
export default stateStrukturPPID;
|
||||
|
||||
@@ -1,124 +1,43 @@
|
||||
import { proxy } from 'valtio'
|
||||
import { toast } from 'react-toastify'
|
||||
import ApiFetch from '@/lib/api-fetch'
|
||||
import { Prisma } from '@prisma/client'
|
||||
import { z } from 'zod'
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { proxy } from "valtio";
|
||||
import { toast } from "react-toastify";
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { z } from "zod";
|
||||
|
||||
// 1. Validasi Zod
|
||||
const userSchema = z.object({
|
||||
nama: z.string().min(1, 'Nama harus diisi'),
|
||||
email: z.string().email('Email tidak valid'),
|
||||
password: z.string().min(6, 'Password minimal 6 karakter'),
|
||||
roleId: z.string().optional(),
|
||||
})
|
||||
|
||||
const defaultForm = { nama: '', email: '', password: '', roleId: '' }
|
||||
|
||||
// 2. State Valtio
|
||||
// State Valtio
|
||||
const userState = proxy({
|
||||
// Register
|
||||
register: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const valid = userSchema.omit({ roleId: true }).safeParse(userState.register.form)
|
||||
if (!valid.success) {
|
||||
const err = valid.error.issues.map(i => i.message).join(', ')
|
||||
return toast.error(err)
|
||||
}
|
||||
try {
|
||||
userState.register.loading = true
|
||||
const res = await ApiFetch.api.user.register.post(userState.register.form)
|
||||
if (res.status === 200) {
|
||||
toast.success('Registrasi berhasil, silakan login')
|
||||
userState.register.form = { ...defaultForm } // reset
|
||||
} else {
|
||||
toast.error(res.data?.message || 'Gagal registrasi')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Terjadi kesalahan saat registrasi')
|
||||
} finally {
|
||||
userState.register.loading = false
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// Login
|
||||
login: {
|
||||
form: { email: '', password: '' },
|
||||
loading: false,
|
||||
async submit() {
|
||||
try {
|
||||
userState.login.loading = true
|
||||
const res = await ApiFetch.api.user.login.post(userState.login.form)
|
||||
if (res.status === 200) {
|
||||
toast.success('Login berhasil')
|
||||
const token = res.data?.data?.token
|
||||
if (typeof token === 'string') {
|
||||
localStorage.setItem('token', token)
|
||||
// Optional: simpan user role untuk otorisasi
|
||||
const user = res.data?.data?.user
|
||||
localStorage.setItem('user', JSON.stringify(user))
|
||||
}
|
||||
} else {
|
||||
toast.error(res.data?.message || 'Login gagal')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Terjadi kesalahan saat login')
|
||||
} finally {
|
||||
userState.login.loading = false
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// CRUD User (untuk admin)
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create(isAdmin = false) {
|
||||
const valid = userSchema.safeParse(userState.create.form)
|
||||
if (!valid.success) {
|
||||
const err = valid.error.issues.map(i => i.message).join(', ')
|
||||
return toast.error(err)
|
||||
}
|
||||
try {
|
||||
userState.create.loading = true
|
||||
const endpoint = isAdmin ? 'create' : 'register'
|
||||
const res = await ApiFetch.api.user[endpoint].post(userState.create.form)
|
||||
if (res.status === 200) {
|
||||
toast.success('User berhasil dibuat')
|
||||
userState.findMany.load() // refresh list
|
||||
userState.create.form = { ...defaultForm } // reset form
|
||||
} else {
|
||||
toast.error(res.data?.message || 'Gagal membuat user')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Gagal membuat user')
|
||||
} finally {
|
||||
userState.create.loading = false
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// Find Many
|
||||
findMany: {
|
||||
data: [] as Prisma.UserGetPayload<{ include: { role: true } }>[],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
async load() {
|
||||
this.loading = true
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
userState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
userState.findMany.page = page;
|
||||
userState.findMany.search = search;
|
||||
|
||||
try {
|
||||
const res = await ApiFetch.api.user.findMany.get()
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data || []
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res = await ApiFetch.api.user["findMany"].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
userState.findMany.data = res.data.data ?? [];
|
||||
userState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
userState.findMany.data = [];
|
||||
userState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Gagal muat data user')
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch user paginated:", err);
|
||||
userState.findMany.data = [];
|
||||
userState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
this.loading = false
|
||||
userState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -128,71 +47,20 @@ const userState = proxy({
|
||||
data: null as Prisma.UserGetPayload<{ include: { role: true } }> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
this.loading = true
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await fetch(`/api/user/findUnique/${id}`)
|
||||
const data = await res.json()
|
||||
const res = await fetch(`/api/user/findUnique/${id}`);
|
||||
const data = await res.json();
|
||||
if (res.status === 200) {
|
||||
this.data = data.data
|
||||
this.data = data.data;
|
||||
} else {
|
||||
toast.error(data.message)
|
||||
toast.error(data.message);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Gagal ambil data user')
|
||||
console.error(e);
|
||||
toast.error("Gagal ambil data user");
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// Update
|
||||
update: {
|
||||
id: '',
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await fetch(`/api/user/findUnique/${id}`)
|
||||
const data = await res.json()
|
||||
if (res.status === 200) {
|
||||
const user = data.data
|
||||
this.id = user.id
|
||||
this.form = {
|
||||
nama: user.nama,
|
||||
email: user.email,
|
||||
password: '', // jangan kirim password lama
|
||||
roleId: user.roleId,
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Gagal muat data')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await fetch(`/api/user/update/${this.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(this.form),
|
||||
})
|
||||
const data = await res.json()
|
||||
if (res.status === 200) {
|
||||
toast.success('Update berhasil')
|
||||
userState.findMany.load()
|
||||
} else {
|
||||
toast.error(data.message || 'Gagal update')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Gagal update user')
|
||||
} finally {
|
||||
this.loading = false
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -201,35 +69,63 @@ const userState = proxy({
|
||||
delete: {
|
||||
loading: false,
|
||||
async submit(id: string) {
|
||||
this.loading = true
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await fetch(`/api/user/del/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
const data = await res.json()
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.status === 200) {
|
||||
toast.success('User dinonaktifkan')
|
||||
userState.findMany.load()
|
||||
toast.success("User dinonaktifkan");
|
||||
userState.findMany.load();
|
||||
} else {
|
||||
toast.error(data.message || 'Gagal hapus')
|
||||
toast.error(data.message || "Gagal hapus");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Gagal hapus user')
|
||||
console.error(e);
|
||||
toast.error("Gagal hapus user");
|
||||
} finally {
|
||||
this.loading = false
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
updateActive: {
|
||||
loading: false,
|
||||
async submit(id: string, isActive: boolean) {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await fetch(`/api/user/updt`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ id, isActive }),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
if (res.status === 200 && data.success) {
|
||||
toast.success(data.message);
|
||||
userState.findMany.load(userState.findMany.page, 10, userState.findMany.search);
|
||||
} else {
|
||||
toast.error(data.message || "Gagal update status user");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
toast.error("Gagal update status user");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templateRole = z.object({
|
||||
name: z.string().min(1, "Nama harus diisi"),
|
||||
permissions: z.array(z.string()).min(1, "Permission harus diisi"),
|
||||
});
|
||||
|
||||
const defaultRole = {
|
||||
name: "",
|
||||
permissions: [] as string[],
|
||||
};
|
||||
|
||||
const roleState = proxy({
|
||||
@@ -247,10 +143,9 @@ const roleState = proxy({
|
||||
|
||||
try {
|
||||
roleState.create.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.role[
|
||||
"create"
|
||||
].post(roleState.create.form);
|
||||
const res = await ApiFetch.api.role["create"].post(
|
||||
roleState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
roleState.findMany.load();
|
||||
return toast.success("Data role Berhasil Dibuat");
|
||||
@@ -273,10 +168,7 @@ const roleState = proxy({
|
||||
}>[],
|
||||
loading: false,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.role[
|
||||
"findMany"
|
||||
].get();
|
||||
const res = await ApiFetch.api.role["findMany"].get();
|
||||
if (res.status === 200) {
|
||||
roleState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
@@ -291,9 +183,7 @@ const roleState = proxy({
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/role/${id}`
|
||||
);
|
||||
const res = await fetch(`/api/role/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
roleState.findUnique.data = data.data ?? null;
|
||||
@@ -315,22 +205,17 @@ const roleState = proxy({
|
||||
try {
|
||||
roleState.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/role/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/role/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Data role berhasil dihapus"
|
||||
);
|
||||
toast.success(result.message || "Data role berhasil dihapus");
|
||||
await roleState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus Data role");
|
||||
@@ -354,15 +239,12 @@ const roleState = proxy({
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/role/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/role/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
@@ -374,6 +256,7 @@ const roleState = proxy({
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
permissions: data.permissions,
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
@@ -400,18 +283,16 @@ const roleState = proxy({
|
||||
try {
|
||||
roleState.update.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/role/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
}),
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/role/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
permissions: this.form.permissions,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
@@ -451,6 +332,6 @@ const roleState = proxy({
|
||||
const user = proxy({
|
||||
userState,
|
||||
roleState,
|
||||
})
|
||||
});
|
||||
|
||||
export default user
|
||||
export default user;
|
||||
|
||||
111
src/app/admin/(dashboard)/auth/login-admin/page.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
'use client'
|
||||
import { apiFetchLogin } from '@/app/admin/auth/_lib/api_fetch_auth';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Flex, Image, Paper, Stack, Text, Title } from '@mantine/core';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { PhoneInput } from "react-international-phone";
|
||||
import "react-international-phone/style.css";
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
|
||||
|
||||
function Login() {
|
||||
const router = useRouter()
|
||||
const [phone, setPhone] = useState("")
|
||||
const [isError, setError] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
async function onLogin() {
|
||||
const nomor = phone.substring(1);
|
||||
if (nomor.length <= 4) return setError(true)
|
||||
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await apiFetchLogin({ nomor: nomor })
|
||||
if (response && response.success) {
|
||||
localStorage.setItem("hipmi_auth_code_id", response.kodeId);
|
||||
toast.success(response.message);
|
||||
router.push("/validasi", { scroll: false });
|
||||
} else {
|
||||
setLoading(false);
|
||||
toast.error(response?.message);
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
console.log("Error Login", error)
|
||||
toast.error("Terjadi kesalahan saat login")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg}>
|
||||
<Box px={{ base: 'md', md: 100 }} pb={50}>
|
||||
<Stack align='center' justify='center' h={"100vh"}>
|
||||
<Paper p={'xl'} radius={'md'} bg={colors['white-trans-1']}>
|
||||
<Stack align='center' gap={"lg"}>
|
||||
<Box>
|
||||
<Title ta={"center"} order={2} fw={'bold'} c={colors['blue-button']}>
|
||||
Login
|
||||
</Title>
|
||||
<Center>
|
||||
<Image src={"/darmasaba-icon.png"} alt="" w={80} />
|
||||
</Center>
|
||||
</Box>
|
||||
<Box>
|
||||
{/* <Box mb={10}>
|
||||
<Text c={colors['blue-button']} ta={"center"} fz={"sm"} fw={'bold'}>Masuk Untuk Akses Admin</Text>
|
||||
<TextInput
|
||||
label='Username'
|
||||
placeholder='Username'
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</Box> */}
|
||||
<PhoneInput
|
||||
countrySelectorStyleProps={{
|
||||
buttonStyle: {
|
||||
backgroundColor: colors['blue-button'],
|
||||
},
|
||||
}}
|
||||
inputStyle={{ width: "100%"}}
|
||||
defaultCountry="id"
|
||||
onChange={(val) => {
|
||||
setPhone(val);
|
||||
}}
|
||||
/>
|
||||
|
||||
{isError ? (
|
||||
toast.error("Masukan nomor telepon anda")
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Box py={20} >
|
||||
<Button
|
||||
fullWidth
|
||||
bg={colors['blue-button']}
|
||||
radius={'xl'}
|
||||
onClick={onLogin}
|
||||
loading={loading ? true : false}
|
||||
>Masuk
|
||||
</Button>
|
||||
</Box>
|
||||
<Flex justify={'center'} align={'center'}>
|
||||
<Text>Belum punya akun? </Text>
|
||||
<Button variant='transparent' component={Link} href={'/registrasi'}>
|
||||
<Text c={colors['blue-button']} fw={'bold'}>Registrasi</Text>
|
||||
</Button>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
||||
121
src/app/admin/(dashboard)/auth/registrasi-admin/page.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
||||
'use client'
|
||||
import { apiFetchRegister } from '@/app/admin/auth/_lib/api_fetch_auth';
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Checkbox, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { PhoneInput } from "react-international-phone";
|
||||
import "react-international-phone/style.css";
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
function Registrasi() {
|
||||
const [phone, setPhone] = useState("")
|
||||
const router = useRouter()
|
||||
const [value, setValue] = useState("")
|
||||
const [isValue, setIsValue] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
async function onRegistarsi() {
|
||||
if (value.length < 5) {
|
||||
toast.error("Username minimal 5 karakter!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.includes(" ")) {
|
||||
toast.error("Username tidak boleh ada spasi!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!phone) {
|
||||
toast.error("Nomor telepon wajib diisi!");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const respone = await apiFetchRegister({ nomor: phone, username: value });
|
||||
|
||||
if (respone.success) {
|
||||
router.push("/login", { scroll: false });
|
||||
toast.success(respone.message);
|
||||
|
||||
} else {
|
||||
setLoading(false);
|
||||
toast.error(respone.message);
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
console.log("Error Registrasi", error);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} gap={"22"} py={"xl"} h={"100vh"}>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Stack justify='center' align='center' h={"80vh"}>
|
||||
<Paper p={'xl'} radius={'md'} bg={colors['white-trans-1']}>
|
||||
<Stack align='center'>
|
||||
<Title order={2} fw={'bold'} c={colors['blue-button']}>
|
||||
Registrasi
|
||||
</Title>
|
||||
<Center>
|
||||
<Image src={"/darmasaba-icon.png"} alt="" w={80} />
|
||||
</Center>
|
||||
<Box>
|
||||
<TextInput placeholder='Username'
|
||||
label='Username'
|
||||
maxLength={50}
|
||||
|
||||
error={
|
||||
value.length > 0 && value.length < 5
|
||||
? "Minimal 5 karakter !"
|
||||
: value.includes(" ")
|
||||
? "Tidak boleh ada spasi"
|
||||
: isValue
|
||||
? "Masukan username anda"
|
||||
: ""
|
||||
}
|
||||
onChange={(val) => {
|
||||
val.currentTarget.value.length > 0 ? setIsValue(false) : "";
|
||||
setValue(val.currentTarget.value);
|
||||
}}
|
||||
required
|
||||
|
||||
/>
|
||||
<Box py={10}>
|
||||
<Text fz={"sm"} >Nomor Telepon</Text>
|
||||
<PhoneInput
|
||||
countrySelectorStyleProps={{
|
||||
buttonStyle: {
|
||||
backgroundColor: colors['blue-button'],
|
||||
},
|
||||
}}
|
||||
inputStyle={{ width: "100%" }}
|
||||
defaultCountry="id"
|
||||
onChange={(val) => {
|
||||
setPhone(val);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box pb={10}>
|
||||
<Checkbox
|
||||
label="Saya menyetujui syarat dan ketentuan yang berlaku"
|
||||
/>
|
||||
</Box>
|
||||
<Box pb={20} >
|
||||
<Button fullWidth bg={colors['blue-button']} radius={'xl'} onClick={onRegistarsi} loading={loading ? true : false}>Daftar</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Registrasi;
|
||||
38
src/app/admin/(dashboard)/auth/validasi-admin/page.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, PinInput, Stack, Text, Title } from '@mantine/core';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
function Validasi() {
|
||||
const router = useRouter()
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg}>
|
||||
<Box px={{ base: 'md', md: 100 }} pb={50}>
|
||||
<Stack align='center' justify='center' h={"100vh"}>
|
||||
<Paper p={'xl'} radius={'md'} bg={colors['white-trans-1']}>
|
||||
<Stack align='center' gap={"lg"}>
|
||||
<Box>
|
||||
<Title ta={"center"} order={2} fw={'bold'} c={colors['blue-button']}>
|
||||
Kode Verifikasi
|
||||
</Title>
|
||||
</Box>
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Text c={colors['blue-button']} ta={"center"} fz={"sm"} fw={'bold'}>Masukkan Kode Verifikasi</Text>
|
||||
<PinInput type={/^[0-9]*$/} inputType="tel" inputMode="numeric" />
|
||||
</Box>
|
||||
<Box py={20} >
|
||||
<Button onClick={() => router.push("/admin/landing-page/profile/program-inovasi")}>
|
||||
Page
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Validasi;
|
||||
@@ -1,9 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
||||
import { ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title, Tooltip } from '@mantine/core';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { IconFileText, IconBuildingStore, IconSparkles, IconUsers } from '@tabler/icons-react';
|
||||
|
||||
function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter()
|
||||
@@ -12,26 +13,35 @@ function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
||||
{
|
||||
label: "Pelayanan Surat Keterangan",
|
||||
value: "pelayanansuratketerangan",
|
||||
href: "/admin/desa/layanan/pelayanan_surat_keterangan"
|
||||
href: "/admin/desa/layanan/pelayanan_surat_keterangan",
|
||||
icon: <IconFileText size={18} stroke={1.8} />,
|
||||
tooltip: "Layanan terkait surat keterangan resmi desa"
|
||||
},
|
||||
{
|
||||
label: "Pelayanan Perizinan Berusaha",
|
||||
value: "pelayananperizinanusaha",
|
||||
href: "/admin/desa/layanan/pelayanan_perizinan_berusaha"
|
||||
href: "/admin/desa/layanan/pelayanan_perizinan_berusaha",
|
||||
icon: <IconBuildingStore size={18} stroke={1.8} />,
|
||||
tooltip: "Layanan untuk izin usaha masyarakat"
|
||||
},
|
||||
{
|
||||
label: "Pelayanan Telunjuk Sakti Desa",
|
||||
value: "pelayanantelunjuksaktidesa",
|
||||
href: "/admin/desa/layanan/pelayanan_telunjuk_sakti_desa"
|
||||
href: "/admin/desa/layanan/pelayanan_telunjuk_sakti_desa",
|
||||
icon: <IconSparkles size={18} stroke={1.8} />,
|
||||
tooltip: "Layanan inovasi khusus desa"
|
||||
},
|
||||
{
|
||||
label: "Pelayanan Penduduk Non-Permanent",
|
||||
value: "pelayanantelunjuknonpermanent",
|
||||
href: "/admin/desa/layanan/pelayanan_penduduk_non_permanent"
|
||||
value: "pelayanannonpermanent",
|
||||
href: "/admin/desa/layanan/pelayanan_penduduk_non_permanent",
|
||||
icon: <IconUsers size={18} stroke={1.8} />,
|
||||
tooltip: "Pendataan penduduk non-permanent"
|
||||
}
|
||||
];
|
||||
const curentTab = tabs.find(tab => tab.href === pathname)
|
||||
const [activeTab, setActiveTab] = useState<string | null>(curentTab?.value || tabs[0].value);
|
||||
|
||||
const currentTab = tabs.find(tab => tab.href === pathname)
|
||||
const [activeTab, setActiveTab] = useState<string | null>(currentTab?.value || tabs[0].value);
|
||||
|
||||
const handleTabChange = (value: string | null) => {
|
||||
const tab = tabs.find(t => t.value === value)
|
||||
@@ -49,24 +59,72 @@ function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
||||
}, [pathname])
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Title order={3}>Layanan</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 */}
|
||||
<></>
|
||||
<Stack gap="lg">
|
||||
<Title order={3} fw={700} style={{ color: "#1A1B1E" }}>Layanan</Title>
|
||||
<Tabs
|
||||
color={colors["blue-button"]}
|
||||
variant="pills"
|
||||
value={activeTab}
|
||||
onChange={handleTabChange}
|
||||
radius="lg"
|
||||
keepMounted={false}
|
||||
>
|
||||
{/* ✅ Scroll horizontal wrapper */}
|
||||
<ScrollArea type="auto" offsetScrollbars>
|
||||
<TabsList
|
||||
p="sm"
|
||||
style={{
|
||||
background: "linear-gradient(135deg, #e7ebf7, #f9faff)",
|
||||
borderRadius: "1rem",
|
||||
boxShadow: "inset 0 0 10px rgba(0,0,0,0.05)",
|
||||
display: "flex",
|
||||
flexWrap: "nowrap",
|
||||
gap: "0.5rem",
|
||||
paddingInline: "0.5rem", // ✅ biar nggak nempel ke tepi
|
||||
}}
|
||||
>
|
||||
{tabs.map((tab, i) => (
|
||||
<Tooltip
|
||||
key={i}
|
||||
label={tab.tooltip}
|
||||
position="bottom"
|
||||
withArrow
|
||||
transitionProps={{ transition: 'pop', duration: 200 }}
|
||||
>
|
||||
<TabsTab
|
||||
value={tab.value}
|
||||
leftSection={tab.icon}
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontSize: "0.9rem",
|
||||
transition: "all 0.2s ease",
|
||||
}}
|
||||
>
|
||||
{tab.label}
|
||||
</TabsTab>
|
||||
</Tooltip>
|
||||
))}
|
||||
</TabsList>
|
||||
</ScrollArea>
|
||||
|
||||
{tabs.map((tab, i) => (
|
||||
<TabsPanel
|
||||
key={i}
|
||||
value={tab.value}
|
||||
style={{
|
||||
padding: "1.5rem",
|
||||
background: "linear-gradient(180deg, #ffffff, #f5f6fa)",
|
||||
borderRadius: "1rem",
|
||||
boxShadow: "0 4px 16px rgba(0,0,0,0.05)",
|
||||
}}
|
||||
>
|
||||
{/* Konten dummy, bisa diganti sesuai routing */}
|
||||
<>{children}</>
|
||||
</TabsPanel>
|
||||
))}
|
||||
</Tabs>
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default LayoutTabsLayanan;
|
||||
export default LayoutTabsLayanan;
|
||||
|
||||