Compare commits
38 Commits
nico/19-au
...
nico/19-se
| Author | SHA1 | Date | |
|---|---|---|---|
| 0fc47c28ff | |||
| 8e25c91e85 | |||
| 068d8b1077 | |||
| 9f72e94557 | |||
| 79ad39fc55 | |||
| 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 |
2
.gitignore
vendored
@@ -48,3 +48,5 @@ next-env.d.ts
|
|||||||
|
|
||||||
.env.*
|
.env.*
|
||||||
|
|
||||||
|
*.tar.gz
|
||||||
|
|
||||||
|
|||||||
15
package.json
@@ -3,11 +3,9 @@
|
|||||||
"version": "0.1.5",
|
"version": "0.1.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack",
|
"dev": "bun --bun next dev",
|
||||||
"build": "next build",
|
"build": "bun --bun next build",
|
||||||
"start": "next start",
|
"start": "bun --bun next start"
|
||||||
"lint": "next lint",
|
|
||||||
"prisma:seed": "bun run prisma/seed.ts"
|
|
||||||
},
|
},
|
||||||
"prisma": {
|
"prisma": {
|
||||||
"seed": "bun run prisma/seed.ts"
|
"seed": "bun run prisma/seed.ts"
|
||||||
@@ -57,6 +55,8 @@
|
|||||||
"form-data": "^4.0.2",
|
"form-data": "^4.0.2",
|
||||||
"framer-motion": "^12.23.5",
|
"framer-motion": "^12.23.5",
|
||||||
"get-port": "^7.1.0",
|
"get-port": "^7.1.0",
|
||||||
|
"iron-session": "^8.0.4",
|
||||||
|
"jose": "^6.1.0",
|
||||||
"jotai": "^2.12.3",
|
"jotai": "^2.12.3",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"motion": "^12.4.1",
|
"motion": "^12.4.1",
|
||||||
"nanoid": "^5.1.5",
|
"nanoid": "^5.1.5",
|
||||||
"next": "15.1.6",
|
"next": "^15.5.2",
|
||||||
"next-view-transitions": "^0.3.4",
|
"next-view-transitions": "^0.3.4",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
"p-limit": "^6.2.0",
|
"p-limit": "^6.2.0",
|
||||||
@@ -73,15 +73,18 @@
|
|||||||
"prisma": "^6.3.1",
|
"prisma": "^6.3.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
"react-international-phone": "^4.6.0",
|
||||||
"react-leaflet": "^5.0.0",
|
"react-leaflet": "^5.0.0",
|
||||||
"react-simple-toasts": "^6.1.0",
|
"react-simple-toasts": "^6.1.0",
|
||||||
"react-toastify": "^11.0.5",
|
"react-toastify": "^11.0.5",
|
||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
"readdirp": "^4.1.1",
|
"readdirp": "^4.1.1",
|
||||||
"recharts": "^2.15.3",
|
"recharts": "^2.15.3",
|
||||||
|
"sharp": "^0.34.3",
|
||||||
"swr": "^2.3.2",
|
"swr": "^2.3.2",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"valtio": "^2.1.3",
|
"valtio": "^2.1.3",
|
||||||
|
"zlib": "^1.0.5",
|
||||||
"zod": "^3.24.3"
|
"zod": "^3.24.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,51 +1,99 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"month": "Jan",
|
"month": "Jan",
|
||||||
"year": 2025,
|
"year": 2025,
|
||||||
"totalUnemployment": 160,
|
"totalUnemployment": 160,
|
||||||
"educatedUnemployment": 95,
|
"educatedUnemployment": 95,
|
||||||
"uneducatedUnemployment": 65,
|
"uneducatedUnemployment": 65,
|
||||||
"percentageChange": null
|
"percentageChange": 0.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"month": "Feb",
|
"month": "Feb",
|
||||||
"year": 2025,
|
"year": 2025,
|
||||||
"totalUnemployment": 155,
|
"totalUnemployment": 158,
|
||||||
"educatedUnemployment": 90,
|
"educatedUnemployment": 93,
|
||||||
"uneducatedUnemployment": 65,
|
"uneducatedUnemployment": 65,
|
||||||
"percentageChange": -3.1
|
"percentageChange": -1.25
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"month": "Mar",
|
"month": "Mar",
|
||||||
"year": 2025,
|
"year": 2025,
|
||||||
"totalUnemployment": 150,
|
"totalUnemployment": 155,
|
||||||
"educatedUnemployment": 88,
|
"educatedUnemployment": 91,
|
||||||
"uneducatedUnemployment": 62,
|
"uneducatedUnemployment": 64,
|
||||||
"percentageChange": -3.2
|
"percentageChange": -1.90
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"month": "Apr",
|
"month": "Apr",
|
||||||
"year": 2025,
|
"year": 2025,
|
||||||
"totalUnemployment": 148,
|
"totalUnemployment": 152,
|
||||||
"educatedUnemployment": 85,
|
"educatedUnemployment": 89,
|
||||||
"uneducatedUnemployment": 63,
|
"uneducatedUnemployment": 63,
|
||||||
"percentageChange": -1.3
|
"percentageChange": -1.94
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"month": "Mei",
|
"month": "Mei",
|
||||||
"year": 2025,
|
"year": 2025,
|
||||||
"totalUnemployment": 145,
|
"totalUnemployment": 150,
|
||||||
"educatedUnemployment": 82,
|
"educatedUnemployment": 88,
|
||||||
"uneducatedUnemployment": 63,
|
"uneducatedUnemployment": 62,
|
||||||
"percentageChange": -2.0
|
"percentageChange": -1.32
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"month": "Jun",
|
"month": "Jun",
|
||||||
"year": 2025,
|
"year": 2025,
|
||||||
"totalUnemployment": 140,
|
"totalUnemployment": 148,
|
||||||
"educatedUnemployment": 80,
|
"educatedUnemployment": 87,
|
||||||
"uneducatedUnemployment": 60,
|
"uneducatedUnemployment": 61,
|
||||||
"percentageChange": -3.4
|
"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",
|
"id": "cmds9h9ko000pvnberdjnx64b",
|
||||||
"name": "1.1 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
"name": "1.1 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
||||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA</p>",
|
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9sjmz000svnbesv2133of",
|
"id": "cmds9sjmz000svnbesv2133of",
|
||||||
"name": "1.2 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA",
|
"name": "1.2 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA",
|
||||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA</p>",
|
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9tcpi000vvnbev3ebtlnt",
|
"id": "cmds9tcpi000vvnbev3ebtlnt",
|
||||||
"name": "1.3 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
"name": "1.3 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9twvj000yvnbep0pq8dzf",
|
"id": "cmds9twvj000yvnbep0pq8dzf",
|
||||||
"name": "1.4 PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA",
|
"name": "1.4 PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA",
|
||||||
"deskripsi": "<p>PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA</p>",
|
"deskripsi": "<p>PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9ugap0011vnbe118yv871",
|
"id": "cmds9ugap0011vnbe118yv871",
|
||||||
"name": "1.5 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA",
|
"name": "1.5 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA",
|
||||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA</p>",
|
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA</p>",
|
||||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
"kategoriId": "cmds9es2o000ivnbe1o0swrvh"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa35310014vnbe6qy6l1rz",
|
"id": "cmdsa35310014vnbe6qy6l1rz",
|
||||||
"name": "2.1 ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA",
|
"name": "2.1 ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA",
|
||||||
"deskripsi": "<p>ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA</p>",
|
"deskripsi": "<p>ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa46590017vnbepp3noso1",
|
"id": "cmdsa46590017vnbepp3noso1",
|
||||||
"name": "2.2 ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH",
|
"name": "2.2 ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH",
|
||||||
"deskripsi": "<p>ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH</p>",
|
"deskripsi": "<p>ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH</p>",
|
||||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa5m7z001avnbe4cvfrcz0",
|
"id": "cmdsa5m7z001avnbe4cvfrcz0",
|
||||||
"name": "2.3 TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI",
|
"name": "2.3 TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI",
|
||||||
"deskripsi": "<p>TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI</p>",
|
"deskripsi": "<p>TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI</p>",
|
||||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa8q5q001dvnbemch8j24x",
|
"id": "cmdsa8q5q001dvnbemch8j24x",
|
||||||
"name": "3.1 ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT",
|
"name": "3.1 ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT",
|
||||||
"deskripsi": "<p>ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT</p>",
|
"deskripsi": "<p>ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsa9lbi001gvnbequn2ba7m",
|
"id": "cmdsa9lbi001gvnbequn2ba7m",
|
||||||
"name": "3.2 ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA",
|
"name": "3.2 ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA",
|
||||||
"deskripsi": "<p>ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA</p>",
|
"deskripsi": "<p>ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsaa7aq001jvnbeizh04e67",
|
"id": "cmdsaa7aq001jvnbeizh04e67",
|
||||||
"name": "3.3 ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA",
|
"name": "3.3 ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA",
|
||||||
"deskripsi": "<p>ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA</p>",
|
"deskripsi": "<p>ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsaaw8d001mvnbek3tfefrk",
|
"id": "cmdsaaw8d001mvnbek3tfefrk",
|
||||||
"name": "3.4 ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT",
|
"name": "3.4 ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT",
|
||||||
"deskripsi": "<p>ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT</p>",
|
"deskripsi": "<p>ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsabhif001pvnbepm06hry6",
|
"id": "cmdsabhif001pvnbepm06hry6",
|
||||||
"name": "3.5 ADANYA MAKLUMAT PELAYANAN",
|
"name": "3.5 ADANYA MAKLUMAT PELAYANAN",
|
||||||
"deskripsi": "<p>ADANYA MAKLUMAT PELAYANAN</p>",
|
"deskripsi": "<p>ADANYA MAKLUMAT PELAYANAN</p>",
|
||||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
"kategoriId": "cmds9fr73000kvnbe6w281dcl"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsag40b001svnbe7krq9khc",
|
"id": "cmdsag40b001svnbe7krq9khc",
|
||||||
"name": "4.1 ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA",
|
"name": "4.1 ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA",
|
||||||
"deskripsi": "<p>ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA</p>",
|
"deskripsi": "<p>ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA</p>",
|
||||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsagkaf001vvnbejo26w8sa",
|
"id": "cmdsagkaf001vvnbejo26w8sa",
|
||||||
"name": "4.2 ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
"name": "4.2 ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||||
"deskripsi": "<p>ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
"deskripsi": "<p>ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsah4qe001yvnbeiy3mwrvb",
|
"id": "cmdsah4qe001yvnbeiy3mwrvb",
|
||||||
"name": "4.3 ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA",
|
"name": "4.3 ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA",
|
||||||
"deskripsi": "<p>ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA</p>",
|
"deskripsi": "<p>ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA</p>",
|
||||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsak5vn0021vnbemg86aab4",
|
"id": "cmdsak5vn0021vnbemg86aab4",
|
||||||
"name": "5.1 ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
"name": "5.1 ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||||
"deskripsi": "<p>ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
"deskripsi": "<p>ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
"kategoriId": "cmds9govb000mvnbesq8b4y99"
|
||||||
"fileId": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmdsalc800024vnbezgulhgrb",
|
"id": "cmdsalc800024vnbezgulhgrb",
|
||||||
"name": "5.2 ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
"name": "5.2 ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||||
"deskripsi": "<p>ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
"deskripsi": "<p>ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
"kategoriId": "cmds9govb000mvnbesq8b4y99"
|
||||||
"fileId": ""
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -2,31 +2,37 @@
|
|||||||
{
|
{
|
||||||
"id": "cmds8w2q60002vnbe6i8qhkuo",
|
"id": "cmds8w2q60002vnbe6i8qhkuo",
|
||||||
"name": "Telephone Desa Darmasaba",
|
"name": "Telephone Desa Darmasaba",
|
||||||
"iconUrl": "081239580000"
|
"iconUrl": "081239580000",
|
||||||
|
"imageId": "cmff3nv180003vn6h5jvedidq"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds8z7u20005vnbegyyvnbk0",
|
"id": "cmds8z7u20005vnbegyyvnbk0",
|
||||||
"name": "Email Desa Darmasaba",
|
"name": "Email Desa Darmasaba",
|
||||||
"iconUrl": "desadarmasaba@badungkab.go.id"
|
"iconUrl": "desadarmasaba@badungkab.go.id",
|
||||||
|
"imageId": "cmff3ll130001vn6hkhls3f5y"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds9023u0008vnbe3oxmhwyf",
|
"id": "cmds9023u0008vnbe3oxmhwyf",
|
||||||
"name": "Desa Darmasaba",
|
"name": "Desa Darmasaba",
|
||||||
"iconUrl": "https://www.youtube.com/channel/UCtPw9WOQO7d2HIKzKgel4Xg"
|
"iconUrl": "https://www.youtube.com/channel/UCtPw9WOQO7d2HIKzKgel4Xg",
|
||||||
|
"imageId": "cmff3joae0000vn6h8sgs0ilg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds90oul000bvnbe2bqkptoi",
|
"id": "cmds90oul000bvnbe2bqkptoi",
|
||||||
"name": "Pemerintah Desa Darmasaba",
|
"name": "Pemerintah Desa Darmasaba",
|
||||||
"iconUrl": "https://www.facebook.com/DarmasabaDesaku"
|
"iconUrl": "https://www.facebook.com/DarmasabaDesaku",
|
||||||
|
"imageId": "cmff3mtat0002vn6hs8vyyhdd"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds91i4e000evnbe8gtf1gub",
|
"id": "cmds91i4e000evnbe8gtf1gub",
|
||||||
"name": "ddarmasaba",
|
"name": "ddarmasaba",
|
||||||
"iconUrl": "https://www.instagram.com/ddarmasaba/"
|
"iconUrl": "https://www.instagram.com/ddarmasaba/",
|
||||||
|
"imageId": "cmff3oouh0004vn6hd94brzv9"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cmds92de5000hvnbemlu6sq5x",
|
"id": "cmds92de5000hvnbemlu6sq5x",
|
||||||
"name": "desa.darmasaba",
|
"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",
|
"id": "edit",
|
||||||
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
"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",
|
"id": "cmdr755pf0005vn5rp8tyuubw",
|
||||||
"name": "Dmangan",
|
"name": "Dmangan",
|
||||||
"description": "Darmasaba Aman Pangan",
|
"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",
|
"id": "cmdr76nqk0008vn5rdddvcxnr",
|
||||||
"name": "Bicara Darmasaba",
|
"name": "Bicara Darmasaba",
|
||||||
"description": "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",
|
"id": "cmdr77vbw000bvn5rvpmoq31s",
|
||||||
"name": "Bares",
|
"name": "Bares",
|
||||||
"description": "Darmasaba Recycling Stock/Exchange",
|
"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",
|
"id": "cmdr7bxtp000evn5rmy85wihx",
|
||||||
"name": "Sajjana Dharma Raksaka",
|
"name": "Sajjana Dharma Raksaka",
|
||||||
"description": "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",
|
"id": "cmdr7dlnk000hvn5r9lur3z35",
|
||||||
"name": "PDKT",
|
"name": "PDKT",
|
||||||
"description": "Perangkat Desa Kuat Teknologi",
|
"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",
|
"id": "cmdr7ftob000mvn5rfhgdtg8v",
|
||||||
"name": "GM",
|
"name": "GM",
|
||||||
"description": "Galah Melah",
|
"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",
|
"id": "cmdr7glue000pvn5r6onzslju",
|
||||||
"name": "Inovasi Desa Darmasaba",
|
"name": "Inovasi Desa Darmasaba",
|
||||||
"description": "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",
|
"id": "cmeppcwzk0000vn5exmudcipd",
|
||||||
"jenisInformasi": "Peraturan Desa",
|
"jenisInformasi": "Potensi Desa",
|
||||||
"deskripsi": "Dokumen yang berisi kebijakan dan regulasi desa",
|
"deskripsi": "<p>“Potensi desa adalah segenap sumber daya alam dan sumber daya manusia yang dimiliki desa sebagai modal dasar yang perlu dikelola dan dikembangkan bagi kelangsungan dan perkembangan desa. Adapun potensi yang dimiliki Desa Darmasaba yaitu:</p><ol><li><p>TPS3R Pudak Mesari</p></li><li><p>Bumdes Pudak Mesari</p></li><li><p>Pertanian</p></li><li><p>Jogging Track Tegeh Aban, Karang Gadon dan Munduk Uma Desa</p></li><li><p>Taman Beji Cengana</p></li><li><p>Dam Tanah Putih</p></li><li><p>Gumuh Sari Water Park</p></li><li><p>UMKM</p></li><li><p>Kawasan Kuliner</p></li><li><p>IKM berbasis Pengolahan Pangan</p></li><li><p>Genteng</p></li><li><p>Peternakan Ikan Lele</p></li><li><p>Pemotongan Daging”</p></li></ol>",
|
||||||
"tanggal": "15 Januari 2024"
|
"tanggal": "2021-05-25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cmeppieay0001vn5e8qe658ub",
|
||||||
|
"jenisInformasi": "Layanan Surat Keterangan Desa",
|
||||||
|
"deskripsi": "<p>“Desa Darmasaba menyediakan berbagai jenis layanan surat keterangan untuk kebutuhan administratif, antara lain:</p><ul><li><p>Surat Keterangan Domisili Organisasi</p></li><li><p>Surat Keterangan Penghasilan</p></li><li><p>Surat Keterangan Tidak Mampu</p></li><li><p>Surat Keterangan Kelahiran</p></li><li><p>Surat Keterangan Usaha</p></li><li><p>Surat Keterangan Tempat Usaha</p></li><li><p>Surat Keterangan Belum Kawin</p></li><li><p>Surat Keterangan Kelakuan Baik (Pengantar SKCK)</p></li><li><p>Surat Keterangan Kematian</p></li><li><p>Surat Keterangan Perbedaan Biodata Diri</p></li><li><p>Surat Keterangan Yatim/Piatu/Yatim Piatu<br>Untuk surat keterangan lainnya, masyarakat dapat berkonsultasi langsung ke kantor Perbekel Darmasaba.”<br><em>(Sumber: Laman Layanan Desa Darmasaba)</em></p></li></ul>",
|
||||||
|
"tanggal": "2025-02-21"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -81,11 +81,8 @@ model FileStorage {
|
|||||||
PelayananSuratKeteranganImage PelayananSuratKeterangan[] @relation("PelayananSuratKeteranganImage")
|
PelayananSuratKeteranganImage PelayananSuratKeterangan[] @relation("PelayananSuratKeteranganImage")
|
||||||
PelayananSuratKeteranganImage2 PelayananSuratKeterangan[] @relation("PelayananSuratKeteranganImage2")
|
PelayananSuratKeteranganImage2 PelayananSuratKeterangan[] @relation("PelayananSuratKeteranganImage2")
|
||||||
PasarDesa PasarDesa[]
|
PasarDesa PasarDesa[]
|
||||||
KontakDaruratKeamanan KontakDaruratKeamanan[]
|
|
||||||
KontakItem KontakItem[]
|
|
||||||
Pegawai Pegawai[]
|
Pegawai Pegawai[]
|
||||||
DesaDigital DesaDigital[]
|
DesaDigital DesaDigital[]
|
||||||
KolaborasiInovasi KolaborasiInovasi[]
|
|
||||||
InfoTekno InfoTekno[]
|
InfoTekno InfoTekno[]
|
||||||
PengaduanMasyarakat PengaduanMasyarakat[]
|
PengaduanMasyarakat PengaduanMasyarakat[]
|
||||||
KegiatanDesa KegiatanDesa[]
|
KegiatanDesa KegiatanDesa[]
|
||||||
@@ -93,13 +90,17 @@ model FileStorage {
|
|||||||
PejabatDesa PejabatDesa[]
|
PejabatDesa PejabatDesa[]
|
||||||
MediaSosial MediaSosial[]
|
MediaSosial MediaSosial[]
|
||||||
DesaAntiKorupsi DesaAntiKorupsi[]
|
DesaAntiKorupsi DesaAntiKorupsi[]
|
||||||
SDGSDesa SDGSDesa[]
|
SDGSDesa SdgsDesa[]
|
||||||
APBDesImage APBDes[] @relation("APBDesImage")
|
APBDesImage APBDes[] @relation("APBDesImage")
|
||||||
APBDesFile APBDes[] @relation("APBDesFile")
|
APBDesFile APBDes[] @relation("APBDesFile")
|
||||||
PrestasiDesa PrestasiDesa[]
|
PrestasiDesa PrestasiDesa[]
|
||||||
DataPerpustakaan DataPerpustakaan[]
|
DataPerpustakaan DataPerpustakaan[]
|
||||||
PegawaiPPID PegawaiPPID[]
|
PegawaiPPID PegawaiPPID[]
|
||||||
PerbekelDariMasaKeMasa PerbekelDariMasaKeMasa[]
|
PerbekelDariMasaKeMasa PerbekelDariMasaKeMasa[]
|
||||||
|
|
||||||
|
MitraKolaborasi MitraKolaborasi[]
|
||||||
|
|
||||||
|
ArtikelKesehatan ArtikelKesehatan[]
|
||||||
}
|
}
|
||||||
|
|
||||||
//========================================= MENU LANDING PAGE ========================================= //
|
//========================================= MENU LANDING PAGE ========================================= //
|
||||||
@@ -167,9 +168,9 @@ model KategoriDesaAntiKorupsi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//========================================= SDGS Desa ========================================= //
|
//========================================= SDGS Desa ========================================= //
|
||||||
model SDGSDesa {
|
model SdgsDesa {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique
|
name String
|
||||||
jumlah String
|
jumlah String
|
||||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||||
imageId String?
|
imageId String?
|
||||||
@@ -182,7 +183,7 @@ model SDGSDesa {
|
|||||||
//========================================= APBDes ========================================= //
|
//========================================= APBDes ========================================= //
|
||||||
model APBDes {
|
model APBDes {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique
|
name String
|
||||||
jumlah String
|
jumlah String
|
||||||
image FileStorage? @relation("APBDesImage", fields: [imageId], references: [id])
|
image FileStorage? @relation("APBDesImage", fields: [imageId], references: [id])
|
||||||
imageId String?
|
imageId String?
|
||||||
@@ -197,12 +198,12 @@ model APBDes {
|
|||||||
//========================================= PRESTASI DESA ========================================= //
|
//========================================= PRESTASI DESA ========================================= //
|
||||||
model PrestasiDesa {
|
model PrestasiDesa {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique
|
name String
|
||||||
deskripsi String @db.Text
|
deskripsi String @db.Text
|
||||||
kategori KategoriPrestasiDesa @relation(fields: [kategoriId], references: [id])
|
kategori KategoriPrestasiDesa @relation(fields: [kategoriId], references: [id])
|
||||||
kategoriId String
|
kategoriId String
|
||||||
image FileStorage @relation(fields: [imageId], references: [id])
|
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||||
imageId String
|
imageId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime @default(now())
|
deletedAt DateTime @default(now())
|
||||||
@@ -223,7 +224,7 @@ model KategoriPrestasiDesa {
|
|||||||
model Responden {
|
model Responden {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique
|
name String @unique
|
||||||
tanggal String // misal: 2025-05-01
|
tanggal DateTime @db.Date // misal: 2025-05-01
|
||||||
jenisKelamin JenisKelaminResponden @relation(fields: [jenisKelaminId], references: [id])
|
jenisKelamin JenisKelaminResponden @relation(fields: [jenisKelaminId], references: [id])
|
||||||
jenisKelaminId String
|
jenisKelaminId String
|
||||||
rating PilihanRatingResponden @relation(fields: [ratingId], references: [id])
|
rating PilihanRatingResponden @relation(fields: [ratingId], references: [id])
|
||||||
@@ -292,6 +293,9 @@ model PosisiOrganisasiPPID {
|
|||||||
pegawai PegawaiPPID[]
|
pegawai PegawaiPPID[]
|
||||||
strukturOrganisasi StrukturPPID[] // Relasi balik
|
strukturOrganisasi StrukturPPID[] // Relasi balik
|
||||||
parentId String?
|
parentId String?
|
||||||
|
isActive Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
||||||
children PosisiOrganisasiPPID[] @relation("Parent")
|
children PosisiOrganisasiPPID[] @relation("Parent")
|
||||||
}
|
}
|
||||||
@@ -968,8 +972,10 @@ model ArtikelKesehatan {
|
|||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
title String
|
title String
|
||||||
content String
|
content String
|
||||||
introduction Introduction @relation(fields: [introductionId], references: [id])
|
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||||
|
imageId String?
|
||||||
introductionId String
|
introductionId String
|
||||||
|
introduction Introduction @relation(fields: [introductionId], references: [id])
|
||||||
symptom Symptom @relation(fields: [symptomId], references: [id])
|
symptom Symptom @relation(fields: [symptomId], references: [id])
|
||||||
symptomId String
|
symptomId String
|
||||||
prevention Prevention @relation(fields: [preventionId], references: [id])
|
prevention Prevention @relation(fields: [preventionId], references: [id])
|
||||||
@@ -1212,71 +1218,51 @@ model LayananPolsek {
|
|||||||
|
|
||||||
// ========================================= KONTAK DARURAT ========================================= //
|
// ========================================= KONTAK DARURAT ========================================= //
|
||||||
model KontakDaruratKeamanan {
|
model KontakDaruratKeamanan {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
nama String // contoh: "Layanan Darurat", "Fasilitas Kesehatan"
|
nama String
|
||||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
icon String
|
||||||
imageId String?
|
kategori KontakItem @relation(fields: [kategoriId], references: [id])
|
||||||
kontakItems KontakItem[]
|
kategoriId String
|
||||||
createdAt DateTime @default(now())
|
kontakItems KontakDaruratToItem[]
|
||||||
updatedAt DateTime @updatedAt
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
deletedAt DateTime?
|
||||||
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
model KontakItem {
|
model KontakItem {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
nama String // contoh: "Polisi", "Ambulans", "Puskesmas Darmasaba"
|
nama String
|
||||||
nomorTelepon String
|
nomorTelepon String
|
||||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
icon String
|
||||||
imageId String?
|
createdAt DateTime @default(now())
|
||||||
kategori KontakDaruratKeamanan @relation(fields: [kategoriId], references: [id])
|
updatedAt DateTime @updatedAt
|
||||||
kategoriId String
|
deletedAt DateTime @default(now())
|
||||||
createdAt DateTime @default(now())
|
isActive Boolean @default(true)
|
||||||
updatedAt DateTime @updatedAt
|
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 ========================================= //
|
// ========================================= PENCEGAHAN KRIMINALITAS ========================================= //
|
||||||
model PencegahanKriminalitas {
|
model PencegahanKriminalitas {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
programKeamanan ProgramKeamanan @relation(fields: [programKeamananId], references: [id])
|
judul String
|
||||||
programKeamananId String
|
deskripsi String
|
||||||
tipsKeamanan TipsKeamanan @relation(fields: [tipsKeamananId], references: [id])
|
deskripsiSingkat String
|
||||||
tipsKeamananId String
|
linkVideo String
|
||||||
videoKeamanan VideoKeamanan @relation(fields: [videoKeamananId], references: [id])
|
createdAt DateTime @default(now())
|
||||||
videoKeamananId String
|
updatedAt DateTime @updatedAt
|
||||||
createdAt DateTime @default(now())
|
deletedAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
isActive Boolean @default(true)
|
||||||
deletedAt DateTime @default(now())
|
|
||||||
isActive Boolean @default(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
model ProgramKeamanan {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
nama String // contoh: "Ronda Malam"
|
|
||||||
deskripsi String? // jika mau tambahkan info detail
|
|
||||||
slug String @unique
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
PencegahanKriminalitas PencegahanKriminalitas[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model TipsKeamanan {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
judul String
|
|
||||||
konten String
|
|
||||||
slug String
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
PencegahanKriminalitas PencegahanKriminalitas[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model VideoKeamanan {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
judul String
|
|
||||||
deskripsi String?
|
|
||||||
videoUrl String // link youtube atau embed url
|
|
||||||
slug String
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
PencegahanKriminalitas PencegahanKriminalitas[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================= LAPORAN PUBLIK ========================================= //
|
// ========================================= LAPORAN PUBLIK ========================================= //
|
||||||
@@ -1285,11 +1271,13 @@ model LaporanPublik {
|
|||||||
judul String
|
judul String
|
||||||
lokasi String
|
lokasi String
|
||||||
tanggalWaktu DateTime
|
tanggalWaktu DateTime
|
||||||
status StatusLaporan
|
status StatusLaporan @default(Proses)
|
||||||
penanganan PenangananLaporanPublik[]
|
penanganan PenangananLaporanPublik[]
|
||||||
kronologi String? // Optional, bisa diisi detail kronologi
|
kronologi String? // Optional, bisa diisi detail kronologi
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
deletedAt DateTime @default(now())
|
||||||
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
model PenangananLaporanPublik {
|
model PenangananLaporanPublik {
|
||||||
@@ -1397,6 +1385,9 @@ model PosisiOrganisasi {
|
|||||||
pegawai Pegawai[]
|
pegawai Pegawai[]
|
||||||
strukturOrganisasi StrukturOrganisasi[] // Relasi balik
|
strukturOrganisasi StrukturOrganisasi[] // Relasi balik
|
||||||
StrukturOrganisasiPPID StrukturOrganisasiPPID[]
|
StrukturOrganisasiPPID StrukturOrganisasiPPID[]
|
||||||
|
isActive Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
@@map("posisi_organisasi")
|
@@map("posisi_organisasi")
|
||||||
}
|
}
|
||||||
@@ -1465,7 +1456,7 @@ model ProgramKemiskinan {
|
|||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
nama String
|
nama String
|
||||||
deskripsi String
|
deskripsi String
|
||||||
ikonUrl String?
|
icon String
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
statistikId String? @unique
|
statistikId String? @unique
|
||||||
statistik StatistikKemiskinan? @relation(fields: [statistikId], references: [id])
|
statistik StatistikKemiskinan? @relation(fields: [statistikId], references: [id])
|
||||||
@@ -1635,18 +1626,27 @@ model ProgramKreatif {
|
|||||||
|
|
||||||
// ========================================= KOLABORASI INOVASI ========================================= //
|
// ========================================= KOLABORASI INOVASI ========================================= //
|
||||||
model KolaborasiInovasi {
|
model KolaborasiInovasi {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
tahun Int
|
tahun Int
|
||||||
slug String @db.Text //deskripsi singkat
|
slug String @db.Text //deskripsi singkat
|
||||||
deskripsi String @db.Text //deskripsi panjang
|
deskripsi String @db.Text //deskripsi panjang
|
||||||
kolaborator String
|
kolaborator String
|
||||||
image FileStorage @relation(fields: [imageId], references: [id])
|
createdAt DateTime @default(now())
|
||||||
imageId String
|
updatedAt DateTime @updatedAt
|
||||||
createdAt DateTime @default(now())
|
deletedAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
isActive Boolean @default(true)
|
||||||
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 ========================================= //
|
// ========================================= INFO TEKHNOLOGI TEPAT GUNA ========================================= //
|
||||||
@@ -2090,26 +2090,66 @@ model KategoriBuku {
|
|||||||
DataPerpustakaan DataPerpustakaan[]
|
DataPerpustakaan DataPerpustakaan[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================= USER ========================================= //
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
nama String
|
username String
|
||||||
email String @unique
|
nomor String @unique
|
||||||
password String
|
role Role @relation(fields: [roleId], references: [id])
|
||||||
role Role @relation(fields: [roleId], references: [id])
|
roleId String @default("1")
|
||||||
roleId String
|
instansi String?
|
||||||
isActive Boolean @default(true)
|
UserSession UserSession? // Nama instansi (Puskesmas, Sekolah, dll)
|
||||||
createdAt DateTime @default(now())
|
isActive Boolean @default(true)
|
||||||
updatedAt DateTime @updatedAt
|
lastLogin DateTime?
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
deletedAt DateTime?
|
||||||
}
|
}
|
||||||
|
|
||||||
model Role {
|
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())
|
id String @id @default(cuid())
|
||||||
name String
|
isActive Boolean @default(true)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime @default(now())
|
nomor String
|
||||||
isActive Boolean @default(true)
|
otp Int
|
||||||
User User[]
|
}
|
||||||
|
|
||||||
|
// 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 ========================================= //
|
// ========================================= DATA PENDIDIKAN ========================================= //
|
||||||
|
|||||||
441
prisma/seed.ts
@@ -1,68 +1,160 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import profilePejabatDesa from "./data/landing-page/profile/profile.json";
|
import profilePejabatDesa from "./data/landing-page/profile/profile.json";
|
||||||
import penghargaan from "./data/landing-page/penghargaan/penghargaan.json";
|
|
||||||
import programInovasi from "./data/landing-page/profile/programInovasi.json";
|
import programInovasi from "./data/landing-page/profile/programInovasi.json";
|
||||||
import mediaSosial from "./data/landing-page/profile/mediaSosial.json";
|
import mediaSosial from "./data/landing-page/profile/mediaSosial.json";
|
||||||
|
import desaAntiKorupsi from "./data/landing-page/desa-anti-korupsi/desaantiKorpusi.json";
|
||||||
|
import kategoriDesaAntiKorupsi from "./data/landing-page/desa-anti-korupsi/kategoriDesaAntiKorupsi.json";
|
||||||
import sdgsDesa from "./data/landing-page/sdgs-desa/sdgs-desa.json";
|
import sdgsDesa from "./data/landing-page/sdgs-desa/sdgs-desa.json";
|
||||||
import apbdes from "./data/landing-page/apbdes/apbdes.json";
|
import apbdes from "./data/landing-page/apbdes/apbdes.json";
|
||||||
import pelayananSuratKeterangan from "./data/desa/layanan/pelayananSuratKeterangan.json";
|
import kategoriPrestasiDesa from "./data/landing-page/prestasi-desa/kategori-prestasi.json";
|
||||||
import categoryPengumuman from "./data/category-pengumuman.json";
|
import prestasiDesa from "./data/landing-page/prestasi-desa/prestasi-desa.json";
|
||||||
import kategoriBerita from "./data/kategori-berita.json";
|
import penghargaan from "./data/landing-page/penghargaan/penghargaan.json";
|
||||||
import caraMemperolehInformasi from "./data/list-caraMemperolehInformasi.json";
|
|
||||||
import caraMemperolehSalinanInformasi from "./data/list-caraMemperolehSalinanInformasi.json";
|
|
||||||
import jenisInformasiDiminta from "./data/list-jenisInfromasi.json";
|
|
||||||
import layanan from "./data/list-layanan.json";
|
|
||||||
import potensi from "./data/list-potensi.json";
|
|
||||||
import dasarHukumPPID from "./data/ppid/dasar-hukum-ppid/dasarhukumPPID.json";
|
|
||||||
import profilePPID from "./data/ppid/profile-ppid/profilePPid.json";
|
import profilePPID from "./data/ppid/profile-ppid/profilePPid.json";
|
||||||
|
import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||||
|
import posisiOrganisasiPPID from "./data/ppid/struktur-ppid/posisi-organisasi-PPID.json";
|
||||||
import visiMisiPPID from "./data/ppid/visi-misi-ppid/visimisiPPID.json";
|
import visiMisiPPID from "./data/ppid/visi-misi-ppid/visimisiPPID.json";
|
||||||
|
import dasarHukumPPID from "./data/ppid/dasar-hukum-ppid/dasarhukumPPID.json";
|
||||||
import jenisKelamin from "./data/ppid/ikm/jenis-kelamin/jenis-kelamin.json";
|
import jenisKelamin from "./data/ppid/ikm/jenis-kelamin/jenis-kelamin.json";
|
||||||
|
import daftarInformasiPublik from "./data/ppid/daftar-informasi-publik-desa-darmasaba/daftarInformasi.json";
|
||||||
import pilihanRatingResponden from "./data/ppid/ikm/pilihan-rating-responden/rating-responden.json";
|
import pilihanRatingResponden from "./data/ppid/ikm/pilihan-rating-responden/rating-responden.json";
|
||||||
import umurResponden from "./data/ppid/ikm/umur-responden/umur-responden.json";
|
import umurResponden from "./data/ppid/ikm/umur-responden/umur-responden.json";
|
||||||
|
import categoryPengumuman from "./data/category-pengumuman.json";
|
||||||
import pelayananPerizinanBerusaha from "./data/desa/layanan/pelayananPerizinanBerusaha.json";
|
import pelayananPerizinanBerusaha from "./data/desa/layanan/pelayananPerizinanBerusaha.json";
|
||||||
|
import pelayananSuratKeterangan from "./data/desa/layanan/pelayananSuratKeterangan.json";
|
||||||
|
import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSaktiDesa.json";
|
||||||
import pelayananPendudukNonPermanen from "./data/desa/layanan/pelayanaPendudukNonPermanen.json";
|
import pelayananPendudukNonPermanen from "./data/desa/layanan/pelayanaPendudukNonPermanen.json";
|
||||||
import sejarahDesa from "./data/desa/profile/sejarah_desa.json";
|
|
||||||
import visiMisiDesa from "./data/desa/profile/visi_misi_desa.json";
|
|
||||||
import lambangDesa from "./data/desa/profile/lambang_desa.json";
|
import lambangDesa from "./data/desa/profile/lambang_desa.json";
|
||||||
import maskotDesa from "./data/desa/profile/maskot_desa.json";
|
import maskotDesa from "./data/desa/profile/maskot_desa.json";
|
||||||
import profilPerbekel from "./data/desa/profile/profil_perbekel.json";
|
import profilPerbekel from "./data/desa/profile/profil_perbekel.json";
|
||||||
|
import sejarahDesa from "./data/desa/profile/sejarah_desa.json";
|
||||||
|
import visiMisiDesa from "./data/desa/profile/visi_misi_desa.json";
|
||||||
|
import detailDataPengangguran from "./data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json";
|
||||||
import kategoriProduk from "./data/ekonomi/pasar-desa/kategori-produk.json";
|
import kategoriProduk from "./data/ekonomi/pasar-desa/kategori-produk.json";
|
||||||
import hubunganOrganisasi from "./data/ekonomi/struktur-organisasi/hubungan-organisasi.json";
|
import hubunganOrganisasi from "./data/ekonomi/struktur-organisasi/hubungan-organisasi.json";
|
||||||
import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json";
|
|
||||||
import pegawai from "./data/ekonomi/struktur-organisasi/pegawai.json";
|
import pegawai from "./data/ekonomi/struktur-organisasi/pegawai.json";
|
||||||
import detailDataPengangguran from "./data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json";
|
import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json";
|
||||||
import tujuanEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
|
import kategoriBerita from "./data/kategori-berita.json";
|
||||||
import materiEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
|
|
||||||
import contohEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/contoh-kegiatan-di-desa-darmasaba.json";
|
import contohEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/contoh-kegiatan-di-desa-darmasaba.json";
|
||||||
import nilaiKonservasiAdat from "./data/lingkungan/konservasi-adat-bali/nilai-konservasi-adat.json";
|
import materiEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
|
||||||
|
import tujuanEdukasiLingkungan from "./data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
|
||||||
import bentukKonservasiBerdasarkanAdat from "./data/lingkungan/konservasi-adat-bali/bentuk-konservasi.json";
|
import bentukKonservasiBerdasarkanAdat from "./data/lingkungan/konservasi-adat-bali/bentuk-konservasi.json";
|
||||||
import filosofiTriHita from "./data/lingkungan/konservasi-adat-bali/filosofi-tri-hita.json";
|
import filosofiTriHita from "./data/lingkungan/konservasi-adat-bali/filosofi-tri-hita.json";
|
||||||
import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
import nilaiKonservasiAdat from "./data/lingkungan/konservasi-adat-bali/nilai-konservasi-adat.json";
|
||||||
|
import caraMemperolehInformasi from "./data/list-caraMemperolehInformasi.json";
|
||||||
|
import caraMemperolehSalinanInformasi from "./data/list-caraMemperolehSalinanInformasi.json";
|
||||||
|
import jenisInformasiDiminta from "./data/list-jenisInfromasi.json";
|
||||||
|
import potensi from "./data/list-potensi.json";
|
||||||
|
import fasilitasBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json";
|
||||||
|
import lokasiJadwalBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json";
|
||||||
|
import tujuanBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json";
|
||||||
|
import jenisProgramYangDiselenggarakan from "./data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json";
|
||||||
|
import tempatKegiatan from "./data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json";
|
||||||
import tujuanProgram2 from "./data/pendidikan/pendidikan-non-formal/tujuan-program2.json";
|
import tujuanProgram2 from "./data/pendidikan/pendidikan-non-formal/tujuan-program2.json";
|
||||||
import programUnggulan from "./data/pendidikan/program-pendidikan-anak/program-unggulan.json";
|
import programUnggulan from "./data/pendidikan/program-pendidikan-anak/program-unggulan.json";
|
||||||
import tujuanBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json";
|
import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
||||||
import lokasiJadwalBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json";
|
import roles from "./data/user/roles.json";
|
||||||
import fasilitasBimbinganBelajarDesa from "./data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json";
|
import users from "./data/user/users.json";
|
||||||
import tempatKegiatan from "./data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json";
|
import fileStorage from "./data/file-storage.json";
|
||||||
import jenisProgramYangDiselenggarakan from "./data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json";
|
|
||||||
import posisiOrganisasiPPID from "./data/ppid/struktur-ppid/posisi-organisasi-PPID.json";
|
|
||||||
import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
|
||||||
import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSaktiDesa.json";
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
// =========== 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 ===========
|
// =========== LANDING PAGE ===========
|
||||||
// =========== PROFILE ===========
|
// =========== SUBMENU PROFILE ===========
|
||||||
|
// =========== PROFILE PEJABAT DESA ===========
|
||||||
for (const p of profilePejabatDesa) {
|
for (const p of profilePejabatDesa) {
|
||||||
await prisma.pejabatDesa.upsert({
|
await prisma.pejabatDesa.upsert({
|
||||||
where: { id: p.id },
|
where: { id: p.id },
|
||||||
update: {
|
update: {
|
||||||
name: p.name,
|
name: p.name,
|
||||||
position: p.position,
|
position: p.position,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
name: p.name,
|
name: p.name,
|
||||||
position: p.position,
|
position: p.position,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -72,18 +164,35 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
// =========== PROGRAM INOVASI ===========
|
// =========== PROGRAM INOVASI ===========
|
||||||
for (const p of programInovasi) {
|
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({
|
await prisma.programInovasi.upsert({
|
||||||
where: { id: p.id },
|
where: { id: p.id },
|
||||||
update: {
|
update: {
|
||||||
name: p.name,
|
name: p.name,
|
||||||
description: p.description,
|
description: p.description,
|
||||||
link: p.link,
|
link: p.link,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
name: p.name,
|
name: p.name,
|
||||||
description: p.description,
|
description: p.description,
|
||||||
link: p.link,
|
link: p.link,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -96,16 +205,102 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
update: {
|
update: {
|
||||||
name: p.name,
|
name: p.name,
|
||||||
iconUrl: p.iconUrl,
|
iconUrl: p.iconUrl,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
name: p.name,
|
name: p.name,
|
||||||
iconUrl: p.iconUrl,
|
iconUrl: p.iconUrl,
|
||||||
|
imageId: p.imageId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("media sosial success ...");
|
console.log("media sosial success ...");
|
||||||
|
|
||||||
|
// =========== SUBMENU DESA ANTI KORUPSI ===========
|
||||||
|
// =========== KATEGORI DESA ANTI KORUPSI ===========
|
||||||
|
for (const k of kategoriDesaAntiKorupsi) {
|
||||||
|
await prisma.kategoriDesaAntiKorupsi.upsert({
|
||||||
|
where: { id: k.id },
|
||||||
|
update: {
|
||||||
|
name: k.name,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: k.id,
|
||||||
|
name: k.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("kategori desa anti korupsi success ...");
|
||||||
|
|
||||||
|
// =========== DESA ANTI KORUPSI ===========
|
||||||
|
for (const p of desaAntiKorupsi) {
|
||||||
|
await prisma.desaAntiKorupsi.upsert({
|
||||||
|
where: { id: p.id },
|
||||||
|
update: {
|
||||||
|
name: p.name,
|
||||||
|
deskripsi: p.deskripsi,
|
||||||
|
kategoriId: p.kategoriId,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: p.id,
|
||||||
|
name: p.name,
|
||||||
|
deskripsi: p.deskripsi,
|
||||||
|
kategoriId: p.kategoriId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("desa anti korupsi success ...");
|
||||||
|
|
||||||
|
// =========== KATEGORI DESA ANTI KORUPSI ===========
|
||||||
|
for (const p of kategoriDesaAntiKorupsi) {
|
||||||
|
await prisma.kategoriDesaAntiKorupsi.upsert({
|
||||||
|
where: { id: p.id },
|
||||||
|
update: {
|
||||||
|
name: p.name,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: p.id,
|
||||||
|
name: p.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("desa anti korupsi success ...");
|
||||||
|
|
||||||
|
// =========== KATEGORI PRESTASI DESA===========
|
||||||
|
for (const c of kategoriPrestasiDesa) {
|
||||||
|
await prisma.kategoriPrestasiDesa.upsert({
|
||||||
|
where: { id: c.id },
|
||||||
|
update: {
|
||||||
|
name: c.name,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: c.id,
|
||||||
|
name: c.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("kategori prestasi desa success ...");
|
||||||
|
|
||||||
|
// =========== PRESTASI DESA===========
|
||||||
|
for (const p of prestasiDesa) {
|
||||||
|
await prisma.prestasiDesa.upsert({
|
||||||
|
where: { id: p.id },
|
||||||
|
update: {
|
||||||
|
name: p.name,
|
||||||
|
deskripsi: p.deskripsi,
|
||||||
|
kategoriId: p.kategoriId,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: p.id,
|
||||||
|
name: p.name,
|
||||||
|
deskripsi: p.deskripsi,
|
||||||
|
kategoriId: p.kategoriId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("prestasi desa success ...");
|
||||||
|
|
||||||
// =========== PENGHARGAAN ===========
|
// =========== PENGHARGAAN ===========
|
||||||
for (const p of penghargaan) {
|
for (const p of penghargaan) {
|
||||||
await prisma.penghargaan.upsert({
|
await prisma.penghargaan.upsert({
|
||||||
@@ -160,30 +355,10 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
}
|
}
|
||||||
console.log("pelayanan surat keterangan success ...");
|
console.log("pelayanan surat keterangan success ...");
|
||||||
|
|
||||||
// =========== LAYANAN ===========
|
|
||||||
for (const l of layanan) {
|
|
||||||
await prisma.layanan.upsert({
|
|
||||||
where: {
|
|
||||||
name: l.name,
|
|
||||||
},
|
|
||||||
update: {
|
|
||||||
name: l.name,
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
name: l.name,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("layanan success ...");
|
|
||||||
|
|
||||||
// =========== SDGSDesa ===========
|
// =========== SDGSDesa ===========
|
||||||
for (const l of sdgsDesa) {
|
for (const l of sdgsDesa) {
|
||||||
await prisma.sDGSDesa.upsert({
|
await prisma.sdgsDesa.upsert({
|
||||||
where: {
|
where: { id: l.id },
|
||||||
name: l.name,
|
|
||||||
jumlah: l.jumlah,
|
|
||||||
},
|
|
||||||
update: {
|
update: {
|
||||||
name: l.name,
|
name: l.name,
|
||||||
jumlah: l.jumlah,
|
jumlah: l.jumlah,
|
||||||
@@ -201,8 +376,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
for (const l of apbdes) {
|
for (const l of apbdes) {
|
||||||
await prisma.aPBDes.upsert({
|
await prisma.aPBDes.upsert({
|
||||||
where: {
|
where: {
|
||||||
name: l.name,
|
id: l.id,
|
||||||
jumlah: l.jumlah,
|
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
name: l.name,
|
name: l.name,
|
||||||
@@ -217,6 +391,9 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("sdgs desa success ...");
|
console.log("sdgs desa success ...");
|
||||||
|
|
||||||
|
// =========== MENU DESA ===========
|
||||||
|
// =========== SUBMENU PROFILE ===========
|
||||||
|
// =========== SEJARAH DESA ===========
|
||||||
for (const l of sejarahDesa) {
|
for (const l of sejarahDesa) {
|
||||||
await prisma.sejarahDesa.upsert({
|
await prisma.sejarahDesa.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -236,6 +413,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("sejarah desa success ...");
|
console.log("sejarah desa success ...");
|
||||||
|
|
||||||
|
// =========== MASKOT DESA ===========
|
||||||
for (const l of maskotDesa) {
|
for (const l of maskotDesa) {
|
||||||
await prisma.maskotDesa.upsert({
|
await prisma.maskotDesa.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -255,6 +433,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("maskot desa success ...");
|
console.log("maskot desa success ...");
|
||||||
|
|
||||||
|
// =========== LAMBANG DESA ===========
|
||||||
for (const l of lambangDesa) {
|
for (const l of lambangDesa) {
|
||||||
await prisma.lambangDesa.upsert({
|
await prisma.lambangDesa.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -274,6 +453,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("lambang desa success ...");
|
console.log("lambang desa success ...");
|
||||||
|
|
||||||
|
// =========== PROFIL PERBEKEL ===========
|
||||||
for (const c of profilPerbekel) {
|
for (const c of profilPerbekel) {
|
||||||
await prisma.profilPerbekel.upsert({
|
await prisma.profilPerbekel.upsert({
|
||||||
where: { id: c.id },
|
where: { id: c.id },
|
||||||
@@ -298,6 +478,7 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
"✅ profilePerbekel seeded without imageId (editable later via UI)"
|
"✅ profilePerbekel seeded without imageId (editable later via UI)"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// =========== VISI MISI DESA ===========
|
||||||
for (const l of visiMisiDesa) {
|
for (const l of visiMisiDesa) {
|
||||||
await prisma.visiMisiDesa.upsert({
|
await prisma.visiMisiDesa.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -317,6 +498,35 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("visi misi desa success ...");
|
console.log("visi misi desa success ...");
|
||||||
|
|
||||||
|
// =========== MENU PPID ===========
|
||||||
|
// =========== SUBMENU PROFILE PPID ===========
|
||||||
|
for (const c of profilePPID) {
|
||||||
|
await prisma.profilePPID.upsert({
|
||||||
|
where: { id: c.id },
|
||||||
|
update: {
|
||||||
|
name: c.name,
|
||||||
|
biodata: c.biodata,
|
||||||
|
riwayat: c.riwayat,
|
||||||
|
pengalaman: c.pengalaman,
|
||||||
|
unggulan: c.unggulan,
|
||||||
|
// imageId tidak di-update
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: c.id,
|
||||||
|
name: c.name,
|
||||||
|
biodata: c.biodata,
|
||||||
|
riwayat: c.riwayat,
|
||||||
|
pengalaman: c.pengalaman,
|
||||||
|
unggulan: c.unggulan,
|
||||||
|
// imageId tidak di-create
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("✅ profilePPID seeded without imageId (editable later via UI)");
|
||||||
|
|
||||||
|
// =========== SUBMENU STRUKTUR PPID ===========
|
||||||
|
// =========== POSISI ORGANISASI PPID ===========
|
||||||
|
|
||||||
const flattenedPosisi = posisiOrganisasiPPID.flat();
|
const flattenedPosisi = posisiOrganisasiPPID.flat();
|
||||||
|
|
||||||
// ✅ Urutkan berdasarkan hierarki
|
// ✅ Urutkan berdasarkan hierarki
|
||||||
@@ -341,9 +551,9 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
create: p,
|
create: p,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("✅ Posisi organisasi berhasil");
|
console.log("posisi organisasi berhasil");
|
||||||
|
|
||||||
// 2. Seed Pegawai
|
// =========== PEGAWAI PPID ===========
|
||||||
const flattenedPegawai = pegawaiPPID.flat();
|
const flattenedPegawai = pegawaiPPID.flat();
|
||||||
for (const p of flattenedPegawai) {
|
for (const p of flattenedPegawai) {
|
||||||
await prisma.pegawaiPPID.upsert({
|
await prisma.pegawaiPPID.upsert({
|
||||||
@@ -352,7 +562,70 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
create: p,
|
create: p,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("✅ Pegawai berhasil");
|
console.log("pegawai berhasil");
|
||||||
|
|
||||||
|
// =========== SUBMENU VISI MISI PPID ===========
|
||||||
|
|
||||||
|
for (const v of visiMisiPPID) {
|
||||||
|
await prisma.visiMisiPPID.upsert({
|
||||||
|
where: {
|
||||||
|
id: v.id,
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
misi: v.misi,
|
||||||
|
visi: v.visi,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: v.id,
|
||||||
|
misi: v.misi,
|
||||||
|
visi: v.visi,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("visi misi PPID success ...");
|
||||||
|
|
||||||
|
// =========== SUBMENU DASAR HUKUM PPID ===========
|
||||||
|
for (const v of dasarHukumPPID) {
|
||||||
|
await prisma.dasarHukumPPID.upsert({
|
||||||
|
where: {
|
||||||
|
id: v.id,
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
judul: v.judul,
|
||||||
|
content: v.content,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: v.id,
|
||||||
|
judul: v.judul,
|
||||||
|
content: v.content,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("dasar hukum PPID success ...");
|
||||||
|
|
||||||
|
// =========== SUBMENU DAFTAR INFORMASI PUBLIK PPID ===========
|
||||||
|
for (const v of daftarInformasiPublik) {
|
||||||
|
// Convert string date to Date object
|
||||||
|
const tanggal = new Date(v.tanggal);
|
||||||
|
|
||||||
|
await prisma.daftarInformasiPublik.upsert({
|
||||||
|
where: {
|
||||||
|
id: v.id,
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
jenisInformasi: v.jenisInformasi,
|
||||||
|
deskripsi: v.deskripsi,
|
||||||
|
tanggal: tanggal,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
id: v.id,
|
||||||
|
jenisInformasi: v.jenisInformasi,
|
||||||
|
deskripsi: v.deskripsi,
|
||||||
|
tanggal: tanggal,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("daftar informasi publik PPID success ...");
|
||||||
|
|
||||||
for (const l of pelayananPerizinanBerusaha) {
|
for (const l of pelayananPerizinanBerusaha) {
|
||||||
await prisma.pelayananPerizinanBerusaha.upsert({
|
await prisma.pelayananPerizinanBerusaha.upsert({
|
||||||
@@ -486,48 +759,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
}
|
}
|
||||||
console.log("cara memperoleh salinan informasi success ...");
|
console.log("cara memperoleh salinan informasi success ...");
|
||||||
|
|
||||||
for (const c of profilePPID) {
|
|
||||||
await prisma.profilePPID.upsert({
|
|
||||||
where: { id: c.id },
|
|
||||||
update: {
|
|
||||||
name: c.name,
|
|
||||||
biodata: c.biodata,
|
|
||||||
riwayat: c.riwayat,
|
|
||||||
pengalaman: c.pengalaman,
|
|
||||||
unggulan: c.unggulan,
|
|
||||||
// imageId tidak di-update
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
id: c.id,
|
|
||||||
name: c.name,
|
|
||||||
biodata: c.biodata,
|
|
||||||
riwayat: c.riwayat,
|
|
||||||
pengalaman: c.pengalaman,
|
|
||||||
unggulan: c.unggulan,
|
|
||||||
// imageId tidak di-create
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.log("✅ profilePPID seeded without imageId (editable later via UI)");
|
|
||||||
|
|
||||||
for (const v of visiMisiPPID) {
|
|
||||||
await prisma.visiMisiPPID.upsert({
|
|
||||||
where: {
|
|
||||||
id: v.id,
|
|
||||||
},
|
|
||||||
update: {
|
|
||||||
misi: v.misi,
|
|
||||||
visi: v.visi,
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
id: v.id,
|
|
||||||
misi: v.misi,
|
|
||||||
visi: v.visi,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.log("visi misi PPID success ...");
|
|
||||||
|
|
||||||
for (const j of jenisKelamin) {
|
for (const j of jenisKelamin) {
|
||||||
await prisma.jenisKelaminResponden.upsert({
|
await prisma.jenisKelaminResponden.upsert({
|
||||||
where: {
|
where: {
|
||||||
@@ -576,24 +807,6 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
}
|
}
|
||||||
console.log("umur responden success ...");
|
console.log("umur responden success ...");
|
||||||
|
|
||||||
for (const v of dasarHukumPPID) {
|
|
||||||
await prisma.dasarHukumPPID.upsert({
|
|
||||||
where: {
|
|
||||||
id: v.id,
|
|
||||||
},
|
|
||||||
update: {
|
|
||||||
judul: v.judul,
|
|
||||||
content: v.content,
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
id: v.id,
|
|
||||||
judul: v.judul,
|
|
||||||
content: v.content,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.log("dasar hukum PPID success ...");
|
|
||||||
|
|
||||||
for (const k of kategoriProduk) {
|
for (const k of kategoriProduk) {
|
||||||
await prisma.kategoriProduk.upsert({
|
await prisma.kategoriProduk.upsert({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
|
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}>
|
<Paper p={"md"} miw={320}>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Image
|
<Image
|
||||||
|
loading="lazy"
|
||||||
src={images["darmasaba-icon"]}
|
src={images["darmasaba-icon"]}
|
||||||
alt="darmasaba"
|
alt="darmasaba"
|
||||||
w={100}
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
100
src/app/admin/(dashboard)/_com/iconMap.tsx
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/* 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,
|
||||||
|
IconAmbulance,
|
||||||
|
IconFiretruck,
|
||||||
|
IconBuilding,
|
||||||
|
IconAlertTriangle,
|
||||||
|
} 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'
|
||||||
|
| 'polisi'
|
||||||
|
| 'ambulans'
|
||||||
|
| 'pemadam'
|
||||||
|
| 'rumahSakit'
|
||||||
|
| 'bangunan'
|
||||||
|
| 'darurat'
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
polisi: IconShieldFilled,
|
||||||
|
ambulans: IconAmbulance,
|
||||||
|
pemadam: IconFiretruck,
|
||||||
|
rumahSakit: IconHospital,
|
||||||
|
bangunan: IconBuilding,
|
||||||
|
darurat: IconAlertTriangle
|
||||||
|
}
|
||||||
|
|
||||||
|
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,24 @@
|
|||||||
|
|
||||||
import { Box, rem, Select } from '@mantine/core';
|
import { Box, rem, Select } from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
|
IconAlertTriangle,
|
||||||
|
IconAmbulance,
|
||||||
|
IconBuilding,
|
||||||
|
IconCash,
|
||||||
IconChartLine,
|
IconChartLine,
|
||||||
IconChristmasTreeFilled,
|
IconChristmasTreeFilled,
|
||||||
IconClipboardTextFilled,
|
IconClipboardTextFilled,
|
||||||
IconDroplet,
|
IconDroplet,
|
||||||
|
IconFiretruck,
|
||||||
IconHome,
|
IconHome,
|
||||||
IconHomeEco,
|
IconHomeEco,
|
||||||
|
IconHospital,
|
||||||
IconLeaf,
|
IconLeaf,
|
||||||
IconRecycle,
|
IconRecycle,
|
||||||
IconScale,
|
IconScale,
|
||||||
|
IconSchool,
|
||||||
IconShieldFilled,
|
IconShieldFilled,
|
||||||
|
IconShoppingCart,
|
||||||
IconTent,
|
IconTent,
|
||||||
IconTrashFilled,
|
IconTrashFilled,
|
||||||
IconTree,
|
IconTree,
|
||||||
@@ -32,13 +40,23 @@ const iconMap = {
|
|||||||
scale: { label: 'Scale', icon: IconScale },
|
scale: { label: 'Scale', icon: IconScale },
|
||||||
clipboard: { label: 'Clipboard', icon: IconClipboardTextFilled },
|
clipboard: { label: 'Clipboard', icon: IconClipboardTextFilled },
|
||||||
trash: { label: 'Trash', icon: IconTrashFilled },
|
trash: { label: 'Trash', icon: IconTrashFilled },
|
||||||
lingkunganSehat: {label: 'Lingkungan Sehat', icon: IconHomeEco},
|
lingkunganSehat: { label: 'Lingkungan Sehat', icon: IconHomeEco },
|
||||||
sumberOksigen: {label: 'Sumber Oksigen', icon: IconChristmasTreeFilled},
|
sumberOksigen: { label: 'Sumber Oksigen', icon: IconChristmasTreeFilled },
|
||||||
ekonomiBerkelanjutan: {label: 'Ekonomi Berkelanjutan', icon: IconTrendingUp},
|
ekonomiBerkelanjutan: { label: 'Ekonomi Berkelanjutan', icon: IconTrendingUp },
|
||||||
mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled},
|
mencegahBencana: { label: 'Mencegah Bencana', icon: IconShieldFilled },
|
||||||
rumah: {label: 'Rumah', icon: IconHome},
|
rumah: { label: 'Rumah', icon: IconHome },
|
||||||
pohon: {label: 'Pohon', icon: IconTree},
|
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 },
|
||||||
|
polisi: { label: 'Polisi', icon: IconShieldFilled },
|
||||||
|
ambulans: { label: 'Ambulans', icon: IconAmbulance },
|
||||||
|
pemadam: { label: 'Pemadam', icon: IconFiretruck },
|
||||||
|
rumahSakit: { label: 'Rumah Sakit', icon: IconHospital },
|
||||||
|
bangunan: { label: 'Bangunan', icon: IconBuilding },
|
||||||
|
darurat: { label: 'Darurat', icon: IconAlertTriangle },
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,22 +2,30 @@
|
|||||||
|
|
||||||
import { Box, rem, Select } from '@mantine/core';
|
import { Box, rem, Select } from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
|
IconAmbulance,
|
||||||
|
IconCash,
|
||||||
IconChartLine,
|
IconChartLine,
|
||||||
IconChristmasTreeFilled,
|
IconChristmasTreeFilled,
|
||||||
IconClipboardTextFilled,
|
IconClipboardTextFilled,
|
||||||
IconDroplet,
|
IconDroplet,
|
||||||
|
IconFiretruck,
|
||||||
IconHome,
|
IconHome,
|
||||||
IconHomeEco,
|
IconHomeEco,
|
||||||
|
IconHospital,
|
||||||
IconLeaf,
|
IconLeaf,
|
||||||
IconRecycle,
|
IconRecycle,
|
||||||
IconScale,
|
IconScale,
|
||||||
|
IconSchool,
|
||||||
IconShieldFilled,
|
IconShieldFilled,
|
||||||
|
IconShoppingCart,
|
||||||
IconTent,
|
IconTent,
|
||||||
IconTrashFilled,
|
IconTrashFilled,
|
||||||
IconTree,
|
IconTree,
|
||||||
IconTrendingUp,
|
IconTrendingUp,
|
||||||
IconTrophy,
|
IconTrophy,
|
||||||
IconTruckFilled,
|
IconTruckFilled,
|
||||||
|
IconBuilding,
|
||||||
|
IconAlertTriangle
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
|
|
||||||
const iconMap = {
|
const iconMap = {
|
||||||
@@ -36,7 +44,17 @@ const iconMap = {
|
|||||||
mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled},
|
mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled},
|
||||||
rumah: {label: 'Rumah', icon: IconHome},
|
rumah: {label: 'Rumah', icon: IconHome},
|
||||||
pohon: {label: 'Pohon', icon: IconTree},
|
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},
|
||||||
|
polisi: {label: 'Polisi', icon: IconShieldFilled},
|
||||||
|
ambulans: {label: 'Ambulans', icon: IconAmbulance},
|
||||||
|
pemadam: {label: 'Pemadam', icon: IconFiretruck},
|
||||||
|
rumahSakit: {label: 'Rumah Sakit', icon: IconHospital},
|
||||||
|
bangunan: {label: 'Bangunan', icon: IconBuilding},
|
||||||
|
darurat: {label: 'Darurat', icon: IconAlertTriangle},
|
||||||
};
|
};
|
||||||
|
|
||||||
type IconKey = keyof typeof iconMap;
|
type IconKey = keyof typeof iconMap;
|
||||||
|
|||||||
@@ -74,18 +74,18 @@ const berita = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
search: "",
|
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.loading = true; // ✅ Akses langsung via nama path
|
||||||
berita.findMany.page = page;
|
berita.findMany.page = page;
|
||||||
berita.findMany.search = search;
|
berita.findMany.search = search;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const query: any = { page, limit };
|
const query: any = { page, limit };
|
||||||
if (search) query.search = search;
|
if (search) query.search = search;
|
||||||
if (kategori) query.kategori = kategori;
|
if (kategori) query.kategori = kategori;
|
||||||
|
|
||||||
const res = await ApiFetch.api.desa.berita["find-many"].get({ query });
|
const res = await ApiFetch.api.desa.berita["find-many"].get({ query });
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
berita.findMany.data = res.data.data ?? [];
|
berita.findMany.data = res.data.data ?? [];
|
||||||
berita.findMany.totalPages = res.data.totalPages ?? 1;
|
berita.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
@@ -368,11 +368,37 @@ const kategoriBerita = proxy({
|
|||||||
isActive: true;
|
isActive: true;
|
||||||
};
|
};
|
||||||
}>[],
|
}>[],
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
search: "",
|
||||||
const res = await ApiFetch.api.desa.kategoriberita["findMany"].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
kategoriBerita.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
kategoriBerita.findMany.data = res.data?.data ?? [];
|
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"),
|
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const templatePelayananPerizinanBerusaha = z.object({
|
const templatePelayananPerizinanBerusaha = z.object({
|
||||||
name: z.string().min(3, "Nama minimal 3 karakter"),
|
name: z.string().min(3, "Nama minimal 3 karakter"),
|
||||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||||
@@ -72,7 +71,6 @@ const pelayananPendudukNonPermanenForm = {
|
|||||||
deskripsi: "",
|
deskripsi: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const suratKeterangan = proxy({
|
const suratKeterangan = proxy({
|
||||||
create: {
|
create: {
|
||||||
form: { ...suratKeteranganForm },
|
form: { ...suratKeteranganForm },
|
||||||
@@ -113,16 +111,21 @@ const suratKeterangan = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
suratKeterangan.findMany.loading = true; // Use the full path to access the property
|
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.page = page;
|
||||||
|
suratKeterangan.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
const res = await ApiFetch.api.desa.layanan.pelayanansuratketerangan[
|
const res = await ApiFetch.api.desa.layanan.pelayanansuratketerangan[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
suratKeterangan.findMany.data = res.data.data || [];
|
suratKeterangan.findMany.data = res.data.data || [];
|
||||||
suratKeterangan.findMany.total = res.data.total || 0;
|
suratKeterangan.findMany.total = res.data.total || 0;
|
||||||
@@ -341,28 +344,34 @@ const pelayananTelunjukSaktiDesa = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
pelayananTelunjukSaktiDesa.findMany.loading = true; // Use the full path to access the property
|
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.page = page;
|
||||||
|
pelayananTelunjukSaktiDesa.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
const res = await ApiFetch.api.desa.layanan.pelayanantelunjuksaktidesa[
|
const res = await ApiFetch.api.desa.layanan.pelayanantelunjuksaktidesa[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
pelayananTelunjukSaktiDesa.findMany.data = res.data.data || [];
|
pelayananTelunjukSaktiDesa.findMany.data = res.data.data || [];
|
||||||
pelayananTelunjukSaktiDesa.findMany.total = res.data.total || 0;
|
pelayananTelunjukSaktiDesa.findMany.total = res.data.total || 0;
|
||||||
pelayananTelunjukSaktiDesa.findMany.totalPages = res.data.totalPages || 1;
|
pelayananTelunjukSaktiDesa.findMany.totalPages =
|
||||||
|
res.data.totalPages || 1;
|
||||||
} else {
|
} 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.data = [];
|
||||||
pelayananTelunjukSaktiDesa.findMany.total = 0;
|
suratKeterangan.findMany.total = 0;
|
||||||
pelayananTelunjukSaktiDesa.findMany.totalPages = 1;
|
suratKeterangan.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading telunjuk sakti desa:", error);
|
console.error("Error loading surat keterangan:", error);
|
||||||
pelayananTelunjukSaktiDesa.findMany.data = [];
|
pelayananTelunjukSaktiDesa.findMany.data = [];
|
||||||
pelayananTelunjukSaktiDesa.findMany.total = 0;
|
pelayananTelunjukSaktiDesa.findMany.total = 0;
|
||||||
pelayananTelunjukSaktiDesa.findMany.totalPages = 1;
|
pelayananTelunjukSaktiDesa.findMany.totalPages = 1;
|
||||||
@@ -410,7 +419,9 @@ const pelayananTelunjukSaktiDesa = proxy({
|
|||||||
);
|
);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
if (response.ok) {
|
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
|
await pelayananTelunjukSaktiDesa.findMany.load(); // refresh list
|
||||||
} else {
|
} else {
|
||||||
toast.error(result.message || "Gagal menghapus telunjuk sakti desa");
|
toast.error(result.message || "Gagal menghapus telunjuk sakti desa");
|
||||||
@@ -501,7 +512,9 @@ const pelayananTelunjukSaktiDesa = proxy({
|
|||||||
}
|
}
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
if (result.success) {
|
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
|
await pelayananTelunjukSaktiDesa.findMany.load(); // refresh list
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@@ -522,7 +535,7 @@ const pelayananTelunjukSaktiDesa = proxy({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const pelayananPerizinanBerusaha = proxy({
|
const pelayananPerizinanBerusaha = proxy({
|
||||||
findById: {
|
findById: {
|
||||||
@@ -596,9 +609,7 @@ const pelayananPerizinanBerusaha = proxy({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching pelayanan perizinan berusaha:", error);
|
console.error("Error fetching pelayanan perizinan berusaha:", error);
|
||||||
toast.error(
|
toast.error(
|
||||||
error instanceof Error
|
error instanceof Error ? error.message : "Gagal memuat data"
|
||||||
? error.message
|
|
||||||
: "Gagal memuat data"
|
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -713,9 +724,7 @@ const pelayananPendudukNonPermanen = proxy({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching pelayanan penduduk non permanen:", error);
|
console.error("Error fetching pelayanan penduduk non permanen:", error);
|
||||||
toast.error(
|
toast.error(
|
||||||
error instanceof Error
|
error instanceof Error ? error.message : "Gagal memuat data"
|
||||||
? error.message
|
|
||||||
: "Gagal memuat data"
|
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,16 +56,21 @@ const penghargaanState = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
penghargaanState.findMany.loading = true; // Use the full path to access the property
|
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.page = page;
|
||||||
|
penghargaanState.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
const res = await ApiFetch.api.desa.penghargaan[
|
const res = await ApiFetch.api.desa.penghargaan[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
penghargaanState.findMany.data = res.data.data || [];
|
penghargaanState.findMany.data = res.data.data || [];
|
||||||
penghargaanState.findMany.total = res.data.total || 0;
|
penghargaanState.findMany.total = res.data.total || 0;
|
||||||
|
|||||||
@@ -55,11 +55,39 @@ const category = proxy({
|
|||||||
pengumumans: number;
|
pengumumans: number;
|
||||||
};
|
};
|
||||||
})[],
|
})[],
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
search: "",
|
||||||
const res = await ApiFetch.api.desa.kategoripengumuman["findMany"].get();
|
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||||
if (res.status === 200) {
|
category.findMany.loading = true; // Use the full path to access the property
|
||||||
category.findMany.data = res.data?.data ?? [];
|
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,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||||
potensiDesa.findMany.loading = true; // Use the full path to access the property
|
potensiDesa.findMany.loading = true; // Use the full path to access the property
|
||||||
potensiDesa.findMany.page = page;
|
potensiDesa.findMany.page = page;
|
||||||
|
potensiDesa.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
const res = await ApiFetch.api.desa.potensi[
|
const res = await ApiFetch.api.desa.potensi[
|
||||||
"find-many"
|
"find-many"
|
||||||
@@ -298,11 +300,34 @@ const kategoriPotensi = proxy({
|
|||||||
isActive: true;
|
isActive: true;
|
||||||
};
|
};
|
||||||
}>[],
|
}>[],
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
search: "",
|
||||||
const res = await ApiFetch.api.desa.kategoripotensi["findMany"].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
kategoriPotensi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
kategoriPotensi.findMany.data = res.data?.data ?? [];
|
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({
|
const templateApbDesa = z.object({
|
||||||
tahun: z.number().min(4, "Tahun minimal 4 karakter"),
|
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"),
|
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 = {
|
const ApbDesaDefaultForm = {
|
||||||
@@ -54,32 +58,46 @@ const ApbDesa = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.ApbDesaGetPayload<{
|
| Prisma.ApbDesaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
pendapatan: true;
|
pendapatan: true;
|
||||||
belanja: true;
|
belanja: true;
|
||||||
pembiayaan: true;
|
pembiayaan: true;
|
||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
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 {
|
try {
|
||||||
this.loading = true;
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.apbdesa[
|
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.apbdesa[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get();
|
].get({ query });
|
||||||
if (res.status === 200) {
|
|
||||||
this.data = res.data?.data ?? [];
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
ApbDesa.findMany.data = res.data.data ?? [];
|
||||||
|
ApbDesa.findMany.totalPages =
|
||||||
|
res.data.totalPages ?? 1;
|
||||||
} else {
|
} else {
|
||||||
toast.error(res.data?.message || "Gagal mengambil APB Desa");
|
ApbDesa.findMany.data = [];
|
||||||
|
ApbDesa.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Find many error:", error);
|
console.error("Gagal fetch APB Desa paginated:", err);
|
||||||
toast.error("Gagal mengambil APB Desa");
|
ApbDesa.findMany.data = [];
|
||||||
|
ApbDesa.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
ApbDesa.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -106,13 +124,13 @@ const ApbDesa = proxy({
|
|||||||
throw new Error("Gagal mengambil APB Desa");
|
throw new Error("Gagal mengambil APB Desa");
|
||||||
}
|
}
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.message || "Gagal memuat APB Desa");
|
throw new Error(result.message || "Gagal memuat APB Desa");
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = result.data;
|
const data = result.data;
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.form = {
|
this.form = {
|
||||||
tahun: data.tahun || 0,
|
tahun: data.tahun || 0,
|
||||||
@@ -120,7 +138,7 @@ const ApbDesa = proxy({
|
|||||||
belanjaIds: data.belanja?.map((b: any) => b.id) || [],
|
belanjaIds: data.belanja?.map((b: any) => b.id) || [],
|
||||||
pembiayaanIds: data.pembiayaan?.map((p: any) => p.id) || [],
|
pembiayaanIds: data.pembiayaan?.map((p: any) => p.id) || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading APB Desa:", error);
|
console.error("Error loading APB Desa:", error);
|
||||||
@@ -189,7 +207,7 @@ const ApbDesa = proxy({
|
|||||||
data: null as Prisma.ApbDesaGetPayload<{
|
data: null as Prisma.ApbDesaGetPayload<{
|
||||||
include: { pendapatan: true; belanja: true; pembiayaan: true };
|
include: { pendapatan: true; belanja: true; pembiayaan: true };
|
||||||
}> | null,
|
}> | null,
|
||||||
|
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@@ -199,11 +217,11 @@ const ApbDesa = proxy({
|
|||||||
throw new Error("Gagal mengambil detail APB Desa");
|
throw new Error("Gagal mengambil detail APB Desa");
|
||||||
}
|
}
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.message || "Gagal mengambil data");
|
throw new Error(result.message || "Gagal mengambil data");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.data = result.data; // ✅ fix utama di sini
|
this.data = result.data; // ✅ fix utama di sini
|
||||||
return result.data;
|
return result.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -264,34 +282,32 @@ const pendapatan = proxy({
|
|||||||
data: null as any[] | null,
|
data: null as any[] | null,
|
||||||
page: 1,
|
page: 1,
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => {
|
search: "",
|
||||||
// Change to arrow function
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
pendapatan.findMany.loading = true; // Use the full path to access the property
|
pendapatan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
pendapatan.findMany.page = page;
|
pendapatan.findMany.page = page;
|
||||||
|
pendapatan.findMany.search = search;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res =
|
const query: any = { page, limit };
|
||||||
await ApiFetch.api.ekonomi.pendapatanaslidesa.pendapatanasli[
|
if (search) query.search = search;
|
||||||
"find-many"
|
|
||||||
].get({
|
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.pendapatanasli[
|
||||||
query: { page, limit },
|
"find-many"
|
||||||
});
|
].get({ query });
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
pendapatan.findMany.data = res.data.data || [];
|
pendapatan.findMany.data = res.data.data ?? [];
|
||||||
pendapatan.findMany.total = res.data.total || 0;
|
pendapatan.findMany.totalPages =
|
||||||
pendapatan.findMany.totalPages = res.data.totalPages || 1;
|
res.data.totalPages ?? 1;
|
||||||
} else {
|
} else {
|
||||||
console.error("Failed to load pendapatan:", res.data?.message);
|
|
||||||
pendapatan.findMany.data = [];
|
pendapatan.findMany.data = [];
|
||||||
pendapatan.findMany.total = 0;
|
|
||||||
pendapatan.findMany.totalPages = 1;
|
pendapatan.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Error loading pendapatan:", error);
|
console.error("Gagal fetch pendapatan asli desa paginated:", err);
|
||||||
pendapatan.findMany.data = [];
|
pendapatan.findMany.data = [];
|
||||||
pendapatan.findMany.total = 0;
|
|
||||||
pendapatan.findMany.totalPages = 1;
|
pendapatan.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
pendapatan.findMany.loading = false;
|
pendapatan.findMany.loading = false;
|
||||||
@@ -308,12 +324,15 @@ const pendapatan = proxy({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${id}`, {
|
const response = await fetch(
|
||||||
method: "GET",
|
`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "GET",
|
||||||
},
|
headers: {
|
||||||
});
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -349,16 +368,19 @@ const pendapatan = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
pendapatan.update.loading = true;
|
pendapatan.update.loading = true;
|
||||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${this.id}`, {
|
const response = await fetch(
|
||||||
method: "PUT",
|
`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${this.id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "PUT",
|
||||||
},
|
headers: {
|
||||||
body: JSON.stringify({
|
"Content-Type": "application/json",
|
||||||
name: this.form.name,
|
},
|
||||||
value: this.form.value,
|
body: JSON.stringify({
|
||||||
}),
|
name: this.form.name,
|
||||||
});
|
value: this.form.value,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -495,23 +517,37 @@ const belanja = proxy({
|
|||||||
name: string;
|
name: string;
|
||||||
value: number;
|
value: number;
|
||||||
}>,
|
}>,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
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 {
|
try {
|
||||||
this.loading = true;
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.belanja[
|
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.belanja[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get();
|
].get({ query });
|
||||||
if (res.status === 200) {
|
|
||||||
this.data = res.data?.data ?? [];
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
belanja.findMany.data = res.data.data ?? [];
|
||||||
|
belanja.findMany.totalPages =
|
||||||
|
res.data.totalPages ?? 1;
|
||||||
} else {
|
} else {
|
||||||
toast.error(res.data?.message || "Gagal mengambil Belanja");
|
belanja.findMany.data = [];
|
||||||
|
belanja.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Find many error:", error);
|
console.error("Gagal fetch Belanja paginated:", err);
|
||||||
toast.error("Gagal mengambil Belanja");
|
belanja.findMany.data = [];
|
||||||
|
belanja.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
belanja.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -525,12 +561,15 @@ const belanja = proxy({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/belanja/${id}`, {
|
const response = await fetch(
|
||||||
method: "GET",
|
`/api/ekonomi/pendapatanaslidesa/belanja/${id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "GET",
|
||||||
},
|
headers: {
|
||||||
});
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -566,16 +605,19 @@ const belanja = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
belanja.update.loading = true;
|
belanja.update.loading = true;
|
||||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/belanja/${this.id}`, {
|
const response = await fetch(
|
||||||
method: "PUT",
|
`/api/ekonomi/pendapatanaslidesa/belanja/${this.id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "PUT",
|
||||||
},
|
headers: {
|
||||||
body: JSON.stringify({
|
"Content-Type": "application/json",
|
||||||
name: this.form.name,
|
},
|
||||||
value: this.form.value,
|
body: JSON.stringify({
|
||||||
}),
|
name: this.form.name,
|
||||||
});
|
value: this.form.value,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -710,23 +752,37 @@ const pembiayaan = proxy({
|
|||||||
name: string;
|
name: string;
|
||||||
value: number;
|
value: number;
|
||||||
}>,
|
}>,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
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 {
|
try {
|
||||||
this.loading = true;
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.pembiayaan[
|
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.pembiayaan[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get();
|
].get({ query });
|
||||||
if (res.status === 200) {
|
|
||||||
this.data = res.data?.data ?? [];
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
pembiayaan.findMany.data = res.data.data ?? [];
|
||||||
|
pembiayaan.findMany.totalPages =
|
||||||
|
res.data.totalPages ?? 1;
|
||||||
} else {
|
} else {
|
||||||
toast.error(res.data?.message || "Gagal mengambil Pembiayaan");
|
pembiayaan.findMany.data = [];
|
||||||
|
pembiayaan.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Find many error:", error);
|
console.error("Gagal fetch Pembiayaan paginated:", err);
|
||||||
toast.error("Gagal mengambil Pembiayaan");
|
pembiayaan.findMany.data = [];
|
||||||
|
pembiayaan.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
pembiayaan.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -740,12 +796,15 @@ const pembiayaan = proxy({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pembiayaan/${id}`, {
|
const response = await fetch(
|
||||||
method: "GET",
|
`/api/ekonomi/pendapatanaslidesa/pembiayaan/${id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "GET",
|
||||||
},
|
headers: {
|
||||||
});
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -781,16 +840,19 @@ const pembiayaan = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
pembiayaan.update.loading = true;
|
pembiayaan.update.loading = true;
|
||||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pembiayaan/${this.id}`, {
|
const response = await fetch(
|
||||||
method: "PUT",
|
`/api/ekonomi/pendapatanaslidesa/pembiayaan/${this.id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "PUT",
|
||||||
},
|
headers: {
|
||||||
body: JSON.stringify({
|
"Content-Type": "application/json",
|
||||||
name: this.form.name,
|
},
|
||||||
value: this.form.value,
|
body: JSON.stringify({
|
||||||
}),
|
name: this.form.name,
|
||||||
});
|
value: this.form.value,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -71,12 +72,37 @@ const demografiPekerjaan = proxy({
|
|||||||
omit: { isActive: true };
|
omit: { isActive: true };
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.demografipekerjaan[
|
totalPages: 1,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
demografiPekerjaan.findMany.data = res.data?.data ?? [];
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -69,16 +70,37 @@ const jumlahPendudukMiskin = proxy({
|
|||||||
select: { id: true; year: true; totalPoorPopulation: true };
|
select: { id: true; year: true; totalPoorPopulation: true };
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
loading: false,
|
page: 1,
|
||||||
async load() {
|
totalPages: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.jumlahpendudukmiskin[
|
loading: false,
|
||||||
"find-many"
|
search: "",
|
||||||
].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
jumlahPendudukMiskin.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
jumlahPendudukMiskin.findMany.data = res.data?.data ?? [];
|
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: {
|
findUnique: {
|
||||||
data: null as Prisma.GrafikJumlahPendudukMiskinGetPayload<{
|
data: null as Prisma.GrafikJumlahPendudukMiskinGetPayload<{
|
||||||
select: { id: true; year: true; totalPoorPopulation: true };
|
select: { id: true; year: true; totalPoorPopulation: true };
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ const templateJumlahPengngguran = z.object({
|
|||||||
uneducatedUnemployment: z
|
uneducatedUnemployment: z
|
||||||
.number()
|
.number()
|
||||||
.min(1, "Pengangguran tidak pendidikan harus diisi"),
|
.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 = {
|
type JumlahPengangguran = {
|
||||||
@@ -29,7 +30,7 @@ type JumlahPengangguran = {
|
|||||||
|
|
||||||
const jumlahPengangguranForm: JumlahPengangguran = {
|
const jumlahPengangguranForm: JumlahPengangguran = {
|
||||||
month: "",
|
month: "",
|
||||||
year: 0,
|
year: new Date().getFullYear(), // Default to current year
|
||||||
totalUnemployment: 0,
|
totalUnemployment: 0,
|
||||||
educatedUnemployment: 0,
|
educatedUnemployment: 0,
|
||||||
uneducatedUnemployment: 0,
|
uneducatedUnemployment: 0,
|
||||||
@@ -60,13 +61,21 @@ const jumlahPengangguran = proxy({
|
|||||||
form: jumlahPengangguranForm,
|
form: jumlahPengangguranForm,
|
||||||
loading: false,
|
loading: false,
|
||||||
async create() {
|
async create() {
|
||||||
const cek = templateJumlahPengngguran.safeParse(
|
// Ensure all number fields are actual numbers
|
||||||
jumlahPengangguran.create.form
|
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) {
|
if (!cek.success) {
|
||||||
const err = `[${cek.error.issues
|
const err = `[${cek.error.issues
|
||||||
.map((v) => `${v.path.join(".")}`)
|
.map((v) => `${v.path.join(".")} (${v.message})`)
|
||||||
.join("\n")}] required`;
|
.join("\n")}]`;
|
||||||
toast.error(err);
|
toast.error(err);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -78,7 +87,7 @@ const jumlahPengangguran = proxy({
|
|||||||
].post(jumlahPengangguran.create.form);
|
].post(jumlahPengangguran.create.form);
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
const id = res.data?.data?.id;
|
const id = res.data?.id;
|
||||||
if (id) {
|
if (id) {
|
||||||
toast.success("Success create");
|
toast.success("Success create");
|
||||||
jumlahPengangguran.create.form = { ...jumlahPengangguranForm };
|
jumlahPengangguran.create.form = { ...jumlahPengangguranForm };
|
||||||
@@ -103,16 +112,40 @@ const jumlahPengangguran = proxy({
|
|||||||
omit: { isActive: true };
|
omit: { isActive: true };
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res =
|
totalPages: 1,
|
||||||
await ApiFetch.api.ekonomi.jumlahpengangguran.detaildatapengangguran[
|
loading: false,
|
||||||
"find-many"
|
search: "",
|
||||||
].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
jumlahPengangguran.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
jumlahPengangguran.findMany.data = res.data?.data ?? [];
|
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: {
|
findUnique: {
|
||||||
data: null as Prisma.DetailDataPengangguranGetPayload<{
|
data: null as Prisma.DetailDataPengangguranGetPayload<{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -61,13 +62,39 @@ const lowonganKerjaState = proxy({
|
|||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.LowonganPekerjaanGetPayload<{
|
| Prisma.LowonganPekerjaanGetPayload<{
|
||||||
omit: { isActive: true };
|
omit: {
|
||||||
|
isActive: true;
|
||||||
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.lowongankerja["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
loading: false,
|
||||||
lowonganKerjaState.findMany.data = res.data?.data ?? [];
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
|
lowonganKerjaState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
lowonganKerjaState.findMany.page = page;
|
||||||
|
lowonganKerjaState.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.ekonomi.lowongankerja["find-many"].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
lowonganKerjaState.findMany.data = res.data.data ?? [];
|
||||||
|
lowonganKerjaState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
lowonganKerjaState.findMany.data = [];
|
||||||
|
lowonganKerjaState.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch lowongan kerja paginated:", err);
|
||||||
|
lowonganKerjaState.findMany.data = [];
|
||||||
|
lowonganKerjaState.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
lowonganKerjaState.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -53,22 +54,47 @@ const pasarDesa = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as Array<
|
data: null as
|
||||||
Prisma.PasarDesaGetPayload<{
|
| Prisma.PasarDesaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
KategoriToPasar: {
|
KategoriToPasar: {
|
||||||
include: {
|
include: {
|
||||||
kategori: true;
|
kategori: true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
}>[]
|
||||||
}>
|
| null,
|
||||||
> | null,
|
page: 1,
|
||||||
async load() {
|
totalPages: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.pasardesa["find-many"].get();
|
loading: false,
|
||||||
if (res.status === 200) {
|
search: "",
|
||||||
pasarDesa.findMany.data = res.data?.data ?? [];
|
load: async (page = 1, limit = 10, search = "", categoryId?: string) => {
|
||||||
|
pasarDesa.findMany.loading = true;
|
||||||
|
pasarDesa.findMany.page = page;
|
||||||
|
pasarDesa.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
if (categoryId) query.categoryId = categoryId;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.ekonomi.pasardesa["find-many"].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
pasarDesa.findMany.data = res.data.data ?? [];
|
||||||
|
pasarDesa.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
pasarDesa.findMany.data = [];
|
||||||
|
pasarDesa.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch keamanan lingkungan paginated:", err);
|
||||||
|
pasarDesa.findMany.data = [];
|
||||||
|
pasarDesa.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
pasarDesa.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -272,14 +298,41 @@ const kategoriProduk = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as Array<{
|
data: null as
|
||||||
id: string;
|
| Prisma.KategoriProdukGetPayload<{
|
||||||
nama: string;
|
omit: {
|
||||||
}> | null,
|
isActive: true;
|
||||||
async load() {
|
};
|
||||||
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get();
|
}>[]
|
||||||
if (res.status === 200) {
|
| null,
|
||||||
kategoriProduk.findMany.data = res.data?.data ?? [];
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
loading: false,
|
||||||
|
search2: "",
|
||||||
|
load: async (page = 1, limit = 10, search2 = "") => {
|
||||||
|
kategoriProduk.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
kategoriProduk.findMany.page = page;
|
||||||
|
kategoriProduk.findMany.search2 = search2;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search2) query.search2 = search2;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
kategoriProduk.findMany.data = res.data.data ?? [];
|
||||||
|
kategoriProduk.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
kategoriProduk.findMany.data = [];
|
||||||
|
kategoriProduk.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch kategori produk paginated:", err);
|
||||||
|
kategoriProduk.findMany.data = [];
|
||||||
|
kategoriProduk.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
kategoriProduk.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -7,22 +8,21 @@ import { z } from "zod";
|
|||||||
const templateForm = z.object({
|
const templateForm = z.object({
|
||||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||||
deskripsi: z.string().min(1, "Deskripsi 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({
|
statistik: z.object({
|
||||||
tahun: z.string().min(1, "Tahun minimal 1 karakter"),
|
tahun: z.string().min(1, "Tahun minimal 1 karakter"),
|
||||||
jumlah: z.string().min(1, "Jumlah minimal 1 karakter"),
|
jumlah: z.string().min(1, "Jumlah minimal 1 karakter"),
|
||||||
})
|
}),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultForm = {
|
const defaultForm = {
|
||||||
nama: "",
|
nama: "",
|
||||||
deskripsi: "",
|
deskripsi: "",
|
||||||
ikonUrl: "",
|
icon: "",
|
||||||
statistik: {
|
statistik: {
|
||||||
tahun: "",
|
tahun: "",
|
||||||
jumlah: ""
|
jumlah: "",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const programKemiskinanState = proxy({
|
const programKemiskinanState = proxy({
|
||||||
@@ -64,12 +64,35 @@ const programKemiskinanState = proxy({
|
|||||||
};
|
};
|
||||||
}>[],
|
}>[],
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.programkemiskinan[
|
totalPages: 1,
|
||||||
"find-many"
|
search: "",
|
||||||
].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
programKemiskinanState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
programKemiskinanState.findMany.data = res.data?.data ?? [];
|
programKemiskinanState.findMany.page = page;
|
||||||
|
programKemiskinanState.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.ekonomi.programkemiskinan[
|
||||||
|
"find-many"
|
||||||
|
].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
programKemiskinanState.findMany.data = res.data.data ?? [];
|
||||||
|
programKemiskinanState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
programKemiskinanState.findMany.data = [];
|
||||||
|
programKemiskinanState.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch program kemiskinan paginated:", err);
|
||||||
|
programKemiskinanState.findMany.data = [];
|
||||||
|
programKemiskinanState.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
programKemiskinanState.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -125,7 +148,7 @@ const programKemiskinanState = proxy({
|
|||||||
this.form = {
|
this.form = {
|
||||||
nama: data.nama,
|
nama: data.nama,
|
||||||
deskripsi: data.deskripsi,
|
deskripsi: data.deskripsi,
|
||||||
ikonUrl: data.ikonUrl || "",
|
icon: data.icon,
|
||||||
statistik: {
|
statistik: {
|
||||||
tahun: data.statistik.tahun,
|
tahun: data.statistik.tahun,
|
||||||
jumlah: data.statistik.jumlah,
|
jumlah: data.statistik.jumlah,
|
||||||
@@ -166,7 +189,7 @@ const programKemiskinanState = proxy({
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
nama: this.form.nama,
|
nama: this.form.nama,
|
||||||
deskripsi: this.form.deskripsi,
|
deskripsi: this.form.deskripsi,
|
||||||
ikonUrl: this.form.ikonUrl,
|
icon: this.form.icon,
|
||||||
statistik: {
|
statistik: {
|
||||||
tahun: this.form.statistik.tahun,
|
tahun: this.form.statistik.tahun,
|
||||||
jumlah: this.form.statistik.jumlah,
|
jumlah: this.form.statistik.jumlah,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -76,13 +77,37 @@ const grafikSektorUnggulan = proxy({
|
|||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
search: "",
|
||||||
const res = await ApiFetch.api.ekonomi.sektourunggulandesa[
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
"find-many"
|
grafikSektorUnggulan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
].get();
|
grafikSektorUnggulan.findMany.page = page;
|
||||||
if (res.status === 200) {
|
grafikSektorUnggulan.findMany.search = search;
|
||||||
grafikSektorUnggulan.findMany.data = res.data?.data ?? [];
|
|
||||||
|
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;
|
deskripsi: string | null;
|
||||||
hierarki: number;
|
hierarki: number;
|
||||||
}>,
|
}>,
|
||||||
async load() {
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
loading: false,
|
||||||
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
|
posisiOrganisasi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
posisiOrganisasi.findMany.page = page;
|
||||||
|
posisiOrganisasi.findMany.search = search;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
const query: any = { page, limit };
|
||||||
"posisi-organisasi"
|
if (search) query.search = search;
|
||||||
]["find-many"].get();
|
|
||||||
if (res.status === 200) {
|
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["posisi-organisasi"]["find-many"].get({ query });
|
||||||
// The API now returns the id field, so we can use it directly
|
|
||||||
this.data = res.data?.data ?? [];
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
posisiOrganisasi.findMany.data = res.data.data ?? [];
|
||||||
|
posisiOrganisasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
posisiOrganisasi.findMany.data = [];
|
||||||
|
posisiOrganisasi.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Find many error:", error);
|
console.error("Gagal fetch posisi organisasi paginated:", err);
|
||||||
this.data = [];
|
posisiOrganisasi.findMany.data = [];
|
||||||
|
posisiOrganisasi.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
posisiOrganisasi.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -75,16 +76,37 @@ const grafikBerdasarkanUsiaKerjaNganggur = proxy({
|
|||||||
omit: { isActive: true };
|
omit: { isActive: true };
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
loading: false,
|
page: 1,
|
||||||
async load() {
|
totalPages: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.grafikusiakerjayangmenganggur[
|
loading: false,
|
||||||
"find-many"
|
search: "",
|
||||||
].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
grafikBerdasarkanUsiaKerjaNganggur.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.data = res.data?.data ?? [];
|
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: {
|
findUnique: {
|
||||||
data: null as Prisma.GrafikMenganggurBerdasarkanUsiaGetPayload<{
|
data: null as Prisma.GrafikMenganggurBerdasarkanUsiaGetPayload<{
|
||||||
omit: { isActive: true };
|
omit: { isActive: true };
|
||||||
@@ -259,15 +281,36 @@ const grafikBerdasarkanPendidikan = proxy({
|
|||||||
omit: { isActive: true };
|
omit: { isActive: true };
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
loading: false,
|
page: 1,
|
||||||
async load() {
|
totalPages: 1,
|
||||||
const res = await ApiFetch.api.ekonomi.grafikmenganggurberdasarkanpendidikan[
|
loading: false,
|
||||||
"find-many"
|
search: "",
|
||||||
].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
grafikBerdasarkanPendidikan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
grafikBerdasarkanPendidikan.findMany.data = res.data?.data ?? [];
|
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: {
|
findUnique: {
|
||||||
data: null as Prisma.GrafikMenganggurBerdasarkanPendidikanGetPayload<{
|
data: null as Prisma.GrafikMenganggurBerdasarkanPendidikanGetPayload<{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -61,10 +62,37 @@ const ajukanIdeInovatifState = proxy({
|
|||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.inovasi.ajukanideinovatif["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
loading: false,
|
||||||
ajukanIdeInovatifState.findMany.data = res.data?.data ?? [];
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
|
ajukanIdeInovatifState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
ajukanIdeInovatifState.findMany.page = page;
|
||||||
|
ajukanIdeInovatifState.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res =
|
||||||
|
await ApiFetch.api.inovasi.ajukanideinovatif[
|
||||||
|
"find-many"
|
||||||
|
].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
ajukanIdeInovatifState.findMany.data = res.data.data ?? [];
|
||||||
|
ajukanIdeInovatifState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
ajukanIdeInovatifState.findMany.data = [];
|
||||||
|
ajukanIdeInovatifState.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch ajukan ide inovatif paginated:", err);
|
||||||
|
ajukanIdeInovatifState.findMany.data = [];
|
||||||
|
ajukanIdeInovatifState.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
ajukanIdeInovatifState.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -97,16 +125,21 @@ const ajukanIdeInovatifState = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
ajukanIdeInovatifState.delete.loading = true;
|
ajukanIdeInovatifState.delete.loading = true;
|
||||||
const response = await fetch(`/api/inovasi/ajukanideinovatif/del/${id}`, {
|
const response = await fetch(
|
||||||
method: "DELETE",
|
`/api/inovasi/ajukanideinovatif/del/${id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "DELETE",
|
||||||
},
|
headers: {
|
||||||
});
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
toast.success(result.message || "Ajukan Ide Inovatif berhasil dihapus");
|
toast.success(
|
||||||
|
result.message || "Ajukan Ide Inovatif berhasil dihapus"
|
||||||
|
);
|
||||||
await ajukanIdeInovatifState.findMany.load();
|
await ajukanIdeInovatifState.findMany.load();
|
||||||
} else {
|
} else {
|
||||||
toast.error(result?.message || "Gagal menghapus ajukan ide inovatif");
|
toast.error(result?.message || "Gagal menghapus ajukan ide inovatif");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -55,10 +56,34 @@ const desaDigitalState = proxy({
|
|||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.inovasi.desadigital["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
loading: false,
|
||||||
desaDigitalState.findMany.data = res.data?.data ?? [];
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -55,10 +56,34 @@ const infoTeknoState = proxy({
|
|||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.inovasi.infotekno["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
loading: false,
|
||||||
infoTeknoState.findMany.data = res.data?.data ?? [];
|
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";
|
import { z } from "zod";
|
||||||
|
|
||||||
const templateForm = z.object({
|
const templateForm = z.object({
|
||||||
name: z.string().min(1, "Nama minimal 1 karakter"),
|
name: z.string().min(1, "Nama kolaborasi inovasi harus diisi"),
|
||||||
tahun: z.number().min(4, "Tahun minimal 4 karakter"),
|
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, "Deskripsi singkat minimal 1 karakter"),
|
slug: z.string().min(1, "Slug harus dihasilkan otomatis"),
|
||||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
deskripsi: z.string().min(1, "Deskripsi harus diisi"),
|
||||||
kolaborator: z.string().min(1, "Kolaborator minimal 1 karakter"),
|
kolaborator: z.string().min(1, "Kolaborator harus diisi"),
|
||||||
imageId: z.string().min(1, "Image ID minimal 1 karakter"),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const defaultForm = {
|
const defaultForm = {
|
||||||
@@ -20,7 +19,6 @@ const defaultForm = {
|
|||||||
slug: "",
|
slug: "",
|
||||||
deskripsi: "",
|
deskripsi: "",
|
||||||
kolaborator: "",
|
kolaborator: "",
|
||||||
imageId: "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const kolaborasiInovasiState = proxy({
|
const kolaborasiInovasiState = proxy({
|
||||||
@@ -28,27 +26,37 @@ const kolaborasiInovasiState = proxy({
|
|||||||
form: { ...defaultForm },
|
form: { ...defaultForm },
|
||||||
loading: false,
|
loading: false,
|
||||||
async create() {
|
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 {
|
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;
|
kolaborasiInovasiState.create.loading = true;
|
||||||
|
|
||||||
const res = await ApiFetch.api.inovasi.kolaborasiinovasi["create"].post(
|
const res = await ApiFetch.api.inovasi.kolaborasiinovasi["create"].post(
|
||||||
kolaborasiInovasiState.create.form
|
kolaborasiInovasiState.create.form
|
||||||
);
|
);
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
kolaborasiInovasiState.findMany.load();
|
await kolaborasiInovasiState.findMany.load();
|
||||||
return toast.success("success create");
|
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) {
|
} 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 {
|
} finally {
|
||||||
kolaborasiInovasiState.create.loading = false;
|
kolaborasiInovasiState.create.loading = false;
|
||||||
}
|
}
|
||||||
@@ -60,13 +68,21 @@ const kolaborasiInovasiState = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => {
|
search: "",
|
||||||
// Change to arrow function
|
year: "",
|
||||||
kolaborasiInovasiState.findMany.loading = true; // Use the full path to access the property
|
load: async (page = 1, limit = 10, search = "", year?: string) => {
|
||||||
|
kolaborasiInovasiState.findMany.loading = true;
|
||||||
kolaborasiInovasiState.findMany.page = page;
|
kolaborasiInovasiState.findMany.page = page;
|
||||||
|
kolaborasiInovasiState.findMany.search = search;
|
||||||
|
kolaborasiInovasiState.findMany.year = year || "";
|
||||||
|
|
||||||
try {
|
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({
|
const res = await ApiFetch.api.inovasi.kolaborasiinovasi["find-many"].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
@@ -124,7 +140,6 @@ const kolaborasiInovasiState = proxy({
|
|||||||
slug: data.slug,
|
slug: data.slug,
|
||||||
deskripsi: data.deskripsi,
|
deskripsi: data.deskripsi,
|
||||||
kolaborator: data.kolaborator,
|
kolaborator: data.kolaborator,
|
||||||
imageId: data.imageId,
|
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
@@ -179,7 +194,7 @@ const kolaborasiInovasiState = proxy({
|
|||||||
},
|
},
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as Prisma.KolaborasiInovasiGetPayload<{
|
data: null as Prisma.KolaborasiInovasiGetPayload<{
|
||||||
include: { image: true };
|
omit: { isActive: true };
|
||||||
}> | null,
|
}> | null,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -54,19 +55,20 @@ const administrasiOnline = proxy({
|
|||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as Array<
|
data: null as Array<
|
||||||
Prisma.AdministrasiOnlineGetPayload<{
|
Prisma.AdministrasiOnlineGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
jenisLayanan: true;
|
jenisLayanan: true;
|
||||||
};
|
};
|
||||||
}>
|
}>
|
||||||
> | null,
|
> | null,
|
||||||
page: 1,
|
page: 1,
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
search: "",
|
||||||
async load(page = 1, limit = 10) {
|
async load(page = 1, limit = 10, search = "") {
|
||||||
administrasiOnline.findMany.loading = true;
|
administrasiOnline.findMany.loading = true;
|
||||||
administrasiOnline.findMany.page = page;
|
administrasiOnline.findMany.page = page;
|
||||||
|
administrasiOnline.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
const res =
|
const res =
|
||||||
await ApiFetch.api.inovasi.layananonlinedesa.administrasionline[
|
await ApiFetch.api.inovasi.layananonlinedesa.administrasionline[
|
||||||
@@ -75,6 +77,7 @@ const administrasiOnline = proxy({
|
|||||||
query: {
|
query: {
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
|
search,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -91,10 +94,10 @@ const administrasiOnline = proxy({
|
|||||||
},
|
},
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as Prisma.AdministrasiOnlineGetPayload<{
|
data: null as Prisma.AdministrasiOnlineGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
jenisLayanan: true;
|
jenisLayanan: true;
|
||||||
};
|
};
|
||||||
}> | null,
|
}> | null,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
@@ -199,13 +202,37 @@ const jenisLayanan = proxy({
|
|||||||
nama: string;
|
nama: string;
|
||||||
deskripsi: string;
|
deskripsi: string;
|
||||||
}> | null,
|
}> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res =
|
totalPages: 1,
|
||||||
await ApiFetch.api.inovasi.layananonlinedesa.administrasionline.jenislayanan[
|
loading: false,
|
||||||
"find-many"
|
search: "",
|
||||||
].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
jenisLayanan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
jenisLayanan.findMany.data = res.data?.data ?? [];
|
jenisLayanan.findMany.page = page;
|
||||||
|
jenisLayanan.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res =
|
||||||
|
await ApiFetch.api.inovasi.layananonlinedesa.administrasionline.jenislayanan[
|
||||||
|
"find-many"
|
||||||
|
].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
jenisLayanan.findMany.data = res.data.data ?? [];
|
||||||
|
jenisLayanan.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
jenisLayanan.findMany.data = [];
|
||||||
|
jenisLayanan.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch jenis layanan paginated:", err);
|
||||||
|
jenisLayanan.findMany.data = [];
|
||||||
|
jenisLayanan.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
jenisLayanan.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -403,7 +430,9 @@ const templatePengaduanMasyarakatForm = z.object({
|
|||||||
nik: z.string().min(1, "NIK minimal 1 karakter"),
|
nik: z.string().min(1, "NIK minimal 1 karakter"),
|
||||||
judulPengaduan: z.string().min(1, "Judul pengaduan minimal 1 karakter"),
|
judulPengaduan: z.string().min(1, "Judul pengaduan minimal 1 karakter"),
|
||||||
lokasiKejadian: z.string().min(1, "Lokasi kejadian minimal 1 karakter"),
|
lokasiKejadian: z.string().min(1, "Lokasi kejadian minimal 1 karakter"),
|
||||||
deskripsiPengaduan: z.string().min(1, "Deskripsi pengaduan minimal 1 karakter"),
|
deskripsiPengaduan: z
|
||||||
|
.string()
|
||||||
|
.min(1, "Deskripsi pengaduan minimal 1 karakter"),
|
||||||
jenisPengaduanId: z.string().min(1, "Jenis pengaduan minimal 1 karakter"),
|
jenisPengaduanId: z.string().min(1, "Jenis pengaduan minimal 1 karakter"),
|
||||||
imageId: z.string().min(1, "Image minimal 1 karakter"),
|
imageId: z.string().min(1, "Image minimal 1 karakter"),
|
||||||
});
|
});
|
||||||
@@ -455,37 +484,42 @@ const pengaduanMasyarakat = proxy({
|
|||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as Array<
|
data: null as Array<
|
||||||
Prisma.PengaduanMasyarakatGetPayload<{
|
Prisma.PengaduanMasyarakatGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
jenisPengaduan: true;
|
jenisPengaduan: true;
|
||||||
image: true;
|
image: true;
|
||||||
};
|
};
|
||||||
}>
|
}>
|
||||||
> | null,
|
> | null,
|
||||||
page: 1,
|
page: 1,
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
search: "",
|
||||||
async load(page = 1, limit = 10) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
pengaduanMasyarakat.findMany.loading = true;
|
pengaduanMasyarakat.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
pengaduanMasyarakat.findMany.page = page;
|
pengaduanMasyarakat.findMany.page = page;
|
||||||
|
pengaduanMasyarakat.findMany.search = search;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res =
|
const res =
|
||||||
await ApiFetch.api.inovasi.layananonlinedesa.pengaduanmasyarakat[
|
await ApiFetch.api.inovasi.layananonlinedesa.pengaduanmasyarakat[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get({
|
].get({ query });
|
||||||
query: {
|
|
||||||
page,
|
|
||||||
limit,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
pengaduanMasyarakat.findMany.data = res.data.data ?? [];
|
pengaduanMasyarakat.findMany.data = res.data.data ?? [];
|
||||||
pengaduanMasyarakat.findMany.totalPages = res.data.totalPages ?? 1;
|
pengaduanMasyarakat.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
pengaduanMasyarakat.findMany.data = [];
|
||||||
|
pengaduanMasyarakat.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Gagal fetch pengaduan masyarakat paginated:", err);
|
console.error("Gagal fetch pengaduan masyarakat paginated:", err);
|
||||||
|
pengaduanMasyarakat.findMany.data = [];
|
||||||
|
pengaduanMasyarakat.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
pengaduanMasyarakat.findMany.loading = false;
|
pengaduanMasyarakat.findMany.loading = false;
|
||||||
}
|
}
|
||||||
@@ -493,11 +527,11 @@ const pengaduanMasyarakat = proxy({
|
|||||||
},
|
},
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as Prisma.PengaduanMasyarakatGetPayload<{
|
data: null as Prisma.PengaduanMasyarakatGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
jenisPengaduan: true;
|
jenisPengaduan: true;
|
||||||
image: true;
|
image: true;
|
||||||
};
|
};
|
||||||
}> | null,
|
}> | null,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
@@ -507,7 +541,10 @@ const pengaduanMasyarakat = proxy({
|
|||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
pengaduanMasyarakat.findUnique.data = data.data ?? null;
|
pengaduanMasyarakat.findUnique.data = data.data ?? null;
|
||||||
} else {
|
} else {
|
||||||
console.error("Failed to fetch pengaduan masyarakat:", res.statusText);
|
console.error(
|
||||||
|
"Failed to fetch pengaduan masyarakat:",
|
||||||
|
res.statusText
|
||||||
|
);
|
||||||
pengaduanMasyarakat.findUnique.data = null;
|
pengaduanMasyarakat.findUnique.data = null;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -542,7 +579,9 @@ const pengaduanMasyarakat = proxy({
|
|||||||
);
|
);
|
||||||
await pengaduanMasyarakat.findMany.load(); // refresh list
|
await pengaduanMasyarakat.findMany.load(); // refresh list
|
||||||
} else {
|
} else {
|
||||||
toast.error(result?.message || "Gagal menghapus pengaduan masyarakat");
|
toast.error(
|
||||||
|
result?.message || "Gagal menghapus pengaduan masyarakat"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Gagal delete:", error);
|
console.error("Gagal delete:", error);
|
||||||
@@ -567,7 +606,9 @@ const jenisPengaduan = proxy({
|
|||||||
form: { ...defaultJenisPengaduanForm },
|
form: { ...defaultJenisPengaduanForm },
|
||||||
loading: false,
|
loading: false,
|
||||||
async create() {
|
async create() {
|
||||||
const cek = templateJenisPengaduanForm.safeParse(jenisPengaduan.create.form);
|
const cek = templateJenisPengaduanForm.safeParse(
|
||||||
|
jenisPengaduan.create.form
|
||||||
|
);
|
||||||
if (!cek.success) {
|
if (!cek.success) {
|
||||||
const err = `[${cek.error.issues
|
const err = `[${cek.error.issues
|
||||||
.map((v) => `${v.path.join(".")}`)
|
.map((v) => `${v.path.join(".")}`)
|
||||||
@@ -598,13 +639,37 @@ const jenisPengaduan = proxy({
|
|||||||
id: string;
|
id: string;
|
||||||
nama: string;
|
nama: string;
|
||||||
}> | null,
|
}> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res =
|
totalPages: 1,
|
||||||
await ApiFetch.api.inovasi.layananonlinedesa.pengaduanmasyarakat.jenispengaduan[
|
loading: false,
|
||||||
"find-many"
|
search: "",
|
||||||
].get();
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
if (res.status === 200) {
|
jenisPengaduan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
jenisPengaduan.findMany.data = res.data?.data ?? [];
|
jenisPengaduan.findMany.page = page;
|
||||||
|
jenisPengaduan.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res =
|
||||||
|
await ApiFetch.api.inovasi.layananonlinedesa.pengaduanmasyarakat.jenispengaduan[
|
||||||
|
"find-many"
|
||||||
|
].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
jenisPengaduan.findMany.data = res.data.data ?? [];
|
||||||
|
jenisPengaduan.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
jenisPengaduan.findMany.data = [];
|
||||||
|
jenisPengaduan.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch jenis pengaduan paginated:", err);
|
||||||
|
jenisPengaduan.findMany.data = [];
|
||||||
|
jenisPengaduan.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
jenisPengaduan.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -693,7 +758,7 @@ const jenisPengaduan = proxy({
|
|||||||
const data = result.data;
|
const data = result.data;
|
||||||
this.id = data.id;
|
this.id = data.id;
|
||||||
this.form = {
|
this.form = {
|
||||||
nama: data.nama
|
nama: data.nama,
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
@@ -709,7 +774,9 @@ const jenisPengaduan = proxy({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async update() {
|
async update() {
|
||||||
const cek = templateJenisPengaduanForm.safeParse(jenisPengaduan.edit.form);
|
const cek = templateJenisPengaduanForm.safeParse(
|
||||||
|
jenisPengaduan.edit.form
|
||||||
|
);
|
||||||
if (!cek.success) {
|
if (!cek.success) {
|
||||||
const err = `[${cek.error.issues
|
const err = `[${cek.error.issues
|
||||||
.map((v) => `${v.path.join(".")}`)
|
.map((v) => `${v.path.join(".")}`)
|
||||||
@@ -759,7 +826,9 @@ const jenisPengaduan = proxy({
|
|||||||
await jenisPengaduan.findMany.load(); // refresh list
|
await jenisPengaduan.findMany.load(); // refresh list
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.message || "Gagal mengupdate jenis pengaduan");
|
throw new Error(
|
||||||
|
result.message || "Gagal mengupdate jenis pengaduan"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If JSON parsing fails, try to get the response text for better error messages
|
// If JSON parsing fails, try to get the response text for better error messages
|
||||||
@@ -792,7 +861,6 @@ const jenisPengaduan = proxy({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const layananonlineDesa = proxy({
|
const layananonlineDesa = proxy({
|
||||||
administrasiOnline,
|
administrasiOnline,
|
||||||
jenisLayanan,
|
jenisLayanan,
|
||||||
|
|||||||
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;
|
||||||
@@ -54,34 +54,32 @@ const programKreatifState = proxy({
|
|||||||
data: null as any[] | null,
|
data: null as any[] | null,
|
||||||
page: 1,
|
page: 1,
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => {
|
search: "",
|
||||||
// Change to arrow function
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
programKreatifState.findMany.loading = true; // Use the full path to access the property
|
programKreatifState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
programKreatifState.findMany.page = page;
|
programKreatifState.findMany.page = page;
|
||||||
|
programKreatifState.findMany.search = search;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await ApiFetch.api.inovasi.programkreatif["find-many"].get({
|
const query: any = { page, limit };
|
||||||
query: { page, limit },
|
if (search) query.search = search;
|
||||||
});
|
|
||||||
|
const res = await ApiFetch.api.inovasi.programkreatif[
|
||||||
|
"find-many"
|
||||||
|
].get({ query });
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
programKreatifState.findMany.data = res.data.data || [];
|
programKreatifState.findMany.data = res.data.data ?? [];
|
||||||
programKreatifState.findMany.total = res.data.total || 0;
|
programKreatifState.findMany.totalPages =
|
||||||
programKreatifState.findMany.totalPages = res.data.totalPages || 1;
|
res.data.totalPages ?? 1;
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
|
||||||
"Failed to load grafik berdasarkan jenis kelamin:",
|
|
||||||
res.data?.message
|
|
||||||
);
|
|
||||||
programKreatifState.findMany.data = [];
|
programKreatifState.findMany.data = [];
|
||||||
programKreatifState.findMany.total = 0;
|
|
||||||
programKreatifState.findMany.totalPages = 1;
|
programKreatifState.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Error loading grafik berdasarkan jenis kelamin:", error);
|
console.error("Gagal fetch program kreatif paginated:", err);
|
||||||
programKreatifState.findMany.data = [];
|
programKreatifState.findMany.data = [];
|
||||||
programKreatifState.findMany.total = 0;
|
|
||||||
programKreatifState.findMany.totalPages = 1;
|
programKreatifState.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
programKreatifState.findMany.loading = false;
|
programKreatifState.findMany.loading = false;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -6,26 +7,14 @@ import { z } from "zod";
|
|||||||
|
|
||||||
const templateForm = z.object({
|
const templateForm = z.object({
|
||||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||||
imageId: z.string().nonempty(),
|
icon: z.string().nonempty(),
|
||||||
kontakItems: z.array(
|
kategoriId: z.array(z.string()).min(1, "Minimal pilih satu kategori"),
|
||||||
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 defaultForm = {
|
const defaultForm = {
|
||||||
nama: "",
|
nama: "",
|
||||||
imageId: "",
|
icon: "",
|
||||||
kontakItems: [
|
kategoriId: [] as string[],
|
||||||
{
|
|
||||||
nama: "",
|
|
||||||
nomorTelepon: "",
|
|
||||||
imageId: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const kontakDaruratKeamananState = proxy({
|
const kontakDaruratKeamananState = proxy({
|
||||||
@@ -61,20 +50,49 @@ const kontakDaruratKeamananState = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as Array<
|
||||||
| Prisma.KontakDaruratKeamananGetPayload<{
|
Prisma.KontakDaruratKeamananGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
kontakItems: true;
|
kategori: true;
|
||||||
image: true;
|
kontakItems: {
|
||||||
|
include: {
|
||||||
|
kontakItem: true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}>[]
|
};
|
||||||
| null,
|
}>
|
||||||
async load() {
|
> | null,
|
||||||
const res = await ApiFetch.api.keamanan.kontakdaruratkeamanan[
|
page: 1,
|
||||||
"find-many"
|
totalPages: 1,
|
||||||
].get();
|
loading: false,
|
||||||
if (res.status === 200) {
|
search: "",
|
||||||
kontakDaruratKeamananState.findMany.data = res.data?.data ?? [];
|
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 +101,10 @@ const kontakDaruratKeamananState = proxy({
|
|||||||
include: {
|
include: {
|
||||||
kontakItems: {
|
kontakItems: {
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
kontakItem: true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
image: true;
|
kategori: true;
|
||||||
};
|
};
|
||||||
}> | null,
|
}> | null,
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -168,14 +186,9 @@ const kontakDaruratKeamananState = proxy({
|
|||||||
this.id = data.id;
|
this.id = data.id;
|
||||||
this.form = {
|
this.form = {
|
||||||
nama: data.nama,
|
nama: data.nama,
|
||||||
imageId: data.imageId,
|
icon: data.icon || "",
|
||||||
kontakItems: [
|
kategoriId:
|
||||||
{
|
data.kontakItems?.map((item: any) => item.kontakItemId) || [],
|
||||||
nama: data.kontakItems.nama,
|
|
||||||
nomorTelepon: data.kontakItems.nomorTelepon,
|
|
||||||
imageId: data.kontakItems.imageId,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
@@ -212,14 +225,8 @@ const kontakDaruratKeamananState = proxy({
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
nama: this.form.nama,
|
nama: this.form.nama,
|
||||||
imageId: this.form.imageId,
|
icon: this.form.icon,
|
||||||
kontakItems: [
|
kategoriId: this.form.kategoriId,
|
||||||
{
|
|
||||||
nama: this.form.kontakItems[0].nama,
|
|
||||||
nomorTelepon: this.form.kontakItems[0].nomorTelepon,
|
|
||||||
imageId: this.form.kontakItems[0].imageId,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -256,4 +263,242 @@ 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"),
|
||||||
|
icon: z.string().nonempty(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultFormItem = {
|
||||||
|
nama: "",
|
||||||
|
nomorTelepon: "",
|
||||||
|
icon: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
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<{
|
||||||
|
omit: {
|
||||||
|
isActive: 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<{
|
||||||
|
omit: {
|
||||||
|
isActive: 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,
|
||||||
|
icon: data.icon,
|
||||||
|
};
|
||||||
|
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,
|
||||||
|
icon: this.form.icon,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -10,12 +11,24 @@ const templateForm = z.object({
|
|||||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||||
lokasi: z.string().min(3, "Lokasi minimal 3 karakter"),
|
lokasi: z.string().min(3, "Lokasi minimal 3 karakter"),
|
||||||
tanggalWaktu: z.string().min(3, "Tanggal Waktu minimal 3 karakter"),
|
tanggalWaktu: z.string().min(3, "Tanggal Waktu minimal 3 karakter"),
|
||||||
status: z.enum(["Selesai", "Proses", "Gagal"]),
|
|
||||||
penanganan: z.string(),
|
|
||||||
kronologi: z.string().optional(),
|
kronologi: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
|
judul: string;
|
||||||
|
lokasi: string;
|
||||||
|
tanggalWaktu: string;
|
||||||
|
kronologi: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultForm: FormData = {
|
||||||
|
judul: "",
|
||||||
|
lokasi: "",
|
||||||
|
tanggalWaktu: new Date().toISOString(),
|
||||||
|
kronologi: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
interface FormEditData {
|
||||||
judul: string;
|
judul: string;
|
||||||
lokasi: string;
|
lokasi: string;
|
||||||
tanggalWaktu: string;
|
tanggalWaktu: string;
|
||||||
@@ -24,15 +37,16 @@ interface FormData {
|
|||||||
kronologi: string;
|
kronologi: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultForm: FormData = {
|
const editForm: FormEditData = {
|
||||||
judul: "",
|
judul: "",
|
||||||
lokasi: "",
|
lokasi: "",
|
||||||
tanggalWaktu: new Date().toISOString(),
|
tanggalWaktu: new Date().toISOString(),
|
||||||
|
kronologi: "",
|
||||||
status: "Proses",
|
status: "Proses",
|
||||||
penanganan: "",
|
penanganan: "",
|
||||||
kronologi: "",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const laporanPublikState = proxy({
|
const laporanPublikState = proxy({
|
||||||
create: {
|
create: {
|
||||||
form: { ...defaultForm },
|
form: { ...defaultForm },
|
||||||
@@ -97,13 +111,37 @@ const laporanPublikState = proxy({
|
|||||||
include: { penanganan: true };
|
include: { penanganan: true };
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.keamanan.laporanpublik["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
loading: false,
|
||||||
laporanPublikState.findMany.data = res.data?.data ?? [];
|
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: {
|
findUnique: {
|
||||||
data: null as Prisma.LaporanPublikGetPayload<{
|
data: null as Prisma.LaporanPublikGetPayload<{
|
||||||
include: { penanganan: true };
|
include: { penanganan: true };
|
||||||
@@ -160,7 +198,7 @@ const laporanPublikState = proxy({
|
|||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
id: "",
|
id: "",
|
||||||
form: { ...defaultForm },
|
form: { ...editForm },
|
||||||
loading: false,
|
loading: false,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
@@ -266,7 +304,7 @@ const laporanPublikState = proxy({
|
|||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
laporanPublikState.edit.id = "";
|
laporanPublikState.edit.id = "";
|
||||||
laporanPublikState.edit.form = { ...defaultForm };
|
laporanPublikState.edit.form = { ...editForm };
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -5,45 +6,17 @@ import { proxy } from "valtio";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
const templateForm = z.object({
|
const templateForm = z.object({
|
||||||
pencegahanKriminalitas: z.object({
|
judul: z.string().min(1, "Judul minimal 1 karakter"),
|
||||||
programKeamanan: z.object({
|
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
deskripsiSingkat: z.string().min(1, "Deskripsi singkat minimal 1 karakter"),
|
||||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
linkVideo: z.string().min(1, "Link video minimal 1 karakter"),
|
||||||
slug: z.string().min(1, "Slug minimal 1 karakter"),
|
|
||||||
}),
|
|
||||||
tipsKeamanan: z.object({
|
|
||||||
judul: z.string().min(1, "Judul minimal 1 karakter"),
|
|
||||||
konten: z.string().min(1, "Konten minimal 1 karakter"),
|
|
||||||
slug: z.string().min(1, "Slug minimal 1 karakter"),
|
|
||||||
}),
|
|
||||||
videoKeamanan: z.object({
|
|
||||||
judul: z.string().min(1, "Judul minimal 1 karakter"),
|
|
||||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
|
||||||
videoUrl: z.string().min(1, "Video URL minimal 1 karakter"),
|
|
||||||
slug: z.string().min(1, "Slug minimal 1 karakter"),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultForm = {
|
const defaultForm = {
|
||||||
pencegahanKriminalitas: {
|
judul: "",
|
||||||
programKeamanan: {
|
deskripsi: "",
|
||||||
nama: "",
|
deskripsiSingkat: "",
|
||||||
deskripsi: "",
|
linkVideo: "",
|
||||||
slug: "",
|
|
||||||
},
|
|
||||||
tipsKeamanan: {
|
|
||||||
judul: "",
|
|
||||||
konten: "",
|
|
||||||
slug: "",
|
|
||||||
},
|
|
||||||
videoKeamanan: {
|
|
||||||
judul: "",
|
|
||||||
deskripsi: "",
|
|
||||||
videoUrl: "",
|
|
||||||
slug: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const pencegahanKriminalitasState = proxy({
|
const pencegahanKriminalitasState = proxy({
|
||||||
@@ -64,7 +37,7 @@ const pencegahanKriminalitasState = proxy({
|
|||||||
pencegahanKriminalitasState.create.loading = true;
|
pencegahanKriminalitasState.create.loading = true;
|
||||||
const res = await ApiFetch.api.keamanan.pencegahankriminalitas[
|
const res = await ApiFetch.api.keamanan.pencegahankriminalitas[
|
||||||
"create"
|
"create"
|
||||||
].post(pencegahanKriminalitasState.create.form.pencegahanKriminalitas);
|
].post(pencegahanKriminalitasState.create.form);
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
pencegahanKriminalitasState.findMany.load();
|
pencegahanKriminalitasState.findMany.load();
|
||||||
return toast.success("success create");
|
return toast.success("success create");
|
||||||
@@ -81,29 +54,46 @@ const pencegahanKriminalitasState = proxy({
|
|||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.PencegahanKriminalitasGetPayload<{
|
| Prisma.PencegahanKriminalitasGetPayload<{
|
||||||
include: {
|
omit: { isActive: true };
|
||||||
programKeamanan: true;
|
|
||||||
tipsKeamanan: true;
|
|
||||||
videoKeamanan: true;
|
|
||||||
};
|
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.keamanan.pencegahankriminalitas[
|
totalPages: 1,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
pencegahanKriminalitasState.findMany.data = res.data?.data ?? [];
|
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;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as Prisma.PencegahanKriminalitasGetPayload<{
|
data: null as Prisma.PencegahanKriminalitasGetPayload<{
|
||||||
include: {
|
omit: { isActive: true };
|
||||||
programKeamanan: true;
|
|
||||||
tipsKeamanan: true;
|
|
||||||
videoKeamanan: true;
|
|
||||||
};
|
|
||||||
}> | null,
|
}> | null,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
@@ -122,6 +112,30 @@ const pencegahanKriminalitasState = proxy({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
findFirst: {
|
||||||
|
data: null as Prisma.PencegahanKriminalitasGetPayload<{
|
||||||
|
omit: { isActive: true };
|
||||||
|
}> | null,
|
||||||
|
loading: false,
|
||||||
|
// findFirst.load()
|
||||||
|
async load() {
|
||||||
|
this.loading = true;
|
||||||
|
try {
|
||||||
|
const res = await ApiFetch.api.keamanan.pencegahankriminalitas["find-first"].get();
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
this.data = res.data.data || null;
|
||||||
|
} else {
|
||||||
|
this.data = null;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch pencegahan kriminalitas terbaru:", err);
|
||||||
|
this.data = null;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
delete: {
|
delete: {
|
||||||
loading: false,
|
loading: false,
|
||||||
async byId(id: string) {
|
async byId(id: string) {
|
||||||
@@ -187,24 +201,10 @@ const pencegahanKriminalitasState = proxy({
|
|||||||
const data = result.data;
|
const data = result.data;
|
||||||
pencegahanKriminalitasState.update.id = data.id;
|
pencegahanKriminalitasState.update.id = data.id;
|
||||||
pencegahanKriminalitasState.update.form = {
|
pencegahanKriminalitasState.update.form = {
|
||||||
pencegahanKriminalitas: {
|
judul: data.judul,
|
||||||
programKeamanan: {
|
deskripsi: data.deskripsi,
|
||||||
nama: data.programKeamanan.nama,
|
deskripsiSingkat: data.deskripsiSingkat,
|
||||||
deskripsi: data.programKeamanan.deskripsi,
|
linkVideo: data.linkVideo,
|
||||||
slug: data.programKeamanan.slug,
|
|
||||||
},
|
|
||||||
tipsKeamanan: {
|
|
||||||
judul: data.tipsKeamanan.judul,
|
|
||||||
konten: data.tipsKeamanan.konten,
|
|
||||||
slug: data.tipsKeamanan.slug,
|
|
||||||
},
|
|
||||||
videoKeamanan: {
|
|
||||||
judul: data.videoKeamanan.judul,
|
|
||||||
deskripsi: data.videoKeamanan.deskripsi,
|
|
||||||
videoUrl: data.videoKeamanan.videoUrl,
|
|
||||||
slug: data.videoKeamanan.slug,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
@@ -240,40 +240,11 @@ const pencegahanKriminalitasState = proxy({
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
pencegahanKriminalitas: {
|
judul: pencegahanKriminalitasState.update.form.judul,
|
||||||
programKeamanan: {
|
deskripsi: pencegahanKriminalitasState.update.form.deskripsi,
|
||||||
nama: pencegahanKriminalitasState.update.form
|
deskripsiSingkat:
|
||||||
.pencegahanKriminalitas.programKeamanan.nama,
|
pencegahanKriminalitasState.update.form.deskripsiSingkat,
|
||||||
deskripsi:
|
linkVideo: pencegahanKriminalitasState.update.form.linkVideo,
|
||||||
pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.programKeamanan.deskripsi,
|
|
||||||
slug: pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.programKeamanan.slug,
|
|
||||||
},
|
|
||||||
tipsKeamanan: {
|
|
||||||
judul:
|
|
||||||
pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.tipsKeamanan.judul,
|
|
||||||
konten:
|
|
||||||
pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.tipsKeamanan.konten,
|
|
||||||
slug: pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.tipsKeamanan.slug,
|
|
||||||
},
|
|
||||||
videoKeamanan: {
|
|
||||||
judul:
|
|
||||||
pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.videoKeamanan.judul,
|
|
||||||
deskripsi:
|
|
||||||
pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.videoKeamanan.deskripsi,
|
|
||||||
videoUrl:
|
|
||||||
pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.videoKeamanan.videoUrl,
|
|
||||||
slug: pencegahanKriminalitasState.update.form
|
|
||||||
.pencegahanKriminalitas.videoKeamanan.slug,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -311,4 +282,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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -53,15 +54,39 @@ const tipsKeamananState = proxy({
|
|||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.MenuTipsKeamananGetPayload<{
|
| Prisma.MenuTipsKeamananGetPayload<{
|
||||||
include: { image: true };
|
include: {
|
||||||
|
image: true;
|
||||||
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.keamanan.menutipskeamanan[
|
totalPages: 1,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
tipsKeamananState.findMany.data = res.data?.data ?? [];
|
tipsKeamananState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
tipsKeamananState.findMany.page = page;
|
||||||
|
tipsKeamananState.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.keamanan.menutipskeamanan["find-many"].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
tipsKeamananState.findMany.data = res.data.data ?? [];
|
||||||
|
tipsKeamananState.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
tipsKeamananState.findMany.data = [];
|
||||||
|
tipsKeamananState.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch menu tips keamanan paginated:", err);
|
||||||
|
tipsKeamananState.findMany.data = [];
|
||||||
|
tipsKeamananState.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
tipsKeamananState.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,11 +31,13 @@ const templateForm = z.object({
|
|||||||
doctorSign: z.object({
|
doctorSign: z.object({
|
||||||
content: z.string().min(1, "Content harus diisi"),
|
content: z.string().min(1, "Content harus diisi"),
|
||||||
}),
|
}),
|
||||||
|
imageId: z.string().min(1, "Image ID harus diisi"),
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultForm = {
|
const defaultForm = {
|
||||||
title: "",
|
title: "",
|
||||||
content: "",
|
content: "",
|
||||||
|
imageId: "",
|
||||||
introduction: {
|
introduction: {
|
||||||
content: "",
|
content: "",
|
||||||
},
|
},
|
||||||
@@ -59,6 +61,7 @@ const defaultForm = {
|
|||||||
doctorSign: {
|
doctorSign: {
|
||||||
content: "",
|
content: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const artikelKesehatanState = proxy({
|
const artikelKesehatanState = proxy({
|
||||||
@@ -112,30 +115,42 @@ const artikelKesehatanState = proxy({
|
|||||||
firstaid: true;
|
firstaid: true;
|
||||||
mythvsfact: true;
|
mythvsfact: true;
|
||||||
doctorsign: true;
|
doctorsign: true;
|
||||||
|
image: true;
|
||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
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 {
|
try {
|
||||||
this.loading = true;
|
const query: any = { page, limit };
|
||||||
const res = await (ApiFetch.api.kesehatan as any)["artikel-kesehatan"][
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.kesehatan["artikel-kesehatan"][
|
||||||
"find-many"
|
"find-many"
|
||||||
].get();
|
].get({ query });
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
this.data = res.data?.data ?? [];
|
artikelKesehatanState.findMany.data =
|
||||||
|
res.data.data ?? [];
|
||||||
|
artikelKesehatanState.findMany.totalPages =
|
||||||
|
res.data.totalPages ?? 1;
|
||||||
} else {
|
} else {
|
||||||
toast.error("Gagal memuat data artikel kesehatan");
|
artikelKesehatanState.findMany.data = [];
|
||||||
|
artikelKesehatanState.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toast.error("Terjadi error saat load data");
|
console.error("Gagal fetch artikel kesehatan paginated:", err);
|
||||||
console.error("LOAD ERROR:", err);
|
artikelKesehatanState.findMany.data = [];
|
||||||
throw err;
|
artikelKesehatanState.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
artikelKesehatanState.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -148,6 +163,7 @@ const artikelKesehatanState = proxy({
|
|||||||
firstaid: true;
|
firstaid: true;
|
||||||
mythvsfact: true;
|
mythvsfact: true;
|
||||||
doctorsign: true;
|
doctorsign: true;
|
||||||
|
image: true;
|
||||||
};
|
};
|
||||||
}> | null,
|
}> | null,
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -202,6 +218,7 @@ const artikelKesehatanState = proxy({
|
|||||||
doctorSign: {
|
doctorSign: {
|
||||||
content: data.doctorsign.content,
|
content: data.doctorsign.content,
|
||||||
},
|
},
|
||||||
|
imageId: data.imageId,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async submit() {
|
async submit() {
|
||||||
@@ -242,6 +259,7 @@ const artikelKesehatanState = proxy({
|
|||||||
doctorSign: {
|
doctorSign: {
|
||||||
content: artikelKesehatanState.edit.form.doctorSign.content,
|
content: artikelKesehatanState.edit.form.doctorSign.content,
|
||||||
},
|
},
|
||||||
|
imageId: artikelKesehatanState.edit.form.imageId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
@@ -280,12 +298,9 @@ const artikelKesehatanState = proxy({
|
|||||||
async byId(id: string) {
|
async byId(id: string) {
|
||||||
try {
|
try {
|
||||||
artikelKesehatanState.delete.loading = true;
|
artikelKesehatanState.delete.loading = true;
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/kesehatan/artikel-kesehatan/del/${id}`, {
|
||||||
`/api/kesehatan/artikel-kesehatan/del/${id}`,
|
method: "DELETE",
|
||||||
{
|
});
|
||||||
method: "DELETE",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await res.json();
|
const result = await res.json();
|
||||||
if (res.ok && result.success) {
|
if (res.ok && result.success) {
|
||||||
|
|||||||
@@ -116,27 +116,38 @@ const fasilitasKesehatan = proxy({
|
|||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
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 {
|
try {
|
||||||
this.loading = true;
|
const query: any = { page, limit };
|
||||||
const res = await (ApiFetch.api.kesehatan as any)[
|
if (search) query.search = search;
|
||||||
"fasilitas-kesehatan"
|
|
||||||
]["find-many"].get();
|
|
||||||
|
|
||||||
if (res.status === 200) {
|
const res = await ApiFetch.api.kesehatan["fasilitas-kesehatan"][
|
||||||
this.data = res.data?.data ?? [];
|
"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 {
|
} else {
|
||||||
toast.error("Gagal memuat data fasilitas kesehatan");
|
fasilitasKesehatanState.fasilitasKesehatan.findMany.data = [];
|
||||||
|
fasilitasKesehatanState.fasilitasKesehatan.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toast.error("Terjadi error saat load data");
|
console.error("Gagal fetch fasilitas kesehatan paginated:", err);
|
||||||
console.error("LOAD ERROR:", err);
|
fasilitasKesehatanState.fasilitasKesehatan.findMany.data = [];
|
||||||
throw err;
|
fasilitasKesehatanState.fasilitasKesehatan.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
fasilitasKesehatanState.fasilitasKesehatan.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -558,7 +569,7 @@ const dokter = proxy({
|
|||||||
|
|
||||||
const fasilitasKesehatanState = proxy({
|
const fasilitasKesehatanState = proxy({
|
||||||
fasilitasKesehatan,
|
fasilitasKesehatan,
|
||||||
dokter
|
dokter,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default fasilitasKesehatanState;
|
export default fasilitasKesehatanState;
|
||||||
|
|||||||
@@ -120,27 +120,36 @@ const jadwalkegiatanState = proxy({
|
|||||||
};
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
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 {
|
try {
|
||||||
this.loading = true;
|
const query: any = { page, limit };
|
||||||
const res = await (ApiFetch.api.kesehatan as any)[
|
if (search) query.search = search;
|
||||||
"jadwal-kegiatan"
|
|
||||||
]["find-many"].get();
|
|
||||||
|
|
||||||
if (res.status === 200) {
|
const res = await ApiFetch.api.kesehatan["jadwal-kegiatan"][
|
||||||
this.data = res.data?.data ?? [];
|
"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 {
|
} else {
|
||||||
toast.error("Gagal memuat data jadwal kegiatan");
|
jadwalkegiatanState.findMany.data = [];
|
||||||
|
jadwalkegiatanState.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toast.error("Terjadi error saat load data");
|
console.error("Gagal fetch jadwal kegiatan paginated:", err);
|
||||||
console.error("LOAD ERROR:", err);
|
jadwalkegiatanState.findMany.data = [];
|
||||||
throw err;
|
jadwalkegiatanState.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
jadwalkegiatanState.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -227,29 +236,42 @@ const jadwalkegiatanState = proxy({
|
|||||||
content: jadwalkegiatanState.edit.form.content,
|
content: jadwalkegiatanState.edit.form.content,
|
||||||
informasiJadwalKegiatan: {
|
informasiJadwalKegiatan: {
|
||||||
name: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.name,
|
name: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.name,
|
||||||
tanggal: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.tanggal,
|
tanggal:
|
||||||
|
jadwalkegiatanState.edit.form.informasiJadwalKegiatan.tanggal,
|
||||||
waktu: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.waktu,
|
waktu: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.waktu,
|
||||||
lokasi: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.lokasi,
|
lokasi:
|
||||||
|
jadwalkegiatanState.edit.form.informasiJadwalKegiatan.lokasi,
|
||||||
},
|
},
|
||||||
layananJadwalKegiatan: {
|
layananJadwalKegiatan: {
|
||||||
content: jadwalkegiatanState.edit.form.layananJadwalKegiatan.content,
|
content:
|
||||||
|
jadwalkegiatanState.edit.form.layananJadwalKegiatan.content,
|
||||||
},
|
},
|
||||||
deskripsiJadwalKegiatan: {
|
deskripsiJadwalKegiatan: {
|
||||||
deskripsi: jadwalkegiatanState.edit.form.deskripsiJadwalKegiatan.deskripsi,
|
deskripsi:
|
||||||
|
jadwalkegiatanState.edit.form.deskripsiJadwalKegiatan.deskripsi,
|
||||||
},
|
},
|
||||||
syaratKetentuanJadwalKegiatan: {
|
syaratKetentuanJadwalKegiatan: {
|
||||||
content: jadwalkegiatanState.edit.form.syaratKetentuanJadwalKegiatan.content,
|
content:
|
||||||
|
jadwalkegiatanState.edit.form.syaratKetentuanJadwalKegiatan
|
||||||
|
.content,
|
||||||
},
|
},
|
||||||
dokumenJadwalKegiatan: {
|
dokumenJadwalKegiatan: {
|
||||||
content: jadwalkegiatanState.edit.form.dokumenJadwalKegiatan.content,
|
content:
|
||||||
|
jadwalkegiatanState.edit.form.dokumenJadwalKegiatan.content,
|
||||||
},
|
},
|
||||||
pendaftaranJadwalKegiatan: {
|
pendaftaranJadwalKegiatan: {
|
||||||
name: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.name,
|
name: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.name,
|
||||||
tanggal: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.tanggal,
|
tanggal:
|
||||||
namaOrangtua: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.namaOrangtua,
|
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.tanggal,
|
||||||
nomor: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.nomor,
|
namaOrangtua:
|
||||||
alamat: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.alamat,
|
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan
|
||||||
catatan: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.catatan,
|
.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: {
|
delete: {
|
||||||
loading: false,
|
loading: false,
|
||||||
async byId(id: string){
|
async byId(id: string) {
|
||||||
try {
|
try {
|
||||||
jadwalkegiatanState.delete.loading = true;
|
jadwalkegiatanState.delete.loading = true;
|
||||||
const res = await fetch(`/api/kesehatan/jadwal-kegiatan/del/${id}`, {
|
const res = await fetch(`/api/kesehatan/jadwal-kegiatan/del/${id}`, {
|
||||||
@@ -305,7 +327,7 @@ const jadwalkegiatanState = proxy({
|
|||||||
} finally {
|
} finally {
|
||||||
jadwalkegiatanState.delete.loading = false;
|
jadwalkegiatanState.delete.loading = false;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,290 @@
|
|||||||
|
/* 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 templateForm = z.object({
|
||||||
|
name: z.string().min(1, "Name minimal 1 karakter"),
|
||||||
|
tanggal: z.string().min(1, "Tanggal minimal 1 karakter"),
|
||||||
|
namaOrangtua: z.string().min(1, "Nama Orangtua minimal 1 karakter"),
|
||||||
|
nomor: z.string().min(1, "Nomor minimal 1 karakter"),
|
||||||
|
alamat: z.string().min(1, "Alamat minimal 1 karakter"),
|
||||||
|
catatan: z.string().min(1, "Catatan minimal 1 karakter"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultForm = {
|
||||||
|
name: "",
|
||||||
|
tanggal: "",
|
||||||
|
namaOrangtua: "",
|
||||||
|
nomor: "",
|
||||||
|
alamat: "",
|
||||||
|
catatan: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
const pendaftaranJadwalKegiatanState = proxy({
|
||||||
|
create: {
|
||||||
|
form: { ...defaultForm },
|
||||||
|
loading: false,
|
||||||
|
async submit() {
|
||||||
|
const cek = templateForm.safeParse(this.form);
|
||||||
|
if (!cek.success) {
|
||||||
|
const errMsg = cek.error.issues
|
||||||
|
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||||
|
.join("\n");
|
||||||
|
toast.error(errMsg);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
const payload = { ...this.form };
|
||||||
|
|
||||||
|
const res = await (ApiFetch.api.kesehatan as any)[
|
||||||
|
"pendaftaran-jadwal-kegiatan"
|
||||||
|
].create.post(payload);
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
toast.success("Berhasil menambahkan jadwal kegiatan");
|
||||||
|
this.resetForm();
|
||||||
|
await pendaftaranJadwalKegiatanState.findMany.load();
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
const msg = err?.message || "Terjadi kesalahan saat mengirim data";
|
||||||
|
toast.error(msg);
|
||||||
|
console.error("SUBMIT ERROR:", err);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetForm() {
|
||||||
|
this.form = { ...defaultForm };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
findMany: {
|
||||||
|
data: null as
|
||||||
|
| Prisma.PendaftaranJadwalKegiatanGetPayload<{
|
||||||
|
omit: {
|
||||||
|
isActive: true;
|
||||||
|
};
|
||||||
|
}>[]
|
||||||
|
| null,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
loading: false,
|
||||||
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.page = page;
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.kesehatan["pendaftaran-jadwal-kegiatan"][
|
||||||
|
"find-many"
|
||||||
|
].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.data = res.data.data ?? [];
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.totalPages =
|
||||||
|
res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.data = [];
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(
|
||||||
|
"Gagal fetch pendaftaran jadwal kegiatan paginated:",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.data = [];
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
pendaftaranJadwalKegiatanState.findMany.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
findUnique: {
|
||||||
|
data: null as Prisma.PendaftaranJadwalKegiatanGetPayload<{
|
||||||
|
omit: {
|
||||||
|
isActive: true;
|
||||||
|
};
|
||||||
|
}> | null,
|
||||||
|
async load(id: string) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(
|
||||||
|
`/api/kesehatan/pendaftaran-jadwal-kegiatan/${id}`
|
||||||
|
);
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json();
|
||||||
|
pendaftaranJadwalKegiatanState.findUnique.data = data.data ?? null;
|
||||||
|
} else {
|
||||||
|
console.error("Failed to fetch data", res.status, res.statusText);
|
||||||
|
pendaftaranJadwalKegiatanState.findUnique.data = null;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
pendaftaranJadwalKegiatanState.findUnique.data = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
loading: false,
|
||||||
|
async byId(id: string) {
|
||||||
|
if (!id) return toast.warn("ID tidak valid");
|
||||||
|
|
||||||
|
try {
|
||||||
|
pendaftaranJadwalKegiatanState.delete.loading = true;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/kesehatan/pendaftaran-jadwal-kegiatan/del/${id}`,
|
||||||
|
{
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok && result?.success) {
|
||||||
|
toast.success(
|
||||||
|
result.message || "Pendaftaran jadwal kegiatan berhasil dihapus"
|
||||||
|
);
|
||||||
|
await pendaftaranJadwalKegiatanState.findMany.load(); // refresh list
|
||||||
|
} else {
|
||||||
|
toast.error(
|
||||||
|
result?.message || "Gagal menghapus pendaftaran jadwal kegiatan"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal delete:", error);
|
||||||
|
toast.error(
|
||||||
|
"Terjadi kesalahan saat menghapus pendaftaran jadwal kegiatan"
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
pendaftaranJadwalKegiatanState.delete.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
id: "",
|
||||||
|
form: { ...defaultForm },
|
||||||
|
loading: false,
|
||||||
|
|
||||||
|
async load(id: string) {
|
||||||
|
if (!id) {
|
||||||
|
toast.warn("ID tidak valid");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/kesehatan/pendaftaran-jadwal-kegiatan/${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,
|
||||||
|
tanggal: data.tanggal,
|
||||||
|
namaOrangtua: data.namaOrangtua,
|
||||||
|
nomor: data.nomor,
|
||||||
|
alamat: data.alamat,
|
||||||
|
catatan: data.catatan,
|
||||||
|
};
|
||||||
|
return data; // Return the loaded data
|
||||||
|
} else {
|
||||||
|
throw new Error(result?.message || "Gagal memuat data");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading pendaftaran jadwal kegiatan:", error);
|
||||||
|
toast.error(
|
||||||
|
error instanceof Error ? error.message : "Gagal memuat data"
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async update() {
|
||||||
|
const cek = templateForm.safeParse(pendaftaranJadwalKegiatanState.edit.form);
|
||||||
|
if (!cek.success) {
|
||||||
|
const err = `[${cek.error.issues
|
||||||
|
.map((v) => `${v.path.join(".")}`)
|
||||||
|
.join("\n")}] required`;
|
||||||
|
toast.error(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pendaftaranJadwalKegiatanState.edit.loading = true;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/kesehatan/pendaftaran-jadwal-kegiatan/${this.id}`,
|
||||||
|
{
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: this.form.name,
|
||||||
|
tanggal: this.form.tanggal,
|
||||||
|
namaOrangtua: this.form.namaOrangtua,
|
||||||
|
nomor: this.form.nomor,
|
||||||
|
alamat: this.form.alamat,
|
||||||
|
catatan: this.form.catatan,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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 pendaftaran jadwal kegiatan");
|
||||||
|
await pendaftaranJadwalKegiatanState.findMany.load(); // refresh list
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || "Gagal update pendaftaran jadwal kegiatan");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating pendaftaran jadwal kegiatan:", error);
|
||||||
|
toast.error(
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "Terjadi kesalahan saat update pendaftaran jadwal kegiatan"
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
pendaftaranJadwalKegiatanState.edit.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
pendaftaranJadwalKegiatanState.edit.id = "";
|
||||||
|
pendaftaranJadwalKegiatanState.edit.form = { ...defaultForm };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default pendaftaranJadwalKegiatanState;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -50,18 +51,50 @@ const apbdes = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as Array<
|
data: null as
|
||||||
Prisma.APBDesGetPayload<{
|
| Prisma.APBDesGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
file: true;
|
file: true;
|
||||||
};
|
};
|
||||||
}>
|
}>[]
|
||||||
> | null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.landingpage.apbdes["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
total: 0,
|
||||||
apbdes.findMany.data = res.data?.data ?? [];
|
loading: false,
|
||||||
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||||
|
apbdes.findMany.loading = true; // Use the full path to access the property
|
||||||
|
apbdes.findMany.page = page;
|
||||||
|
apbdes.findMany.search = search;
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.landingpage.apbdes[
|
||||||
|
"findMany"
|
||||||
|
].get({
|
||||||
|
query
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
apbdes.findMany.data = res.data.data || [];
|
||||||
|
apbdes.findMany.total = res.data.total || 0;
|
||||||
|
apbdes.findMany.totalPages = res.data.totalPages || 1;
|
||||||
|
} else {
|
||||||
|
console.error("Failed to load pegawai:", res.data?.message);
|
||||||
|
apbdes.findMany.data = [];
|
||||||
|
apbdes.findMany.total = 0;
|
||||||
|
apbdes.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading pegawai:", error);
|
||||||
|
apbdes.findMany.data = [];
|
||||||
|
apbdes.findMany.total = 0;
|
||||||
|
apbdes.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
apbdes.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -60,16 +60,22 @@ const desaAntikorupsi = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
desaAntikorupsi.findMany.loading = true; // Use the full path to access the property
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
|
// Change to arrow function
|
||||||
|
desaAntikorupsi.findMany.loading = true; // Use the full path to access the property
|
||||||
desaAntikorupsi.findMany.page = page;
|
desaAntikorupsi.findMany.page = page;
|
||||||
|
desaAntikorupsi.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
||||||
"findMany"
|
"findMany"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
desaAntikorupsi.findMany.data = res.data.data || [];
|
desaAntikorupsi.findMany.data = res.data.data || [];
|
||||||
desaAntikorupsi.findMany.total = res.data.total || 0;
|
desaAntikorupsi.findMany.total = res.data.total || 0;
|
||||||
@@ -305,20 +311,25 @@ const kategoriDesaAntiKorupsi = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
kategoriDesaAntiKorupsi.findMany.loading = true; // Use the full path to access the property
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
|
// Change to arrow function
|
||||||
|
kategoriDesaAntiKorupsi.findMany.loading = true; // Use the full path to access the property
|
||||||
kategoriDesaAntiKorupsi.findMany.page = page;
|
kategoriDesaAntiKorupsi.findMany.page = page;
|
||||||
|
kategoriDesaAntiKorupsi.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
const res = await ApiFetch.api.landingpage.kategoridak[
|
const query: any = { page, limit };
|
||||||
"findMany"
|
if (search) query.search = search;
|
||||||
].get({
|
|
||||||
query: { page, limit },
|
const res = await ApiFetch.api.landingpage.kategoridak["findMany"].get({
|
||||||
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
kategoriDesaAntiKorupsi.findMany.data = res.data.data || [];
|
kategoriDesaAntiKorupsi.findMany.data = res.data.data || [];
|
||||||
kategoriDesaAntiKorupsi.findMany.total = res.data.total || 0;
|
kategoriDesaAntiKorupsi.findMany.total = res.data.total || 0;
|
||||||
kategoriDesaAntiKorupsi.findMany.totalPages = res.data.totalPages || 1;
|
kategoriDesaAntiKorupsi.findMany.totalPages =
|
||||||
|
res.data.totalPages || 1;
|
||||||
} else {
|
} else {
|
||||||
console.error("Failed to load media sosial:", res.data?.message);
|
console.error("Failed to load media sosial:", res.data?.message);
|
||||||
kategoriDesaAntiKorupsi.findMany.data = [];
|
kategoriDesaAntiKorupsi.findMany.data = [];
|
||||||
@@ -363,27 +374,30 @@ const kategoriDesaAntiKorupsi = proxy({
|
|||||||
try {
|
try {
|
||||||
kategoriDesaAntiKorupsi.delete.loading = true;
|
kategoriDesaAntiKorupsi.delete.loading = true;
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/landingpage/kategoridak/del/${id}`, {
|
||||||
`/api/landingpage/kategoridak/del/${id}`,
|
method: "DELETE",
|
||||||
{
|
headers: {
|
||||||
method: "DELETE",
|
"Content-Type": "application/json",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json",
|
});
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (response.ok && result?.success) {
|
if (response.ok && result?.success) {
|
||||||
toast.success(result.message || "Kategori desa anti korupsi berhasil dihapus");
|
toast.success(
|
||||||
|
result.message || "Kategori desa anti korupsi berhasil dihapus"
|
||||||
|
);
|
||||||
await kategoriDesaAntiKorupsi.findMany.load(); // refresh list
|
await kategoriDesaAntiKorupsi.findMany.load(); // refresh list
|
||||||
} else {
|
} else {
|
||||||
toast.error(result?.message || "Gagal menghapus kategori desa anti korupsi");
|
toast.error(
|
||||||
|
result?.message || "Gagal menghapus kategori desa anti korupsi"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Gagal delete:", error);
|
console.error("Gagal delete:", error);
|
||||||
toast.error("Terjadi kesalahan saat menghapus kategori desa anti korupsi");
|
toast.error(
|
||||||
|
"Terjadi kesalahan saat menghapus kategori desa anti korupsi"
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
kategoriDesaAntiKorupsi.delete.loading = false;
|
kategoriDesaAntiKorupsi.delete.loading = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -58,16 +59,43 @@ const prestasiDesa = proxy({
|
|||||||
Prisma.PrestasiDesaGetPayload<{
|
Prisma.PrestasiDesaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
kategori: true;
|
kategori: {
|
||||||
|
select: {
|
||||||
|
id: true;
|
||||||
|
name: true;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}>
|
}>
|
||||||
> | null,
|
> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.landingpage.prestasidesa[
|
totalPages: 1,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
prestasiDesa.findMany.data = res.data?.data ?? [];
|
prestasiDesa.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
prestasiDesa.findMany.page = page;
|
||||||
|
prestasiDesa.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.landingpage.prestasidesa["find-many"].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
prestasiDesa.findMany.data = res.data.data ?? [];
|
||||||
|
prestasiDesa.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
prestasiDesa.findMany.data = [];
|
||||||
|
prestasiDesa.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch prestasi desa paginated:", err);
|
||||||
|
prestasiDesa.findMany.data = [];
|
||||||
|
prestasiDesa.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
prestasiDesa.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -283,12 +311,34 @@ const kategoriPrestasi = proxy({
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
}> | null,
|
}> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.landingpage.kategoriprestasi[
|
totalPages: 1,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
kategoriPrestasi.findMany.data = res.data?.data ?? [];
|
kategoriPrestasi.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
kategoriPrestasi.findMany.page = page;
|
||||||
|
kategoriPrestasi.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.landingpage.kategoriprestasi["find-many"].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
kategoriPrestasi.findMany.data = res.data.data ?? [];
|
||||||
|
kategoriPrestasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
kategoriPrestasi.findMany.data = [];
|
||||||
|
kategoriPrestasi.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch kategori prestasi paginated:", err);
|
||||||
|
kategoriPrestasi.findMany.data = [];
|
||||||
|
kategoriPrestasi.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
kategoriPrestasi.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,7 +23,12 @@ type ProgramInovasiForm = Prisma.ProgramInovasiGetPayload<{
|
|||||||
|
|
||||||
const programInovasi = proxy({
|
const programInovasi = proxy({
|
||||||
create: {
|
create: {
|
||||||
form: {} as ProgramInovasiForm,
|
form: {
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
imageId: "",
|
||||||
|
link: ""
|
||||||
|
} as ProgramInovasiForm,
|
||||||
loading: false,
|
loading: false,
|
||||||
async create() {
|
async create() {
|
||||||
// Ensure all required fields are non-null
|
// Ensure all required fields are non-null
|
||||||
@@ -65,14 +70,19 @@ const programInovasi = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||||
programInovasi.findMany.loading = true; // Use the full path to access the property
|
programInovasi.findMany.loading = true; // Use the full path to access the property
|
||||||
programInovasi.findMany.page = page;
|
programInovasi.findMany.page = page;
|
||||||
|
programInovasi.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.landingpage.programinovasi[
|
const res = await ApiFetch.api.landingpage.programinovasi[
|
||||||
"findMany"
|
"findMany"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
@@ -482,14 +492,19 @@ const mediaSosial = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||||
mediaSosial.findMany.loading = true; // Use the full path to access the property
|
mediaSosial.findMany.loading = true; // Use the full path to access the property
|
||||||
mediaSosial.findMany.page = page;
|
mediaSosial.findMany.page = page;
|
||||||
try {
|
mediaSosial.findMany.search = search;
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.landingpage.mediasosial[
|
const res = await ApiFetch.api.landingpage.mediasosial[
|
||||||
"findMany"
|
"findMany"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
|||||||
@@ -58,16 +58,21 @@ const sdgsDesa = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => { // Change to arrow function
|
||||||
sdgsDesa.findMany.loading = true; // Use the full path to access the property
|
sdgsDesa.findMany.loading = true; // Use the full path to access the property
|
||||||
sdgsDesa.findMany.page = page;
|
sdgsDesa.findMany.page = page;
|
||||||
|
sdgsDesa.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
||||||
"findMany"
|
"findMany"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
sdgsDesa.findMany.data = res.data.data || [];
|
sdgsDesa.findMany.data = res.data.data || [];
|
||||||
sdgsDesa.findMany.total = res.data.total || 0;
|
sdgsDesa.findMany.total = res.data.total || 0;
|
||||||
@@ -89,7 +94,7 @@ const sdgsDesa = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as Prisma.SDGSDesaGetPayload<{
|
data: null as Prisma.SdgsDesaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,13 +56,17 @@ const dataLingkunganDesaState = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => {
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
// Change to arrow function
|
// Change to arrow function
|
||||||
dataLingkunganDesaState.findMany.loading = true; // Use the full path to access the property
|
dataLingkunganDesaState.findMany.loading = true; // Use the full path to access the property
|
||||||
dataLingkunganDesaState.findMany.page = page;
|
dataLingkunganDesaState.findMany.page = page;
|
||||||
|
dataLingkunganDesaState.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
const res = await ApiFetch.api.lingkungan.datalingkungandesa["find-many"].get({
|
const res = await ApiFetch.api.lingkungan.datalingkungandesa["find-many"].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -67,10 +68,46 @@ const kegiatanDesa = proxy({
|
|||||||
};
|
};
|
||||||
}>
|
}>
|
||||||
> | null,
|
> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.lingkungan.kegiatandesa["find-many"].get();
|
totalPages: 1,
|
||||||
if (res.status === 200) {
|
total: 0,
|
||||||
kegiatanDesa.findMany.data = res.data?.data ?? [];
|
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 };
|
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 ========================================= //
|
// ========================================= KATEGORI kegiatan ========================================= //
|
||||||
@@ -269,9 +335,7 @@ const kategoriKegiatan = proxy({
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
kategoriKegiatan.create.loading = true;
|
kategoriKegiatan.create.loading = true;
|
||||||
const res = await ApiFetch.api.lingkungan.kategorikegiatan[
|
const res = await ApiFetch.api.lingkungan.kategorikegiatan["create"].post(kategoriKegiatan.create.form);
|
||||||
"create"
|
|
||||||
].post(kategoriKegiatan.create.form);
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
kategoriKegiatan.findMany.load();
|
kategoriKegiatan.findMany.load();
|
||||||
return toast.success("Data berhasil ditambahkan");
|
return toast.success("Data berhasil ditambahkan");
|
||||||
@@ -305,9 +369,7 @@ const kategoriKegiatan = proxy({
|
|||||||
}> | null,
|
}> | null,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/lingkungan/kategorikegiatan/${id}`);
|
||||||
`/api/lingkungan/kategorikegiatan/${id}`
|
|
||||||
);
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
kategoriKegiatan.findUnique.data = data.data ?? null;
|
kategoriKegiatan.findUnique.data = data.data ?? null;
|
||||||
@@ -367,15 +429,12 @@ const kategoriKegiatan = proxy({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/lingkungan/kategorikegiatan/${id}`, {
|
||||||
`/api/lingkungan/kategorikegiatan/${id}`,
|
method: "GET",
|
||||||
{
|
headers: {
|
||||||
method: "GET",
|
"Content-Type": "application/json",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json",
|
});
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,15 +52,19 @@ const pengelolaanSampah = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => {
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
// Change to arrow function
|
// Change to arrow function
|
||||||
pengelolaanSampah.findMany.loading = true; // Use the full path to access the property
|
pengelolaanSampah.findMany.loading = true; // Use the full path to access the property
|
||||||
pengelolaanSampah.findMany.page = page;
|
pengelolaanSampah.findMany.page = page;
|
||||||
|
pengelolaanSampah.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
const res = await ApiFetch.api.lingkungan.pengelolaansampah[
|
const res = await ApiFetch.api.lingkungan.pengelolaansampah[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get({
|
].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
if (res.status === 200 && res.data?.success) {
|
||||||
@@ -265,7 +269,7 @@ const keteranganSampah = proxy({
|
|||||||
try {
|
try {
|
||||||
keteranganSampah.create.loading = true;
|
keteranganSampah.create.loading = true;
|
||||||
const res =
|
const res =
|
||||||
await ApiFetch.api.lingkungan.pengelolaansampah.keteranganbankterdekat[
|
await ApiFetch.api.lingkungan.keteranganbankterdekat[
|
||||||
"create"
|
"create"
|
||||||
].post(keteranganSampah.create.form);
|
].post(keteranganSampah.create.form);
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
@@ -287,14 +291,47 @@ const keteranganSampah = proxy({
|
|||||||
omit: { isActive: true };
|
omit: { isActive: true };
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.lingkungan.pengelolaansampah.keteranganbankterdekat[
|
totalPages: 1,
|
||||||
"find-many"
|
total: 0,
|
||||||
].get();
|
loading: false,
|
||||||
if (res.status === 200) {
|
search: "",
|
||||||
keteranganSampah.findMany.data = res.data?.data ?? [];
|
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: {
|
findUnique: {
|
||||||
data: null as Prisma.KeteranganBankSampahTerdekatGetPayload<{
|
data: null as Prisma.KeteranganBankSampahTerdekatGetPayload<{
|
||||||
@@ -302,7 +339,7 @@ const keteranganSampah = proxy({
|
|||||||
}> | null,
|
}> | null,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${id}`);
|
const res = await fetch(`/api/lingkungan/keteranganbankterdekat/${id}`);
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
keteranganSampah.findUnique.data = data.data ?? null;
|
keteranganSampah.findUnique.data = data.data ?? null;
|
||||||
@@ -324,7 +361,7 @@ const keteranganSampah = proxy({
|
|||||||
try {
|
try {
|
||||||
keteranganSampah.delete.loading = true;
|
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",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -359,7 +396,7 @@ const keteranganSampah = proxy({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${id}`, {
|
const response = await fetch(`/api/lingkungan/keteranganbankterdekat/${id}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -404,7 +441,7 @@ const keteranganSampah = proxy({
|
|||||||
try {
|
try {
|
||||||
keteranganSampah.edit.loading = true;
|
keteranganSampah.edit.loading = true;
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${this.id}`,
|
`/api/lingkungan/keteranganbankterdekat/${this.id}`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -56,13 +56,17 @@ const programPenghijauanState = proxy({
|
|||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
load: async (page = 1, limit = 10) => {
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
// Change to arrow function
|
// Change to arrow function
|
||||||
programPenghijauanState.findMany.loading = true; // Use the full path to access the property
|
programPenghijauanState.findMany.loading = true; // Use the full path to access the property
|
||||||
programPenghijauanState.findMany.page = page;
|
programPenghijauanState.findMany.page = page;
|
||||||
|
programPenghijauanState.findMany.search = search;
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
const res = await ApiFetch.api.lingkungan.programpenghijauan["find-many"].get({
|
const res = await ApiFetch.api.lingkungan.programpenghijauan["find-many"].get({
|
||||||
query: { page, limit },
|
query,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { proxy } from "valtio";
|
import { proxy } from "valtio";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
// ========================================= BEASISWA PENDAFTAR ========================================= //
|
||||||
|
|
||||||
const templateBeasiswaPendaftar = z.object({
|
const templateBeasiswaPendaftar = z.object({
|
||||||
namaLengkap: z.string().min(1, "Nama harus diisi"),
|
namaLengkap: z.string().min(1, "Nama harus diisi"),
|
||||||
nik: z.string().min(1, "NIK harus diisi"),
|
nik: z.string().min(1, "NIK harus diisi"),
|
||||||
@@ -76,13 +79,34 @@ const beasiswaPendaftar = proxy({
|
|||||||
isActive: true;
|
isActive: true;
|
||||||
};
|
};
|
||||||
}>[],
|
}>[],
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
search: "",
|
||||||
const res = await ApiFetch.api.pendidikan.beasiswa.beasiswapendaftar[
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
"findMany"
|
beasiswaPendaftar.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
].get();
|
beasiswaPendaftar.findMany.page = page;
|
||||||
if (res.status === 200) {
|
beasiswaPendaftar.findMany.search = search;
|
||||||
beasiswaPendaftar.findMany.data = res.data?.data ?? [];
|
|
||||||
|
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({
|
const beasiswaDesaState = proxy({
|
||||||
beasiswaPendaftar,
|
beasiswaPendaftar,
|
||||||
|
keunggulanProgram
|
||||||
});
|
});
|
||||||
|
|
||||||
export default beasiswaDesaState;
|
export default beasiswaDesaState;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -51,13 +52,46 @@ const jenjangPendidikan = proxy({
|
|||||||
id: string;
|
id: string;
|
||||||
nama: string;
|
nama: string;
|
||||||
}> | null,
|
}> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res =
|
totalPages: 1,
|
||||||
await ApiFetch.api.pendidikan.infosekolahpaud.jenjangpendidikan[
|
total: 0,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
jenjangPendidikan.findMany.data = res.data?.data ?? [];
|
// 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<{
|
Prisma.LembagaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
jenjangPendidikan: true;
|
jenjangPendidikan: true;
|
||||||
siswa: true;
|
|
||||||
pengajar: true;
|
|
||||||
};
|
};
|
||||||
}>
|
}> & {
|
||||||
|
siswa?: [];
|
||||||
|
pengajar?: [];
|
||||||
|
}
|
||||||
> | null,
|
> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res =
|
totalPages: 1,
|
||||||
await ApiFetch.api.pendidikan.infosekolahpaud.lembagapendidikan[
|
total: 0,
|
||||||
"find-many"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "", jenjangPendidikan = "") => {
|
||||||
lembagaPendidikan.findMany.data = res.data?.data ?? [];
|
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<
|
data: null as Array<
|
||||||
Prisma.SiswaGetPayload<{
|
Prisma.SiswaGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
lembaga: true;
|
lembaga: {
|
||||||
|
include: {
|
||||||
|
jenjangPendidikan: true;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}>
|
}>
|
||||||
> | null,
|
> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.pendidikan.infosekolahpaud.siswa[
|
totalPages: 1,
|
||||||
"find-many"
|
total: 0,
|
||||||
].get();
|
loading: false,
|
||||||
if (res.status === 200) {
|
search: "",
|
||||||
siswa.findMany.data = res.data?.data ?? [];
|
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<
|
data: null as Array<
|
||||||
Prisma.PengajarGetPayload<{
|
Prisma.PengajarGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
lembaga: true;
|
lembaga: {
|
||||||
|
include: {
|
||||||
|
jenjangPendidikan: true
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}>
|
}>
|
||||||
> | null,
|
> | null,
|
||||||
async load() {
|
page: 1,
|
||||||
const res = await ApiFetch.api.pendidikan.infosekolahpaud.pengajar[
|
totalPages: 1,
|
||||||
"find-many"
|
total: 0,
|
||||||
].get();
|
loading: false,
|
||||||
if (res.status === 200) {
|
search: "",
|
||||||
pengajar.findMany.data = res.data?.data ?? [];
|
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,
|
}> | null,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/pendidikan/infosekolahpaud/pengajar/${id}`);
|
const res = await fetch(
|
||||||
|
`/api/pendidikan/infosekolahpaud/pengajar/${id}`
|
||||||
|
);
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
pengajar.findUnique.data = data.data ?? null;
|
pengajar.findUnique.data = data.data ?? null;
|
||||||
@@ -948,7 +1109,8 @@ const pengajar = proxy({
|
|||||||
result
|
result
|
||||||
);
|
);
|
||||||
throw new Error(
|
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 ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -54,23 +55,46 @@ const dataPerpustakaan = proxy({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: [] as Prisma.DataPerpustakaanGetPayload<{
|
data: null as
|
||||||
include: {
|
| Prisma.DataPerpustakaanGetPayload<{
|
||||||
kategori: true;
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
};
|
kategori: true;
|
||||||
}>[],
|
};
|
||||||
loading: false,
|
}>[]
|
||||||
async load() {
|
| null,
|
||||||
const res =
|
page: 1,
|
||||||
await ApiFetch.api.pendidikan.perpustakaandigital.dataperpustakaan[
|
totalPages: 1,
|
||||||
"findMany"
|
loading: false,
|
||||||
].get();
|
search: "",
|
||||||
if (res.status === 200) {
|
load: async (page = 1, limit = 10, search = "", kategori = "") => {
|
||||||
dataPerpustakaan.findMany.data = res.data?.data ?? [];
|
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: {
|
findUnique: {
|
||||||
data: null as Prisma.DataPerpustakaanGetPayload<{
|
data: null as Prisma.DataPerpustakaanGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
@@ -293,14 +317,34 @@ const kategoriBuku = proxy({
|
|||||||
isActive: true;
|
isActive: true;
|
||||||
};
|
};
|
||||||
}>[],
|
}>[],
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
search: "",
|
||||||
const res =
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
await ApiFetch.api.pendidikan.perpustakaandigital.kategoribuku[
|
kategoriBuku.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
"findMany"
|
kategoriBuku.findMany.page = page;
|
||||||
].get();
|
kategoriBuku.findMany.search = search;
|
||||||
if (res.status === 200) {
|
|
||||||
kategoriBuku.findMany.data = res.data?.data ?? [];
|
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;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -348,18 +348,36 @@ const posisiOrganisasi = proxy({
|
|||||||
deskripsi: string | null;
|
deskripsi: string | null;
|
||||||
hierarki: number;
|
hierarki: number;
|
||||||
}>,
|
}>,
|
||||||
async load() {
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
loading: false,
|
||||||
|
search: "",
|
||||||
|
load: async (page = 1, limit?: number, search = "") => {
|
||||||
|
const appliedLimit = limit ?? 10;
|
||||||
|
posisiOrganisasi.findMany.page = page;
|
||||||
|
posisiOrganisasi.findMany.search = search;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const query: any = { page, limit: appliedLimit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
const res = await ApiFetch.api.ppid.strukturppid.posisiorganisasi[
|
const res = await ApiFetch.api.ppid.strukturppid.posisiorganisasi[
|
||||||
"find-many"
|
"find-many"
|
||||||
].get();
|
].get({ query });
|
||||||
if (res.status === 200) {
|
|
||||||
// The API now returns the id field, so we can use it directly
|
if (res.status === 200 && res.data?.success) {
|
||||||
this.data = res.data?.data ?? [];
|
posisiOrganisasi.findMany.data = res.data.data ?? [];
|
||||||
|
posisiOrganisasi.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
posisiOrganisasi.findMany.data = [];
|
||||||
|
posisiOrganisasi.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Find many error:", error);
|
console.error("Gagal fetch posisi organisasi paginated:", err);
|
||||||
this.data = [];
|
posisiOrganisasi.findMany.data = [];
|
||||||
|
posisiOrganisasi.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
posisiOrganisasi.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -438,9 +456,9 @@ const pegawai = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
pegawai.create.loading = true;
|
pegawai.create.loading = true;
|
||||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
const res = await ApiFetch.api.ppid.strukturppid.pegawai["create"].post(
|
||||||
"create"
|
pegawai.create.form
|
||||||
].post(pegawai.create.form);
|
);
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
toast.success("Pegawai berhasil ditambahkan");
|
toast.success("Pegawai berhasil ditambahkan");
|
||||||
await pegawai.findMany.load();
|
await pegawai.findMany.load();
|
||||||
@@ -457,42 +475,55 @@ const pegawai = proxy({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// In struktur-organisasi.ts
|
// In struktur-organisasi.ts
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as any[] | null,
|
data: null as
|
||||||
page: 1,
|
| Prisma.PegawaiPPIDGetPayload<{
|
||||||
totalPages: 1,
|
include: {
|
||||||
total: 0,
|
image: true;
|
||||||
loading: false,
|
posisi: true;
|
||||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
};
|
||||||
pegawai.findMany.loading = true; // Use the full path to access the property
|
}>[]
|
||||||
pegawai.findMany.page = page;
|
| null,
|
||||||
try {
|
page: 1,
|
||||||
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
totalPages: 1,
|
||||||
"find-many"
|
total: 0,
|
||||||
].get({
|
loading: false,
|
||||||
query: { page, limit },
|
search: "",
|
||||||
});
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
|
// Change to arrow function
|
||||||
|
pegawai.findMany.loading = true; // Use the full path to access the property
|
||||||
|
pegawai.findMany.page = page;
|
||||||
|
pegawai.findMany.search = search;
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
if (res.status === 200 && res.data?.success) {
|
const res = await ApiFetch.api.ppid.strukturppid.pegawai[
|
||||||
pegawai.findMany.data = res.data.data || [];
|
"find-many"
|
||||||
pegawai.findMany.total = res.data.total || 0;
|
].get({
|
||||||
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
query,
|
||||||
} else {
|
});
|
||||||
console.error("Failed to load pegawai:", res.data?.message);
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
pegawai.findMany.data = res.data.data || [];
|
||||||
|
pegawai.findMany.total = res.data.total || 0;
|
||||||
|
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
||||||
|
} else {
|
||||||
|
console.error("Failed to load pegawai:", res.data?.message);
|
||||||
|
pegawai.findMany.data = [];
|
||||||
|
pegawai.findMany.total = 0;
|
||||||
|
pegawai.findMany.totalPages = 1;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading pegawai:", error);
|
||||||
pegawai.findMany.data = [];
|
pegawai.findMany.data = [];
|
||||||
pegawai.findMany.total = 0;
|
pegawai.findMany.total = 0;
|
||||||
pegawai.findMany.totalPages = 1;
|
pegawai.findMany.totalPages = 1;
|
||||||
|
} finally {
|
||||||
|
pegawai.findMany.loading = false;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
},
|
||||||
console.error("Error loading pegawai:", error);
|
|
||||||
pegawai.findMany.data = [];
|
|
||||||
pegawai.findMany.total = 0;
|
|
||||||
pegawai.findMany.totalPages = 1;
|
|
||||||
} finally {
|
|
||||||
pegawai.findMany.loading = false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as
|
data: null as
|
||||||
| (Prisma.PegawaiGetPayload<{
|
| (Prisma.PegawaiGetPayload<{
|
||||||
@@ -521,12 +552,9 @@ findMany: {
|
|||||||
if (!id) return toast.warn("ID tidak valid");
|
if (!id) return toast.warn("ID tidak valid");
|
||||||
try {
|
try {
|
||||||
pegawai.delete.loading = true;
|
pegawai.delete.loading = true;
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/ppid/strukturppid/pegawai/del/${id}`, {
|
||||||
`/api/ppid/strukturppid/pegawai/del/${id}`,
|
method: "DELETE",
|
||||||
{
|
});
|
||||||
method: "DELETE",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
toast.success(json.message ?? "Berhasil hapus pegawai");
|
toast.success(json.message ?? "Berhasil hapus pegawai");
|
||||||
@@ -555,15 +583,12 @@ findMany: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/ppid/strukturppid/pegawai/${id}`, {
|
||||||
`/api/ppid/strukturppid/pegawai/${id}`,
|
method: "GET",
|
||||||
{
|
headers: {
|
||||||
method: "GET",
|
"Content-Type": "application/json",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json",
|
});
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
@@ -677,7 +702,7 @@ findMany: {
|
|||||||
const stateStrukturPPID = proxy({
|
const stateStrukturPPID = proxy({
|
||||||
stateStruktur,
|
stateStruktur,
|
||||||
posisiOrganisasi,
|
posisiOrganisasi,
|
||||||
pegawai
|
pegawai,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default stateStrukturPPID;
|
export default stateStrukturPPID;
|
||||||
|
|||||||
@@ -1,124 +1,43 @@
|
|||||||
import { proxy } from 'valtio'
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { toast } from 'react-toastify'
|
import { proxy } from "valtio";
|
||||||
import ApiFetch from '@/lib/api-fetch'
|
import { toast } from "react-toastify";
|
||||||
import { Prisma } from '@prisma/client'
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { z } from 'zod'
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
// 1. Validasi Zod
|
// State Valtio
|
||||||
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
|
|
||||||
const userState = proxy({
|
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
|
// Find Many
|
||||||
findMany: {
|
findMany: {
|
||||||
data: [] as Prisma.UserGetPayload<{ include: { role: true } }>[],
|
data: [] as Prisma.UserGetPayload<{ include: { role: true } }>[],
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
search: "",
|
||||||
this.loading = true
|
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 {
|
try {
|
||||||
const res = await ApiFetch.api.user.findMany.get()
|
const query: any = { page, limit };
|
||||||
if (res.status === 200) {
|
if (search) query.search = search;
|
||||||
this.data = res.data?.data || []
|
|
||||||
|
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) {
|
} catch (err) {
|
||||||
console.error(e)
|
console.error("Gagal fetch user paginated:", err);
|
||||||
toast.error('Gagal muat data user')
|
userState.findMany.data = [];
|
||||||
|
userState.findMany.totalPages = 1;
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
userState.findMany.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -128,71 +47,20 @@ const userState = proxy({
|
|||||||
data: null as Prisma.UserGetPayload<{ include: { role: true } }> | null,
|
data: null as Prisma.UserGetPayload<{ include: { role: true } }> | null,
|
||||||
loading: false,
|
loading: false,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
this.loading = true
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/user/findUnique/${id}`)
|
const res = await fetch(`/api/user/findUnique/${id}`);
|
||||||
const data = await res.json()
|
const data = await res.json();
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
this.data = data.data
|
this.data = data.data;
|
||||||
} else {
|
} else {
|
||||||
toast.error(data.message)
|
toast.error(data.message);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e);
|
||||||
toast.error('Gagal ambil data user')
|
toast.error("Gagal ambil data user");
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
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
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -201,35 +69,63 @@ const userState = proxy({
|
|||||||
delete: {
|
delete: {
|
||||||
loading: false,
|
loading: false,
|
||||||
async submit(id: string) {
|
async submit(id: string) {
|
||||||
this.loading = true
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/user/del/${id}`, {
|
const res = await fetch(`/api/user/del/${id}`, {
|
||||||
method: 'PUT',
|
method: "PUT",
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
});
|
||||||
const data = await res.json()
|
const data = await res.json();
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
toast.success('User dinonaktifkan')
|
toast.success("User dinonaktifkan");
|
||||||
userState.findMany.load()
|
userState.findMany.load();
|
||||||
} else {
|
} else {
|
||||||
toast.error(data.message || 'Gagal hapus')
|
toast.error(data.message || "Gagal hapus");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e);
|
||||||
toast.error('Gagal hapus user')
|
toast.error("Gagal hapus user");
|
||||||
} finally {
|
} 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({
|
const templateRole = z.object({
|
||||||
name: z.string().min(1, "Nama harus diisi"),
|
name: z.string().min(1, "Nama harus diisi"),
|
||||||
|
permissions: z.array(z.string()).min(1, "Permission harus diisi"),
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultRole = {
|
const defaultRole = {
|
||||||
name: "",
|
name: "",
|
||||||
|
permissions: [] as string[],
|
||||||
};
|
};
|
||||||
|
|
||||||
const roleState = proxy({
|
const roleState = proxy({
|
||||||
@@ -247,10 +143,9 @@ const roleState = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
roleState.create.loading = true;
|
roleState.create.loading = true;
|
||||||
const res =
|
const res = await ApiFetch.api.role["create"].post(
|
||||||
await ApiFetch.api.role[
|
roleState.create.form
|
||||||
"create"
|
);
|
||||||
].post(roleState.create.form);
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
roleState.findMany.load();
|
roleState.findMany.load();
|
||||||
return toast.success("Data role Berhasil Dibuat");
|
return toast.success("Data role Berhasil Dibuat");
|
||||||
@@ -273,10 +168,7 @@ const roleState = proxy({
|
|||||||
}>[],
|
}>[],
|
||||||
loading: false,
|
loading: false,
|
||||||
async load() {
|
async load() {
|
||||||
const res =
|
const res = await ApiFetch.api.role["findMany"].get();
|
||||||
await ApiFetch.api.role[
|
|
||||||
"findMany"
|
|
||||||
].get();
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
roleState.findMany.data = res.data?.data ?? [];
|
roleState.findMany.data = res.data?.data ?? [];
|
||||||
}
|
}
|
||||||
@@ -291,9 +183,7 @@ const roleState = proxy({
|
|||||||
loading: false,
|
loading: false,
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/role/${id}`);
|
||||||
`/api/role/${id}`
|
|
||||||
);
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
roleState.findUnique.data = data.data ?? null;
|
roleState.findUnique.data = data.data ?? null;
|
||||||
@@ -315,22 +205,17 @@ const roleState = proxy({
|
|||||||
try {
|
try {
|
||||||
roleState.delete.loading = true;
|
roleState.delete.loading = true;
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/role/del/${id}`, {
|
||||||
`/api/role/del/${id}`,
|
method: "DELETE",
|
||||||
{
|
headers: {
|
||||||
method: "DELETE",
|
"Content-Type": "application/json",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json",
|
});
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (response.ok && result?.success) {
|
if (response.ok && result?.success) {
|
||||||
toast.success(
|
toast.success(result.message || "Data role berhasil dihapus");
|
||||||
result.message || "Data role berhasil dihapus"
|
|
||||||
);
|
|
||||||
await roleState.findMany.load(); // refresh list
|
await roleState.findMany.load(); // refresh list
|
||||||
} else {
|
} else {
|
||||||
toast.error(result?.message || "Gagal menghapus Data role");
|
toast.error(result?.message || "Gagal menghapus Data role");
|
||||||
@@ -354,15 +239,12 @@ const roleState = proxy({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/role/${id}`, {
|
||||||
`/api/role/${id}`,
|
method: "GET",
|
||||||
{
|
headers: {
|
||||||
method: "GET",
|
"Content-Type": "application/json",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json",
|
});
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -374,6 +256,7 @@ const roleState = proxy({
|
|||||||
this.id = data.id;
|
this.id = data.id;
|
||||||
this.form = {
|
this.form = {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
|
permissions: data.permissions,
|
||||||
};
|
};
|
||||||
return data; // Return the loaded data
|
return data; // Return the loaded data
|
||||||
} else {
|
} else {
|
||||||
@@ -400,18 +283,16 @@ const roleState = proxy({
|
|||||||
try {
|
try {
|
||||||
roleState.update.loading = true;
|
roleState.update.loading = true;
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/role/${this.id}`, {
|
||||||
`/api/role/${this.id}`,
|
method: "PUT",
|
||||||
{
|
headers: {
|
||||||
method: "PUT",
|
"Content-Type": "application/json",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json",
|
body: JSON.stringify({
|
||||||
},
|
name: this.form.name,
|
||||||
body: JSON.stringify({
|
permissions: this.form.permissions,
|
||||||
name: this.form.name,
|
}),
|
||||||
}),
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
@@ -451,6 +332,6 @@ const roleState = proxy({
|
|||||||
const user = proxy({
|
const user = proxy({
|
||||||
userState,
|
userState,
|
||||||
roleState,
|
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 loading="lazy" 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 loading="lazy" 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 */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
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 { usePathname, useRouter } from 'next/navigation';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { IconFileText, IconBuildingStore, IconSparkles, IconUsers } from '@tabler/icons-react';
|
||||||
|
|
||||||
function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -12,26 +13,35 @@ function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
|||||||
{
|
{
|
||||||
label: "Pelayanan Surat Keterangan",
|
label: "Pelayanan Surat Keterangan",
|
||||||
value: "pelayanansuratketerangan",
|
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",
|
label: "Pelayanan Perizinan Berusaha",
|
||||||
value: "pelayananperizinanusaha",
|
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",
|
label: "Pelayanan Telunjuk Sakti Desa",
|
||||||
value: "pelayanantelunjuksaktidesa",
|
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",
|
label: "Pelayanan Penduduk Non-Permanent",
|
||||||
value: "pelayanantelunjuknonpermanent",
|
value: "pelayanannonpermanent",
|
||||||
href: "/admin/desa/layanan/pelayanan_penduduk_non_permanent"
|
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 handleTabChange = (value: string | null) => {
|
||||||
const tab = tabs.find(t => t.value === value)
|
const tab = tabs.find(t => t.value === value)
|
||||||
@@ -49,24 +59,72 @@ function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
|||||||
}, [pathname])
|
}, [pathname])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack gap="lg">
|
||||||
<Title order={3}>Layanan</Title>
|
<Title order={3} fw={700} style={{ color: "#1A1B1E" }}>Layanan</Title>
|
||||||
<Tabs color={colors['blue-button']} variant='pills' value={activeTab} onChange={handleTabChange}>
|
<Tabs
|
||||||
<TabsList p={"xs"} bg={"#BBC8E7FF"}>
|
color={colors["blue-button"]}
|
||||||
{tabs.map((e, i) => (
|
variant="pills"
|
||||||
<TabsTab key={i} value={e.value}>{e.label}</TabsTab>
|
value={activeTab}
|
||||||
))}
|
onChange={handleTabChange}
|
||||||
</TabsList>
|
radius="lg"
|
||||||
{tabs.map((e, i) => (
|
keepMounted={false}
|
||||||
<TabsPanel key={i} value={e.value}>
|
>
|
||||||
{/* Konten dummy, bisa diganti tergantung routing */}
|
{/* ✅ 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>
|
</TabsPanel>
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{children}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default LayoutTabsLayanan;
|
export default LayoutTabsLayanan;
|
||||||
|
|||||||