Compare commits
99 Commits
nico/24-ju
...
nico/30-ju
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e61695649 | |||
| c11cc421a4 | |||
| 0109886e00 | |||
| 50e8999205 | |||
| e2e1672c80 | |||
| ac0eb926eb | |||
| b24bcd8019 | |||
| 5601e59922 | |||
| a25cfe8b8a | |||
| b745bd4623 | |||
| bdf751ec3d | |||
| 1bc6dd8dbf | |||
| 88a10538a7 | |||
| d4efcacf1b | |||
| 9b2201ea57 | |||
| 80a7df663e | |||
| 9dfcda7687 | |||
| e2f75ff3ad | |||
| f05a096633 | |||
| 9c55869aa6 | |||
| 6e5d45fa20 | |||
| e5373b4823 | |||
| 928cd048c0 | |||
| 41f54772e9 | |||
| cd343badb2 | |||
| 4025771a4d | |||
| 7439eb7687 | |||
| 49a1084099 | |||
| cde6c91cd4 | |||
| 55433128a9 | |||
| e8ad74d118 | |||
| 99c1fd1004 | |||
| 03c0523194 | |||
| ae328f40a0 | |||
| 6e109ffe00 | |||
| c4aea568e9 | |||
| 1c8104ee69 | |||
| 4baffe95f3 | |||
| cb52701f47 | |||
| 2bc9b2f3c6 | |||
| 7b2b306849 | |||
| d328f64d86 | |||
| 119275b95c | |||
| 124dfb8160 | |||
| 46c79b8ded | |||
| d105293149 | |||
| adcbe3aa3d | |||
| bffe648802 | |||
| 7e95d5fbb4 | |||
| 2725c2c064 | |||
| be189df37c | |||
| c0b941395d | |||
| a2e25a3e3a | |||
| d86824a943 | |||
| c823462a47 | |||
| 4f97c01501 | |||
| 0fd47e3e94 | |||
| b92a974dcd | |||
| 10361770b4 | |||
| aec2f5094a | |||
| 72d39b020a | |||
| 51d67736ef | |||
| 406c6f3c9f | |||
| 1c5e4410c4 | |||
| 4724b7473d | |||
| 32a75bcb01 | |||
| c5fc4f4cea | |||
| 9f39eb41ab | |||
| 81ea18cb07 | |||
| dd7ce6943d | |||
| ee10f339e9 | |||
| 02462b2c19 | |||
| 41181d4cb3 | |||
| 6d5b8dcf64 | |||
| 924be5b11b | |||
| 21085ce342 | |||
| 88784f00f6 | |||
| 4f6cc66b7c | |||
| 456342851b | |||
| 4683034cd7 | |||
| 37de71a75a | |||
| fa922c7127 | |||
| 45acdba93f | |||
| cb8d561467 | |||
| 85a0cb6d56 | |||
| 4f2c565b2e | |||
| c4adc9bb22 | |||
| 9d572f82c3 | |||
| 452692f314 | |||
| 5010677bc8 | |||
| 7af3fbff2d | |||
| 34ca736dda | |||
| 3b61f54509 | |||
| fbe0c19d22 | |||
| f8914ab78f | |||
| 8f3ee2f831 | |||
| ddf0ca62c4 | |||
| f8cdd3abdd | |||
| 64bc739496 |
1
auth
Submodule
1
auth
Submodule
Submodule auth added at 51d749567a
21
package.json
21
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "desa-darmasaba",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.5",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
@@ -14,8 +14,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@cubejs-client/core": "^0.31.0",
|
||||
"@elysiajs/cookie": "^0.8.0",
|
||||
"@elysiajs/cors": "^1.2.0",
|
||||
"@elysiajs/eden": "^1.2.0",
|
||||
"@elysiajs/eden": "^1.3.2",
|
||||
"@elysiajs/jwt": "^1.3.2",
|
||||
"@elysiajs/static": "^1.3.0",
|
||||
"@elysiajs/stream": "^1.1.0",
|
||||
"@elysiajs/swagger": "^1.2.0",
|
||||
@@ -40,19 +42,24 @@
|
||||
"@tiptap/react": "^2.11.7",
|
||||
"@tiptap/starter-kit": "^2.11.7",
|
||||
"@types/bun": "^1.2.2",
|
||||
"@types/leaflet": "^1.9.20",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"add": "^2.0.6",
|
||||
"animate.css": "^4.1.1",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"bun": "^1.2.2",
|
||||
"chart.js": "^4.4.8",
|
||||
"dayjs": "^1.11.13",
|
||||
"elysia": "^1.2.12",
|
||||
"elysia": "^1.3.5",
|
||||
"embla-carousel-autoplay": "^8.5.2",
|
||||
"embla-carousel-react": "^7.1.0",
|
||||
"form-data": "^4.0.2",
|
||||
"framer-motion": "^12.4.1",
|
||||
"framer-motion": "^12.23.5",
|
||||
"get-port": "^7.1.0",
|
||||
"jotai": "^2.12.3",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"leaflet": "^1.9.4",
|
||||
"list": "^2.0.19",
|
||||
"lodash": "^4.17.21",
|
||||
"motion": "^12.4.1",
|
||||
"nanoid": "^5.1.5",
|
||||
@@ -63,6 +70,7 @@
|
||||
"prisma": "^6.3.1",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-simple-toasts": "^6.1.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"readdirp": "^4.1.1",
|
||||
@@ -74,15 +82,16 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "15.1.6",
|
||||
"parcel": "^2.6.2",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss-preset-mantine": "^1.17.0",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"typescript": "^5",
|
||||
"parcel": "^2.6.2"
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
[
|
||||
{
|
||||
"month": "Jan",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 160,
|
||||
"educatedUnemployment": 95,
|
||||
"uneducatedUnemployment": 65,
|
||||
"percentageChange": null
|
||||
},
|
||||
{
|
||||
"month": "Feb",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 155,
|
||||
"educatedUnemployment": 90,
|
||||
"uneducatedUnemployment": 65,
|
||||
"percentageChange": -3.1
|
||||
},
|
||||
{
|
||||
"month": "Mar",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 150,
|
||||
"educatedUnemployment": 88,
|
||||
"uneducatedUnemployment": 62,
|
||||
"percentageChange": -3.2
|
||||
},
|
||||
{
|
||||
"month": "Apr",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 148,
|
||||
"educatedUnemployment": 85,
|
||||
"uneducatedUnemployment": 63,
|
||||
"percentageChange": -1.3
|
||||
},
|
||||
{
|
||||
"month": "Mei",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 145,
|
||||
"educatedUnemployment": 82,
|
||||
"uneducatedUnemployment": 63,
|
||||
"percentageChange": -2.0
|
||||
},
|
||||
{
|
||||
"month": "Jun",
|
||||
"year": 2025,
|
||||
"totalUnemployment": 140,
|
||||
"educatedUnemployment": 80,
|
||||
"uneducatedUnemployment": 60,
|
||||
"percentageChange": -3.4
|
||||
}
|
||||
]
|
||||
|
||||
10
prisma/data/ekonomi/pasar-desa/kategori-produk.json
Normal file
10
prisma/data/ekonomi/pasar-desa/kategori-produk.json
Normal file
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"id": "4b95bge6-012e-5ged-9552-4d8g65d44959",
|
||||
"nama": "Makanan"
|
||||
},
|
||||
{
|
||||
"id": "5c06chf7-123f-6hfe-0663-5e9h76e55060",
|
||||
"nama": "Minuman"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"id": "650e8400-e29b-41d4-a716-446655440001",
|
||||
"atasanId": "550e8400-e29b-41d4-a716-446655440001",
|
||||
"bawahanId": "550e8400-e29b-41d4-a716-446655440002",
|
||||
"tipe": "Langsung Melapor"
|
||||
}
|
||||
]
|
||||
24
prisma/data/ekonomi/struktur-organisasi/pegawai.json
Normal file
24
prisma/data/ekonomi/struktur-organisasi/pegawai.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": "550e8400-e29b-41d4-a716-446655440001",
|
||||
"namaLengkap": "Budi Santoso",
|
||||
"gelarAkademik": "S.IP",
|
||||
"tanggalMasuk": "2020-01-01T00:00:00.000Z",
|
||||
"email": "budi@desa.id",
|
||||
"telepon": "081234567891",
|
||||
"alamat": "Jl. Raya Desa No. 1",
|
||||
"posisiId": "kepala_desa",
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": "550e8400-e29b-41d4-a716-446655440002",
|
||||
"namaLengkap": "Ani Lestari",
|
||||
"gelarAkademik": "S.Pd",
|
||||
"tanggalMasuk": "2020-02-01T00:00:00.000Z",
|
||||
"email": "ani@desa.id",
|
||||
"telepon": "081234567892",
|
||||
"alamat": "Jl. Raya Desa No. 2",
|
||||
"posisiId": "sekretaris_desa",
|
||||
"isActive": true
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
[
|
||||
{
|
||||
"id": "kepala_desa",
|
||||
"nama": "Kepala Desa",
|
||||
"deskripsi": "Kepala Desa",
|
||||
"hierarki": 1
|
||||
},
|
||||
{
|
||||
"id": "sekretaris_desa",
|
||||
"nama": "Sekretaris Desa",
|
||||
"deskripsi": "Sekretaris Desa",
|
||||
"hierarki": 2
|
||||
},
|
||||
{
|
||||
"id": "bendahara_desa",
|
||||
"nama": "Bendahara Desa",
|
||||
"deskripsi": "Bendahara Desa",
|
||||
"hierarki": 3
|
||||
},
|
||||
{
|
||||
"id": "staff_umum",
|
||||
"nama": "Staff Umum",
|
||||
"deskripsi": "Staff Umum",
|
||||
"hierarki": 4
|
||||
}
|
||||
]
|
||||
|
||||
8
prisma/data/landing-page/profile.json
Normal file
8
prisma/data/landing-page/profile.json
Normal file
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
||||
"position": "Perbekel Darmasaba periode 2021-2027"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Contoh Kegiatan di Desa Darmasaba",
|
||||
"deskripsi": "<ul><li><p>Pelatihan membuat kompos dari sampah rumah tangga</p></li><li><p>Gerakan Jumat Bersih rutin</p></li><li><p>Workshop membuat ecobrick</p></li><li><p>Lomba kebersihan antar banjar</p></li><li><p>Sosialisasi lingkungan di sekolah dan posyandu</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Materi Edukasi yang Diberikan",
|
||||
"deskripsi": "<ul><li><p>Pengelolaan Sampah (Pilah sampah organik dan anorganik)</p></li><li><p>Pencegahan pencemaran lingkungan (air, udara, dan tanah)</p></li><li><p>Pemanfaatan lahan hijau dan penghijauan desa</p></li><li><p>Daur ulang dan kreatifitas dari sampah</p></li><li><p>Bahaya pembakaran sampah sembarangan</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Tujuan Edukasi Lingkungan",
|
||||
"deskripsi": "<ul><li><p>Meningkatkan kesadaran masyarakat tentang pentingnya lingkungan bersih dan sehat</p></li><li><p>Mendorong partisipasi warga dalam kegiatan pengelolaan sampah, penghijauan, dan konservasi</p></li><li><p>Mengurangi dampak negatif terhadap lingkungan dari kegiatan manusia</p></li><li><p>Membentuk generasi muda yang peduli terhadap isu-isu lingkungan</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Bentuk Konservasi Berdasarkan Adat",
|
||||
"deskripsi": "<ul><li><p>Pelestarian Hutan Adat seperti Alas Pala Sangeh atau Wana Kerthi</p></li><li><p>Subak: Sistem pengelolaan irigasi tradisional yang menjunjung kebersamaan dan keberlanjutan</p></li><li><p>Hari Raya Tumpek Uduh: Perayaan khusus untuk menghormati pohon dan tumbuhan</p></li><li><p>Perarem dan Awig-Awig: Aturan adat desa yang mengatur larangan menebang pohon sembarangan, membuang limbah ke sungai, dll.</p></li><li><p>Ritual penyucian alam seperti Melasti, Piodalan Segara, dan lainnya</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Filosofi Tri Hita Karuna",
|
||||
"deskripsi": "<ul><li><p>Parahyangan: Hubungan manusia dengan Tuhan</p></li><li><p>Pawongan: Hubungan antar manusia</p></li><li><p>Palemahan: Hubungan manusia dengan alam</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Nilai Konservasi Adat",
|
||||
"deskripsi": "<ul><li><p>Menjaga keseimbangan ekosistem</p></li><li><p>Melestarikan spiritualitas lokal dan kesucian alam</p></li><li><p>Menumbuhkan kesadaran kolektif untuk hidup selaras dengan lingkungan</p></li><li><p>Menjaga keberlangsungan sumber daya alam untuk generasi mendatang</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Fasilitas yang Disediakan",
|
||||
"deskripsi": "<ul><li><p>Buku-buku pelajaran dan alat tulis</p></li><li><p>Ruang belajar nyaman dan kondusif</p></li><li><p>Modul latihan dan pendampingan tugas</p></li><li><p>Minuman ringan dan dukungan motivasi belajar</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Lokasi dan Jadwal",
|
||||
"deskripsi": "<ul><li><p>Lokasi: Balai Banjar / Balai Desa Darmasaba / Perpustakaan Desa</p></li><li><p>Jadwal: Setiap hari Senin, Rabu, dan Jumat pukul 16.00–18.00 WITA</p></li><li><p>Peserta: Terbuka untuk semua siswa SD–SMP di wilayah desa</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Tujuan Program",
|
||||
"deskripsi": "<ul><li><p>Memberikan pendampingan belajar secara gratis bagi siswa SD hingga SMP</p></li><li><p>Membantu siswa dalam menghadapi ujian dan menyelesaikan tugas sekolah</p></li><li><p>Menumbuhkan kepercayaan diri dan kemandirian dalam belajar</p></li><li><p>Meningkatkan kesetaraan pendidikan untuk seluruh anak desa</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Tempat Kegiatan",
|
||||
"deskripsi": "<p>Program Pendidikan Non Formal yang diselenggarakan di Desa Darmasaba meliputi:</p><p>1) Keaksaraan Fungsional</p><ul><li><p>Untuk warga yang belum bisa membaca dan menulis</p></li></ul><p>2) Pendidikan Kesetaraan (Paket A, B, C)</p><ul><li><p>Setara SD, SMP, dan SMA bagi yang tidak menyelesaikan pendidikan formal</p></li></ul><p>3) Pelatihan Keterampilan</p><ul><li><p>Menjahit, memasak, sablon, pertanian, peternakan, hingga teknologi digital</p></li></ul><p>4) Kursus & Pelatihan Soft Skill</p><ul><li><p>Public speaking, pengelolaan keuangan, kepemimpinan pemuda</p></li></ul><p>5) Pendidikan Keluarga & Parenting</p><ul><li><p>Untuk membekali orang tua dalam mendampingi tumbuh kembang anak</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Tempat Kegiatan",
|
||||
"deskripsi": "<ul><li><p>Balai Desa Darmasaba</p></li><li><p>TPK, Perpustakaan Desa, atau Posyandu</p></li><li><p>Bisa juga dilakukan secara mobile atau door to door</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Tujuan Program",
|
||||
"deskripsi": "<ul><li><p>Memberikan kesempatan belajar yang fleksibel bagi warga desa</p></li><li><p>Meningkatkan keterampilan hidup dan kemandirian ekonomi</p></li><li><p>Mendorong partisipasi masyarakat dalam pembangunan desa</p></li><li><p>Mengurangi angka putus sekolah dan meningkatkan kualitas SDM</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Program Unggulan",
|
||||
"deskripsi": "<ul><li><p>Bimbingan Belajar Gratis: Untuk siswa kurang mampu</p></li><li><p>Gerakan Literasi Desa: Meningkatkan minat baca sejak dini</p></li><li><p>Pelatihan Digital untuk Anak dan Remaja</p></li><li><p>Beasiswa Anak Berprestasi & Kurang Mampu</p></li></ul>"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"judul": "Tujuan Program",
|
||||
"deskripsi": "<ul><li><p>Meningkatkan akses pendidikan yang merata dan berkualitas</p></li><li><p>Menumbuhkan semangat belajar sejak dini</p></li><li><p>Membentuk karakter anak yang berakhlak dan berwawasan lingkungan</p></li><li><p>Mendukung tumbuh kembang anak melalui pendekatan pendidikan yang holistik</p></li></ul>"
|
||||
}
|
||||
]
|
||||
96
prisma/migrations/20250625035558_25jun2025_1/migration.sql
Normal file
96
prisma/migrations/20250625035558_25jun2025_1/migration.sql
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `_DokterdanTenagaMedisToFasilitasKesehatan` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_FasilitasKesehatanToFasilitasPendukung` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_FasilitasKesehatanToInformasiUmum` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_FasilitasKesehatanToLayananUnggulan` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_FasilitasKesehatanToProsedurPendaftaran` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_FasilitasKesehatanToTarifDanLayanan` table. If the table is not empty, all the data it contains will be lost.
|
||||
- Added the required column `dokterdanTenagaMedisId` to the `FasilitasKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `fasilitasPendukungId` to the `FasilitasKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `informasiUmumId` to the `FasilitasKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `layananUnggulanId` to the `FasilitasKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `prosedurPendaftaranId` to the `FasilitasKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `tarifDanLayananId` to the `FasilitasKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_DokterdanTenagaMedisToFasilitasKesehatan" DROP CONSTRAINT "_DokterdanTenagaMedisToFasilitasKesehatan_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_DokterdanTenagaMedisToFasilitasKesehatan" DROP CONSTRAINT "_DokterdanTenagaMedisToFasilitasKesehatan_B_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToFasilitasPendukung" DROP CONSTRAINT "_FasilitasKesehatanToFasilitasPendukung_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToFasilitasPendukung" DROP CONSTRAINT "_FasilitasKesehatanToFasilitasPendukung_B_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToInformasiUmum" DROP CONSTRAINT "_FasilitasKesehatanToInformasiUmum_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToInformasiUmum" DROP CONSTRAINT "_FasilitasKesehatanToInformasiUmum_B_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToLayananUnggulan" DROP CONSTRAINT "_FasilitasKesehatanToLayananUnggulan_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToLayananUnggulan" DROP CONSTRAINT "_FasilitasKesehatanToLayananUnggulan_B_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToProsedurPendaftaran" DROP CONSTRAINT "_FasilitasKesehatanToProsedurPendaftaran_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToProsedurPendaftaran" DROP CONSTRAINT "_FasilitasKesehatanToProsedurPendaftaran_B_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToTarifDanLayanan" DROP CONSTRAINT "_FasilitasKesehatanToTarifDanLayanan_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_FasilitasKesehatanToTarifDanLayanan" DROP CONSTRAINT "_FasilitasKesehatanToTarifDanLayanan_B_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "FasilitasKesehatan" ADD COLUMN "dokterdanTenagaMedisId" TEXT NOT NULL,
|
||||
ADD COLUMN "fasilitasPendukungId" TEXT NOT NULL,
|
||||
ADD COLUMN "informasiUmumId" TEXT NOT NULL,
|
||||
ADD COLUMN "layananUnggulanId" TEXT NOT NULL,
|
||||
ADD COLUMN "prosedurPendaftaranId" TEXT NOT NULL,
|
||||
ADD COLUMN "tarifDanLayananId" TEXT NOT NULL;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_DokterdanTenagaMedisToFasilitasKesehatan";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_FasilitasKesehatanToFasilitasPendukung";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_FasilitasKesehatanToInformasiUmum";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_FasilitasKesehatanToLayananUnggulan";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_FasilitasKesehatanToProsedurPendaftaran";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_FasilitasKesehatanToTarifDanLayanan";
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FasilitasKesehatan" ADD CONSTRAINT "FasilitasKesehatan_informasiUmumId_fkey" FOREIGN KEY ("informasiUmumId") REFERENCES "InformasiUmum"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FasilitasKesehatan" ADD CONSTRAINT "FasilitasKesehatan_layananUnggulanId_fkey" FOREIGN KEY ("layananUnggulanId") REFERENCES "LayananUnggulan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FasilitasKesehatan" ADD CONSTRAINT "FasilitasKesehatan_dokterdanTenagaMedisId_fkey" FOREIGN KEY ("dokterdanTenagaMedisId") REFERENCES "DokterdanTenagaMedis"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FasilitasKesehatan" ADD CONSTRAINT "FasilitasKesehatan_fasilitasPendukungId_fkey" FOREIGN KEY ("fasilitasPendukungId") REFERENCES "FasilitasPendukung"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FasilitasKesehatan" ADD CONSTRAINT "FasilitasKesehatan_prosedurPendaftaranId_fkey" FOREIGN KEY ("prosedurPendaftaranId") REFERENCES "ProsedurPendaftaran"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FasilitasKesehatan" ADD CONSTRAINT "FasilitasKesehatan_tarifDanLayananId_fkey" FOREIGN KEY ("tarifDanLayananId") REFERENCES "TarifDanLayanan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
32
prisma/migrations/20250625085706_25_jun_25_2/migration.sql
Normal file
32
prisma/migrations/20250625085706_25_jun_25_2/migration.sql
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The primary key for the `DataKematian_Kelahiran` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The `id` column on the `DataKematian_Kelahiran` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||
- The primary key for the `GrafikKepuasan` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The `id` column on the `GrafikKepuasan` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||
- A unique constraint covering the columns `[uuid]` on the table `DataKematian_Kelahiran` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[uuid]` on the table `GrafikKepuasan` will be added. If there are existing duplicate values, this will fail.
|
||||
- The required column `uuid` was added to the `DataKematian_Kelahiran` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required.
|
||||
- The required column `uuid` was added to the `GrafikKepuasan` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "DataKematian_Kelahiran" DROP CONSTRAINT "DataKematian_Kelahiran_pkey",
|
||||
ADD COLUMN "uuid" TEXT NOT NULL,
|
||||
DROP COLUMN "id",
|
||||
ADD COLUMN "id" SERIAL NOT NULL,
|
||||
ADD CONSTRAINT "DataKematian_Kelahiran_pkey" PRIMARY KEY ("id");
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "GrafikKepuasan" DROP CONSTRAINT "GrafikKepuasan_pkey",
|
||||
ADD COLUMN "uuid" TEXT NOT NULL,
|
||||
DROP COLUMN "id",
|
||||
ADD COLUMN "id" SERIAL NOT NULL,
|
||||
ADD CONSTRAINT "GrafikKepuasan_pkey" PRIMARY KEY ("id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "DataKematian_Kelahiran_uuid_key" ON "DataKematian_Kelahiran"("uuid");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "GrafikKepuasan_uuid_key" ON "GrafikKepuasan"("uuid");
|
||||
92
prisma/migrations/20250626061909_26_jun_25_01/migration.sql
Normal file
92
prisma/migrations/20250626061909_26_jun_25_01/migration.sql
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The primary key for the `ArtikelKesehatan` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The primary key for the `DoctorSign` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The primary key for the `FirstAid` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The primary key for the `Introduction` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The primary key for the `MythVsFact` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The primary key for the `Prevention` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The primary key for the `Symptom` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- Added the required column `deskripsiJadwalKegiatanId` to the `JadwalKegiatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `dokumenJadwalKegiatanId` to the `JadwalKegiatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `informasiJadwalKegiatanId` to the `JadwalKegiatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `layananJadwalKegiatanId` to the `JadwalKegiatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `pendaftaranJadwalKegiatanId` to the `JadwalKegiatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `syaratKetentuanJadwalKegiatanId` to the `JadwalKegiatan` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "ArtikelKesehatan" DROP CONSTRAINT "ArtikelKesehatan_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ADD CONSTRAINT "ArtikelKesehatan_pkey" PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "ArtikelKesehatan_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "DoctorSign" DROP CONSTRAINT "DoctorSign_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ADD CONSTRAINT "DoctorSign_pkey" PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "DoctorSign_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "FirstAid" DROP CONSTRAINT "FirstAid_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ADD CONSTRAINT "FirstAid_pkey" PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "FirstAid_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Introduction" DROP CONSTRAINT "Introduction_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ADD CONSTRAINT "Introduction_pkey" PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "Introduction_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "JadwalKegiatan" ADD COLUMN "deskripsiJadwalKegiatanId" TEXT NOT NULL,
|
||||
ADD COLUMN "dokumenJadwalKegiatanId" TEXT NOT NULL,
|
||||
ADD COLUMN "informasiJadwalKegiatanId" TEXT NOT NULL,
|
||||
ADD COLUMN "layananJadwalKegiatanId" TEXT NOT NULL,
|
||||
ADD COLUMN "pendaftaranJadwalKegiatanId" TEXT NOT NULL,
|
||||
ADD COLUMN "syaratKetentuanJadwalKegiatanId" TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "MythVsFact" DROP CONSTRAINT "MythVsFact_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ADD CONSTRAINT "MythVsFact_pkey" PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "MythVsFact_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Prevention" DROP CONSTRAINT "Prevention_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ADD CONSTRAINT "Prevention_pkey" PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "Prevention_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Symptom" DROP CONSTRAINT "Symptom_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ADD CONSTRAINT "Symptom_pkey" PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "Symptom_id_seq";
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JadwalKegiatan" ADD CONSTRAINT "JadwalKegiatan_informasiJadwalKegiatanId_fkey" FOREIGN KEY ("informasiJadwalKegiatanId") REFERENCES "InformasiJadwalKegiatan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JadwalKegiatan" ADD CONSTRAINT "JadwalKegiatan_deskripsiJadwalKegiatanId_fkey" FOREIGN KEY ("deskripsiJadwalKegiatanId") REFERENCES "DeskripsiJadwalKegiatan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JadwalKegiatan" ADD CONSTRAINT "JadwalKegiatan_layananJadwalKegiatanId_fkey" FOREIGN KEY ("layananJadwalKegiatanId") REFERENCES "LayananJadwalKegiatan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JadwalKegiatan" ADD CONSTRAINT "JadwalKegiatan_syaratKetentuanJadwalKegiatanId_fkey" FOREIGN KEY ("syaratKetentuanJadwalKegiatanId") REFERENCES "SyaratKetentuanJadwalKegiatan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JadwalKegiatan" ADD CONSTRAINT "JadwalKegiatan_dokumenJadwalKegiatanId_fkey" FOREIGN KEY ("dokumenJadwalKegiatanId") REFERENCES "DokumenJadwalKegiatan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JadwalKegiatan" ADD CONSTRAINT "JadwalKegiatan_pendaftaranJadwalKegiatanId_fkey" FOREIGN KEY ("pendaftaranJadwalKegiatanId") REFERENCES "PendaftaranJadwalKegiatan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The primary key for the `DataKematian_Kelahiran` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- You are about to drop the column `uuid` on the `DataKematian_Kelahiran` table. All the data in the column will be lost.
|
||||
- The primary key for the `GrafikKepuasan` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- You are about to drop the column `uuid` on the `GrafikKepuasan` table. All the data in the column will be lost.
|
||||
- A unique constraint covering the columns `[id]` on the table `DataKematian_Kelahiran` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[id]` on the table `GrafikKepuasan` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `doctorSignId` to the `ArtikelKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `firstAidId` to the `ArtikelKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `introductionId` to the `ArtikelKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `mythVsFactId` to the `ArtikelKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `preventionId` to the `ArtikelKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `symptomId` to the `ArtikelKesehatan` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropIndex
|
||||
DROP INDEX "DataKematian_Kelahiran_uuid_key";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "GrafikKepuasan_uuid_key";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "ArtikelKesehatan" ADD COLUMN "doctorSignId" TEXT NOT NULL,
|
||||
ADD COLUMN "firstAidId" TEXT NOT NULL,
|
||||
ADD COLUMN "introductionId" TEXT NOT NULL,
|
||||
ADD COLUMN "mythVsFactId" TEXT NOT NULL,
|
||||
ADD COLUMN "preventionId" TEXT NOT NULL,
|
||||
ADD COLUMN "symptomId" TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "DataKematian_Kelahiran" DROP CONSTRAINT "DataKematian_Kelahiran_pkey",
|
||||
DROP COLUMN "uuid",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT;
|
||||
DROP SEQUENCE "DataKematian_Kelahiran_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "GrafikKepuasan" DROP CONSTRAINT "GrafikKepuasan_pkey",
|
||||
DROP COLUMN "uuid",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT;
|
||||
DROP SEQUENCE "GrafikKepuasan_id_seq";
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "DataKematian_Kelahiran_id_key" ON "DataKematian_Kelahiran"("id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "GrafikKepuasan_id_key" ON "GrafikKepuasan"("id");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ArtikelKesehatan" ADD CONSTRAINT "ArtikelKesehatan_introductionId_fkey" FOREIGN KEY ("introductionId") REFERENCES "Introduction"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ArtikelKesehatan" ADD CONSTRAINT "ArtikelKesehatan_symptomId_fkey" FOREIGN KEY ("symptomId") REFERENCES "Symptom"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ArtikelKesehatan" ADD CONSTRAINT "ArtikelKesehatan_preventionId_fkey" FOREIGN KEY ("preventionId") REFERENCES "Prevention"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ArtikelKesehatan" ADD CONSTRAINT "ArtikelKesehatan_firstAidId_fkey" FOREIGN KEY ("firstAidId") REFERENCES "FirstAid"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ArtikelKesehatan" ADD CONSTRAINT "ArtikelKesehatan_mythVsFactId_fkey" FOREIGN KEY ("mythVsFactId") REFERENCES "MythVsFact"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ArtikelKesehatan" ADD CONSTRAINT "ArtikelKesehatan_doctorSignId_fkey" FOREIGN KEY ("doctorSignId") REFERENCES "DoctorSign"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
201
prisma/migrations/20250630030216_nico_30_jun_25_1/migration.sql
Normal file
201
prisma/migrations/20250630030216_nico_30_jun_25_1/migration.sql
Normal file
@@ -0,0 +1,201 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "StatusLaporan" AS ENUM ('SELESAI', 'PROSES', 'GAGAL');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "DataKematian_Kelahiran" ADD CONSTRAINT "DataKematian_Kelahiran_pkey" PRIMARY KEY ("id");
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "DataKematian_Kelahiran_id_key";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "GrafikKepuasan" ADD CONSTRAINT "GrafikKepuasan_pkey" PRIMARY KEY ("id");
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "GrafikKepuasan_id_key";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KeamananLingkungan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"imageId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "KeamananLingkungan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PolsekTerdekat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"jarakKeDesa" TEXT NOT NULL,
|
||||
"alamat" TEXT NOT NULL,
|
||||
"nomorTelepon" TEXT NOT NULL,
|
||||
"jamOperasional" TEXT NOT NULL,
|
||||
"embedMapUrl" TEXT NOT NULL,
|
||||
"namaTempatMaps" TEXT NOT NULL,
|
||||
"alamatMaps" TEXT NOT NULL,
|
||||
"linkPetunjukArah" TEXT NOT NULL,
|
||||
"layananPolsekId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "PolsekTerdekat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LayananPolsek" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "LayananPolsek_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KontakDaruratKeamanan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"kontak" TEXT NOT NULL,
|
||||
"icon" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "KontakDaruratKeamanan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PencegahanKriminalitas" (
|
||||
"id" TEXT NOT NULL,
|
||||
"programKeamananId" TEXT NOT NULL,
|
||||
"tipsKeamananId" TEXT NOT NULL,
|
||||
"videoKeamananId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "PencegahanKriminalitas_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ProgramKeamanan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"deskripsi" TEXT,
|
||||
"slug" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ProgramKeamanan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TipsKeamanan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"konten" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "TipsKeamanan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "VideoKeamanan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT,
|
||||
"videoUrl" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "VideoKeamanan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LaporanPublik" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"lokasi" TEXT NOT NULL,
|
||||
"tanggalWaktu" TIMESTAMP(3) NOT NULL,
|
||||
"status" "StatusLaporan" NOT NULL,
|
||||
"kronologi" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "LaporanPublik_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PenangananLaporanPublik" (
|
||||
"id" TEXT NOT NULL,
|
||||
"laporanId" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "PenangananLaporanPublik_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Pelapor" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"alamat" TEXT NOT NULL,
|
||||
"nomorTelepon" TEXT NOT NULL,
|
||||
"imageId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Pelapor_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "MenuTipsKeamanan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"imageId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "MenuTipsKeamanan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ProgramKeamanan_slug_key" ON "ProgramKeamanan"("slug");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KeamananLingkungan" ADD CONSTRAINT "KeamananLingkungan_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PolsekTerdekat" ADD CONSTRAINT "PolsekTerdekat_layananPolsekId_fkey" FOREIGN KEY ("layananPolsekId") REFERENCES "LayananPolsek"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PencegahanKriminalitas" ADD CONSTRAINT "PencegahanKriminalitas_programKeamananId_fkey" FOREIGN KEY ("programKeamananId") REFERENCES "ProgramKeamanan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PencegahanKriminalitas" ADD CONSTRAINT "PencegahanKriminalitas_tipsKeamananId_fkey" FOREIGN KEY ("tipsKeamananId") REFERENCES "TipsKeamanan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PencegahanKriminalitas" ADD CONSTRAINT "PencegahanKriminalitas_videoKeamananId_fkey" FOREIGN KEY ("videoKeamananId") REFERENCES "VideoKeamanan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PenangananLaporanPublik" ADD CONSTRAINT "PenangananLaporanPublik_laporanId_fkey" FOREIGN KEY ("laporanId") REFERENCES "LaporanPublik"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Pelapor" ADD CONSTRAINT "Pelapor_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "MenuTipsKeamanan" ADD CONSTRAINT "MenuTipsKeamanan_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "LayananPolsek" ALTER COLUMN "deletedAt" DROP NOT NULL,
|
||||
ALTER COLUMN "deletedAt" DROP DEFAULT;
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `deletedAt` on the `KontakDarurat` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `deskripsi` on the `KontakDarurat` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `imageId` on the `KontakDarurat` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `isActive` on the `KontakDarurat` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `name` on the `KontakDarurat` table. All the data in the column will be lost.
|
||||
- Added the required column `nama` to the `KontakDarurat` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "KontakDarurat" DROP CONSTRAINT "KontakDarurat_imageId_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "KontakDarurat" DROP COLUMN "deletedAt",
|
||||
DROP COLUMN "deskripsi",
|
||||
DROP COLUMN "imageId",
|
||||
DROP COLUMN "isActive",
|
||||
DROP COLUMN "name",
|
||||
ADD COLUMN "icon" TEXT,
|
||||
ADD COLUMN "nama" TEXT NOT NULL,
|
||||
ADD COLUMN "urutan" INTEGER;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KontakItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"nomorTelepon" TEXT NOT NULL,
|
||||
"icon" TEXT,
|
||||
"kategoriId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "KontakItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PasarDesa" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"harga" INTEGER NOT NULL,
|
||||
"satuan" TEXT NOT NULL,
|
||||
"alamat" TEXT NOT NULL,
|
||||
"imageId" TEXT NOT NULL,
|
||||
"rating" DOUBLE PRECISION NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"kategoriId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "PasarDesa_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KategoriMakanan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3),
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "KategoriMakanan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KontakItem" ADD CONSTRAINT "KontakItem_kategoriId_fkey" FOREIGN KEY ("kategoriId") REFERENCES "KontakDarurat"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PasarDesa" ADD CONSTRAINT "PasarDesa_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PasarDesa" ADD CONSTRAINT "PasarDesa_kategoriId_fkey" FOREIGN KEY ("kategoriId") REFERENCES "KategoriMakanan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `icon` on the `KontakDarurat` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `nama` on the `KontakDarurat` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `urutan` on the `KontakDarurat` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `deletedAt` on the `KontakDaruratKeamanan` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `isActive` on the `KontakDaruratKeamanan` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `kontak` on the `KontakDaruratKeamanan` table. All the data in the column will be lost.
|
||||
- Added the required column `deskripsi` to the `KontakDarurat` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `imageId` to the `KontakDarurat` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `name` to the `KontakDarurat` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "KontakItem" DROP CONSTRAINT "KontakItem_kategoriId_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "KontakDarurat" DROP COLUMN "icon",
|
||||
DROP COLUMN "nama",
|
||||
DROP COLUMN "urutan",
|
||||
ADD COLUMN "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "deskripsi" TEXT NOT NULL,
|
||||
ADD COLUMN "imageId" TEXT NOT NULL,
|
||||
ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
ADD COLUMN "name" TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "KontakDaruratKeamanan" DROP COLUMN "deletedAt",
|
||||
DROP COLUMN "isActive",
|
||||
DROP COLUMN "kontak",
|
||||
ADD COLUMN "urutan" INTEGER;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KontakDarurat" ADD CONSTRAINT "KontakDarurat_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KontakItem" ADD CONSTRAINT "KontakItem_kategoriId_fkey" FOREIGN KEY ("kategoriId") REFERENCES "KontakDaruratKeamanan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
85
prisma/migrations/20250703070556_3_jul_2025_1/migration.sql
Normal file
85
prisma/migrations/20250703070556_3_jul_2025_1/migration.sql
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The values [SELESAI,PROSES,GAGAL] on the enum `StatusLaporan` will be removed. If these variants are still used in the database, this will fail.
|
||||
- You are about to drop the column `icon` on the `KontakDaruratKeamanan` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `urutan` on the `KontakDaruratKeamanan` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `icon` on the `KontakItem` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterEnum
|
||||
BEGIN;
|
||||
CREATE TYPE "StatusLaporan_new" AS ENUM ('Selesai', 'Proses', 'Gagal');
|
||||
ALTER TABLE "LaporanPublik" ALTER COLUMN "status" TYPE "StatusLaporan_new" USING ("status"::text::"StatusLaporan_new");
|
||||
ALTER TYPE "StatusLaporan" RENAME TO "StatusLaporan_old";
|
||||
ALTER TYPE "StatusLaporan_new" RENAME TO "StatusLaporan";
|
||||
DROP TYPE "StatusLaporan_old";
|
||||
COMMIT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "KontakDaruratKeamanan" DROP COLUMN "icon",
|
||||
DROP COLUMN "urutan",
|
||||
ADD COLUMN "imageId" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "KontakItem" DROP COLUMN "icon",
|
||||
ADD COLUMN "imageId" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LowonganPekerjaan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"posisi" TEXT NOT NULL,
|
||||
"namaPerusahaan" TEXT NOT NULL,
|
||||
"lokasi" TEXT NOT NULL,
|
||||
"tipePekerjaan" TEXT NOT NULL,
|
||||
"gaji" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"kualifikasi" TEXT NOT NULL,
|
||||
"tanggalPosting" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "LowonganPekerjaan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ProgramKemiskinan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"ikonUrl" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"statistikId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ProgramKemiskinan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "StatistikKemiskinan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tahun" INTEGER NOT NULL,
|
||||
"jumlah" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "StatistikKemiskinan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ProgramKemiskinan_statistikId_key" ON "ProgramKemiskinan"("statistikId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "StatistikKemiskinan_tahun_key" ON "StatistikKemiskinan"("tahun");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KontakDaruratKeamanan" ADD CONSTRAINT "KontakDaruratKeamanan_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KontakItem" ADD CONSTRAINT "KontakItem_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ProgramKemiskinan" ADD CONSTRAINT "ProgramKemiskinan_statistikId_fkey" FOREIGN KEY ("statistikId") REFERENCES "StatistikKemiskinan"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `alamat` on the `PasarDesa` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `deletedAt` on the `PasarDesa` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `isActive` on the `PasarDesa` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `kategoriId` on the `PasarDesa` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `satuan` on the `PasarDesa` table. All the data in the column will be lost.
|
||||
- You are about to drop the `KategoriMakanan` table. If the table is not empty, all the data it contains will be lost.
|
||||
- Added the required column `alamatUsaha` to the `PasarDesa` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "PasarDesa" DROP CONSTRAINT "PasarDesa_imageId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "PasarDesa" DROP CONSTRAINT "PasarDesa_kategoriId_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "PasarDesa" DROP COLUMN "alamat",
|
||||
DROP COLUMN "deletedAt",
|
||||
DROP COLUMN "isActive",
|
||||
DROP COLUMN "kategoriId",
|
||||
DROP COLUMN "satuan",
|
||||
ADD COLUMN "alamatUsaha" TEXT NOT NULL,
|
||||
ALTER COLUMN "imageId" DROP NOT NULL;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "KategoriMakanan";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KategoriProduk" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "KategoriProduk_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_ProdukToKategori" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_ProdukToKategori_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_ProdukToKategori_B_index" ON "_ProdukToKategori"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PasarDesa" ADD CONSTRAINT "PasarDesa_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ProdukToKategori" ADD CONSTRAINT "_ProdukToKategori_A_fkey" FOREIGN KEY ("A") REFERENCES "KategoriProduk"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ProdukToKategori" ADD CONSTRAINT "_ProdukToKategori_B_fkey" FOREIGN KEY ("B") REFERENCES "PasarDesa"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `_ProdukToKategori` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_ProdukToKategori" DROP CONSTRAINT "_ProdukToKategori_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_ProdukToKategori" DROP CONSTRAINT "_ProdukToKategori_B_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "KategoriProduk" ADD COLUMN "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "PasarDesa" ADD COLUMN "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_ProdukToKategori";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KategoriToPasar" (
|
||||
"id" TEXT NOT NULL,
|
||||
"kategoriId" TEXT NOT NULL,
|
||||
"pasarDesaId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "KategoriToPasar_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KategoriToPasar" ADD CONSTRAINT "KategoriToPasar_kategoriId_fkey" FOREIGN KEY ("kategoriId") REFERENCES "KategoriProduk"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KategoriToPasar" ADD CONSTRAINT "KategoriToPasar_pasarDesaId_fkey" FOREIGN KEY ("pasarDesaId") REFERENCES "PasarDesa"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
11
prisma/migrations/20250704091225_4_jul_2025/migration.sql
Normal file
11
prisma/migrations/20250704091225_4_jul_2025/migration.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `kategoriProdukId` to the `PasarDesa` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "PasarDesa" ADD COLUMN "kategoriProdukId" TEXT NOT NULL;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PasarDesa" ADD CONSTRAINT "PasarDesa_kategoriProdukId_fkey" FOREIGN KEY ("kategoriProdukId") REFERENCES "KategoriProduk"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,78 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "posisi_organisasi" (
|
||||
"id" VARCHAR(50) NOT NULL,
|
||||
"nama" VARCHAR(100) NOT NULL,
|
||||
"deskripsi" TEXT,
|
||||
"hierarki" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "posisi_organisasi_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "pegawai" (
|
||||
"id" UUID NOT NULL,
|
||||
"namaLengkap" VARCHAR(255) NOT NULL,
|
||||
"gelarAkademik" VARCHAR(100),
|
||||
"imageId" TEXT,
|
||||
"tanggalMasuk" DATE,
|
||||
"email" VARCHAR(255),
|
||||
"telepon" VARCHAR(20),
|
||||
"alamat" TEXT,
|
||||
"posisiId" VARCHAR(50) NOT NULL,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "pegawai_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "hubungan_organisasi" (
|
||||
"id" UUID NOT NULL,
|
||||
"atasanId" UUID NOT NULL,
|
||||
"bawahanId" UUID NOT NULL,
|
||||
"tipe" VARCHAR(50),
|
||||
|
||||
CONSTRAINT "hubungan_organisasi_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "struktur_organisasi" (
|
||||
"id" TEXT NOT NULL,
|
||||
"posisiOrganisasiId" VARCHAR(50) NOT NULL,
|
||||
"pegawaiId" UUID NOT NULL,
|
||||
"hubunganOrganisasiId" UUID NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3),
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "struktur_organisasi_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "pegawai_email_key" ON "pegawai"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "hubungan_organisasi_atasanId_bawahanId_key" ON "hubungan_organisasi"("atasanId", "bawahanId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "pegawai" ADD CONSTRAINT "pegawai_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "pegawai" ADD CONSTRAINT "pegawai_posisiId_fkey" FOREIGN KEY ("posisiId") REFERENCES "posisi_organisasi"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "hubungan_organisasi" ADD CONSTRAINT "hubungan_organisasi_atasanId_fkey" FOREIGN KEY ("atasanId") REFERENCES "pegawai"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "hubungan_organisasi" ADD CONSTRAINT "hubungan_organisasi_bawahanId_fkey" FOREIGN KEY ("bawahanId") REFERENCES "pegawai"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "struktur_organisasi" ADD CONSTRAINT "struktur_organisasi_posisiOrganisasiId_fkey" FOREIGN KEY ("posisiOrganisasiId") REFERENCES "posisi_organisasi"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "struktur_organisasi" ADD CONSTRAINT "struktur_organisasi_pegawaiId_fkey" FOREIGN KEY ("pegawaiId") REFERENCES "pegawai"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "struktur_organisasi" ADD CONSTRAINT "struktur_organisasi_hubunganOrganisasiId_fkey" FOREIGN KEY ("hubunganOrganisasiId") REFERENCES "hubungan_organisasi"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,77 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "GrafikMenganggurBerdasarkanUsia" (
|
||||
"id" TEXT NOT NULL,
|
||||
"usia18_25" TEXT NOT NULL,
|
||||
"usia26_35" TEXT NOT NULL,
|
||||
"usia36_45" TEXT NOT NULL,
|
||||
"usia46_keatas" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "GrafikMenganggurBerdasarkanUsia_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "GrafikMenganggurBerdasarkanPendidikan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"SD" TEXT NOT NULL,
|
||||
"SMP" TEXT NOT NULL,
|
||||
"SMA" TEXT NOT NULL,
|
||||
"D3" TEXT NOT NULL,
|
||||
"S1" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "GrafikMenganggurBerdasarkanPendidikan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "GrafikJumlahPendudukMiskin" (
|
||||
"id" UUID NOT NULL,
|
||||
"year" INTEGER NOT NULL,
|
||||
"totalPoorPopulation" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "GrafikJumlahPendudukMiskin_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SektorUnggulanDesa" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(100) NOT NULL,
|
||||
"description" TEXT,
|
||||
"value" DOUBLE PRECISION,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "SektorUnggulanDesa_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DataDemografiPekerjaan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"pekerjaan" TEXT NOT NULL,
|
||||
"lakiLaki" INTEGER NOT NULL,
|
||||
"perempuan" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "DataDemografiPekerjaan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "GrafikJumlahPendudukMiskin_year_key" ON "GrafikJumlahPendudukMiskin"("year");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "SektorUnggulanDesa_name_key" ON "SektorUnggulanDesa"("name");
|
||||
@@ -0,0 +1,19 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "DetailDataPengangguran" (
|
||||
"id" UUID NOT NULL,
|
||||
"month" VARCHAR(20) NOT NULL,
|
||||
"year" INTEGER NOT NULL,
|
||||
"totalUnemployment" INTEGER NOT NULL,
|
||||
"educatedUnemployment" INTEGER NOT NULL,
|
||||
"uneducatedUnemployment" INTEGER NOT NULL,
|
||||
"percentageChange" DOUBLE PRECISION,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "DetailDataPengangguran_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "DetailDataPengangguran_month_year_key" ON "DetailDataPengangguran"("month", "year");
|
||||
133
prisma/migrations/20250710032516_nico_10_jul_25_1/migration.sql
Normal file
133
prisma/migrations/20250710032516_nico_10_jul_25_1/migration.sql
Normal file
@@ -0,0 +1,133 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "ApbDesa" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tahun" INTEGER NOT NULL,
|
||||
"pendapatanId" TEXT NOT NULL,
|
||||
"belanjaId" TEXT NOT NULL,
|
||||
"pembiayaanId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ApbDesa_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Pendapatan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"value" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "Pendapatan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Belanja" (
|
||||
"id" TEXT NOT NULL,
|
||||
"penyelenggaraan" INTEGER NOT NULL,
|
||||
"pelaksanaanPembangunan" INTEGER NOT NULL,
|
||||
"pembinaanMasyarakat" INTEGER NOT NULL,
|
||||
"pemberdayaanMasyarakat" INTEGER NOT NULL,
|
||||
"penanggulanganBencana" INTEGER NOT NULL,
|
||||
"total" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "Belanja_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Pembiayaan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"silpa" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "Pembiayaan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KlasifikasiBelanja" (
|
||||
"id" TEXT NOT NULL,
|
||||
"jenis" TEXT NOT NULL,
|
||||
"persen" DOUBLE PRECISION NOT NULL,
|
||||
"total" INTEGER NOT NULL,
|
||||
"apbDesaId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "KlasifikasiBelanja_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "RincianBelanja" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"jumlah" INTEGER NOT NULL,
|
||||
"klasifikasiBelanjaId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "RincianBelanja_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KegiatanSubak" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"jumlah" INTEGER NOT NULL,
|
||||
"apbDesaId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "KegiatanSubak_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_ApbDesaToKegiatanSubak" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_ApbDesaToKegiatanSubak_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_BelanjaToKlasifikasiBelanja" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_BelanjaToKlasifikasiBelanja_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_KlasifikasiBelanjaToRincianBelanja" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_KlasifikasiBelanjaToRincianBelanja_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_ApbDesaToKegiatanSubak_B_index" ON "_ApbDesaToKegiatanSubak"("B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_BelanjaToKlasifikasiBelanja_B_index" ON "_BelanjaToKlasifikasiBelanja"("B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_KlasifikasiBelanjaToRincianBelanja_B_index" ON "_KlasifikasiBelanjaToRincianBelanja"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ApbDesa" ADD CONSTRAINT "ApbDesa_pendapatanId_fkey" FOREIGN KEY ("pendapatanId") REFERENCES "Pendapatan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ApbDesa" ADD CONSTRAINT "ApbDesa_belanjaId_fkey" FOREIGN KEY ("belanjaId") REFERENCES "Belanja"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ApbDesa" ADD CONSTRAINT "ApbDesa_pembiayaanId_fkey" FOREIGN KEY ("pembiayaanId") REFERENCES "Pembiayaan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ApbDesaToKegiatanSubak" ADD CONSTRAINT "_ApbDesaToKegiatanSubak_A_fkey" FOREIGN KEY ("A") REFERENCES "ApbDesa"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ApbDesaToKegiatanSubak" ADD CONSTRAINT "_ApbDesaToKegiatanSubak_B_fkey" FOREIGN KEY ("B") REFERENCES "KegiatanSubak"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_BelanjaToKlasifikasiBelanja" ADD CONSTRAINT "_BelanjaToKlasifikasiBelanja_A_fkey" FOREIGN KEY ("A") REFERENCES "Belanja"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_BelanjaToKlasifikasiBelanja" ADD CONSTRAINT "_BelanjaToKlasifikasiBelanja_B_fkey" FOREIGN KEY ("B") REFERENCES "KlasifikasiBelanja"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_KlasifikasiBelanjaToRincianBelanja" ADD CONSTRAINT "_KlasifikasiBelanjaToRincianBelanja_A_fkey" FOREIGN KEY ("A") REFERENCES "KlasifikasiBelanja"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_KlasifikasiBelanjaToRincianBelanja" ADD CONSTRAINT "_KlasifikasiBelanjaToRincianBelanja_B_fkey" FOREIGN KEY ("B") REFERENCES "RincianBelanja"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `pelaksanaanPembangunan` on the `Belanja` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `pemberdayaanMasyarakat` on the `Belanja` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `pembinaanMasyarakat` on the `Belanja` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `penanggulanganBencana` on the `Belanja` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `penyelenggaraan` on the `Belanja` table. All the data in the column will be lost.
|
||||
- Added the required column `name` to the `Belanja` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `updatedAt` to the `Belanja` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `value` to the `Belanja` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `total` to the `Pendapatan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `updatedAt` to the `Pendapatan` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Belanja" DROP COLUMN "pelaksanaanPembangunan",
|
||||
DROP COLUMN "pemberdayaanMasyarakat",
|
||||
DROP COLUMN "pembinaanMasyarakat",
|
||||
DROP COLUMN "penanggulanganBencana",
|
||||
DROP COLUMN "penyelenggaraan",
|
||||
ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
ADD COLUMN "name" TEXT NOT NULL,
|
||||
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
ADD COLUMN "value" INTEGER NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Pendapatan" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
ADD COLUMN "total" INTEGER NOT NULL,
|
||||
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `total` on the `Belanja` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `total` on the `Pendapatan` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Belanja" DROP COLUMN "total";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Pendapatan" DROP COLUMN "total";
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `silpa` on the `Pembiayaan` table. All the data in the column will be lost.
|
||||
- Added the required column `name` to the `Pembiayaan` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `value` to the `Pembiayaan` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Pembiayaan" DROP COLUMN "silpa",
|
||||
ADD COLUMN "name" TEXT NOT NULL,
|
||||
ADD COLUMN "value" INTEGER NOT NULL;
|
||||
245
prisma/migrations/20250715072239_nico_15_jul_25_1/migration.sql
Normal file
245
prisma/migrations/20250715072239_nico_15_jul_25_1/migration.sql
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `belanjaId` on the `ApbDesa` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `pembiayaanId` on the `ApbDesa` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `pendapatanId` on the `ApbDesa` table. All the data in the column will be lost.
|
||||
- You are about to drop the `KegiatanSubak` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `KlasifikasiBelanja` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `RincianBelanja` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_ApbDesaToKegiatanSubak` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_BelanjaToKlasifikasiBelanja` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_KlasifikasiBelanjaToRincianBelanja` table. If the table is not empty, all the data it contains will be lost.
|
||||
- Changed the type of `tanggal` on the `DaftarInformasiPublik` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required.
|
||||
- Added the required column `updatedAt` to the `Pembiayaan` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ApbDesa" DROP CONSTRAINT "ApbDesa_belanjaId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ApbDesa" DROP CONSTRAINT "ApbDesa_pembiayaanId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ApbDesa" DROP CONSTRAINT "ApbDesa_pendapatanId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_ApbDesaToKegiatanSubak" DROP CONSTRAINT "_ApbDesaToKegiatanSubak_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_ApbDesaToKegiatanSubak" DROP CONSTRAINT "_ApbDesaToKegiatanSubak_B_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_BelanjaToKlasifikasiBelanja" DROP CONSTRAINT "_BelanjaToKlasifikasiBelanja_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_BelanjaToKlasifikasiBelanja" DROP CONSTRAINT "_BelanjaToKlasifikasiBelanja_B_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_KlasifikasiBelanjaToRincianBelanja" DROP CONSTRAINT "_KlasifikasiBelanjaToRincianBelanja_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_KlasifikasiBelanjaToRincianBelanja" DROP CONSTRAINT "_KlasifikasiBelanjaToRincianBelanja_B_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "ApbDesa" DROP COLUMN "belanjaId",
|
||||
DROP COLUMN "pembiayaanId",
|
||||
DROP COLUMN "pendapatanId",
|
||||
ADD COLUMN "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "DaftarInformasiPublik" DROP COLUMN "tanggal",
|
||||
ADD COLUMN "tanggal" DATE NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Pembiayaan" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "KegiatanSubak";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "KlasifikasiBelanja";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "RincianBelanja";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_ApbDesaToKegiatanSubak";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_BelanjaToKlasifikasiBelanja";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "_KlasifikasiBelanjaToRincianBelanja";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DesaDigital" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"imageId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "DesaDigital_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ProgramKreatif" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"icon" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "ProgramKreatif_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KolaborasiInovasi" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"tahun" INTEGER NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"kolaborator" TEXT NOT NULL,
|
||||
"imageId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "KolaborasiInovasi_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "InfoTekno" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"imageId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "InfoTekno_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AjukanIdeInovatif" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"alamat" TEXT NOT NULL,
|
||||
"namaIde" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"masalah" TEXT NOT NULL,
|
||||
"benefit" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "AjukanIdeInovatif_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AdministrasiOnline" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"alamat" TEXT NOT NULL,
|
||||
"nomorTelepon" TEXT NOT NULL,
|
||||
"jenisLayananId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "AdministrasiOnline_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "JenisLayanan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "JenisLayanan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_ApbDesaPembiayaan" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_ApbDesaPembiayaan_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_ApbDesaBelanja" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_ApbDesaBelanja_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_ApbDesaPendapatan" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_ApbDesaPendapatan_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_ApbDesaPembiayaan_B_index" ON "_ApbDesaPembiayaan"("B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_ApbDesaBelanja_B_index" ON "_ApbDesaBelanja"("B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_ApbDesaPendapatan_B_index" ON "_ApbDesaPendapatan"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DesaDigital" ADD CONSTRAINT "DesaDigital_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KolaborasiInovasi" ADD CONSTRAINT "KolaborasiInovasi_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "InfoTekno" ADD CONSTRAINT "InfoTekno_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "AdministrasiOnline" ADD CONSTRAINT "AdministrasiOnline_jenisLayananId_fkey" FOREIGN KEY ("jenisLayananId") REFERENCES "JenisLayanan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ApbDesaPembiayaan" ADD CONSTRAINT "_ApbDesaPembiayaan_A_fkey" FOREIGN KEY ("A") REFERENCES "ApbDesa"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ApbDesaPembiayaan" ADD CONSTRAINT "_ApbDesaPembiayaan_B_fkey" FOREIGN KEY ("B") REFERENCES "Pembiayaan"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ApbDesaBelanja" ADD CONSTRAINT "_ApbDesaBelanja_A_fkey" FOREIGN KEY ("A") REFERENCES "ApbDesa"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ApbDesaBelanja" ADD CONSTRAINT "_ApbDesaBelanja_B_fkey" FOREIGN KEY ("B") REFERENCES "Belanja"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ApbDesaPendapatan" ADD CONSTRAINT "_ApbDesaPendapatan_A_fkey" FOREIGN KEY ("A") REFERENCES "ApbDesa"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ApbDesaPendapatan" ADD CONSTRAINT "_ApbDesaPendapatan_B_fkey" FOREIGN KEY ("B") REFERENCES "Pendapatan"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,67 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "PengaduanMasyarakat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"nomorTelepon" TEXT NOT NULL,
|
||||
"nik" TEXT NOT NULL,
|
||||
"judulPengaduan" TEXT NOT NULL,
|
||||
"lokasiKejadian" TEXT NOT NULL,
|
||||
"imageId" TEXT NOT NULL,
|
||||
"deskripsiPengaduan" TEXT NOT NULL,
|
||||
"jenisPengaduanId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "PengaduanMasyarakat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "JenisPengaduan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "JenisPengaduan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PengelolaanSampah" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"icon" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "PengelolaanSampah_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KeteranganBankSampahTerdekat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"alamat" TEXT NOT NULL,
|
||||
"namaTempatMaps" TEXT NOT NULL,
|
||||
"linkPetunjukArah" TEXT NOT NULL,
|
||||
"lat" DOUBLE PRECISION NOT NULL,
|
||||
"lng" DOUBLE PRECISION NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "KeteranganBankSampahTerdekat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PengaduanMasyarakat" ADD CONSTRAINT "PengaduanMasyarakat_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PengaduanMasyarakat" ADD CONSTRAINT "PengaduanMasyarakat_jenisPengaduanId_fkey" FOREIGN KEY ("jenisPengaduanId") REFERENCES "JenisPengaduan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
144
prisma/migrations/20250721095104_nico_21_jul_25/migration.sql
Normal file
144
prisma/migrations/20250721095104_nico_21_jul_25/migration.sql
Normal file
@@ -0,0 +1,144 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "ProgramPenghijauan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"icon" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "ProgramPenghijauan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DataLingkunganDesa" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"jumlah" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"icon" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "DataLingkunganDesa_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KegiatanDesa" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsiSingkat" TEXT NOT NULL,
|
||||
"deskripsiLengkap" TEXT NOT NULL,
|
||||
"tanggal" TIMESTAMP(3) NOT NULL,
|
||||
"lokasi" TEXT NOT NULL,
|
||||
"partisipan" INTEGER NOT NULL,
|
||||
"imageId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"kategoriKegiatanId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "KegiatanDesa_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KategoriKegiatan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nama" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "KategoriKegiatan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TujuanEdukasiLingkungan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "TujuanEdukasiLingkungan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "MateriEdukasiLingkungan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "MateriEdukasiLingkungan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ContohEdukasiLingkungan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "ContohEdukasiLingkungan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FilosofiTriHita" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "FilosofiTriHita_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BentukKonservasiBerdasarkanAdat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "BentukKonservasiBerdasarkanAdat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "NilaiKonservasiAdat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"judul" TEXT NOT NULL,
|
||||
"deskripsi" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "NilaiKonservasiAdat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KegiatanDesa" ADD CONSTRAINT "KegiatanDesa_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "KegiatanDesa" ADD CONSTRAINT "KegiatanDesa_kategoriKegiatanId_fkey" FOREIGN KEY ("kategoriKegiatanId") REFERENCES "KategoriKegiatan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,56 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "PejabatDesa" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"position" TEXT NOT NULL,
|
||||
"imageId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "PejabatDesa_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ProgramInovasi" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"description" TEXT,
|
||||
"imageId" TEXT,
|
||||
"link" VARCHAR(255),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "ProgramInovasi_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "MediaSosial" (
|
||||
"id" TEXT NOT NULL,
|
||||
"imageId" TEXT NOT NULL,
|
||||
"iconUrl" VARCHAR(255),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3),
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "MediaSosial_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "PejabatDesa_name_key" ON "PejabatDesa"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ProgramInovasi_name_key" ON "ProgramInovasi"("name");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PejabatDesa" ADD CONSTRAINT "PejabatDesa_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ProgramInovasi" ADD CONSTRAINT "ProgramInovasi_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "MediaSosial" ADD CONSTRAINT "MediaSosial_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
1378
prisma/schema.prisma
1378
prisma/schema.prisma
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 275 KiB |
391
prisma/seed.ts
391
prisma/seed.ts
@@ -17,6 +17,27 @@ import visiMisiDesa from "./data/desa/profile/visi_misi_desa.json";
|
||||
import lambangDesa from "./data/desa/profile/lambang_desa.json";
|
||||
import maskotDesa from "./data/desa/profile/maskot_desa.json";
|
||||
import profilPerbekel from "./data/desa/profile/profil_perbekel.json";
|
||||
import kategoriProduk from "./data/ekonomi/pasar-desa/kategori-produk.json";
|
||||
import hubunganOrganisasi from "./data/ekonomi/struktur-organisasi/hubungan-organisasi.json";
|
||||
import posisiOrganisasi from "./data/ekonomi/struktur-organisasi/posisi-organisasi.json";
|
||||
import pegawai from "./data/ekonomi/struktur-organisasi/pegawai.json";
|
||||
import detailDataPengangguran from './data/ekonomi/jumlah-pengangguran/detail-data-pengangguran.json';
|
||||
import tujuanEdukasiLingkungan from './data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json';
|
||||
import materiEdukasiLingkungan from './data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json';
|
||||
import 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 bentukKonservasiBerdasarkanAdat from './data/lingkungan/konservasi-adat-bali/bentuk-konservasi.json';
|
||||
import filosofiTriHita from './data/lingkungan/konservasi-adat-bali/filosofi-tri-hita.json';
|
||||
import profilePejabatDesa from './data/landing-page/profile.json';
|
||||
import tujuanProgram from './data/pendidikan/program-pendidikan-anak/tujuan-program.json';
|
||||
import tujuanProgram2 from './data/pendidikan/pendidikan-non-formal/tujuan-program2.json';
|
||||
import programUnggulan from './data/pendidikan/program-pendidikan-anak/program-unggulan.json';
|
||||
import tujuanBimbinganBelajarDesa from './data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json';
|
||||
import lokasiJadwalBimbinganBelajarDesa from './data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json';
|
||||
import fasilitasBimbinganBelajarDesa from './data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json';
|
||||
import tempatKegiatan from './data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json';
|
||||
import jenisProgramYangDiselenggarakan from './data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json';
|
||||
|
||||
|
||||
(async () => {
|
||||
for (const l of layanan) {
|
||||
@@ -340,6 +361,376 @@ import profilPerbekel from "./data/desa/profile/profil_perbekel.json";
|
||||
});
|
||||
}
|
||||
console.log("dasar hukum PPID success ...");
|
||||
|
||||
for (const k of kategoriProduk) {
|
||||
await prisma.kategoriProduk.upsert({
|
||||
where: {
|
||||
id: k.id,
|
||||
},
|
||||
update: {
|
||||
nama: k.nama,
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
nama: k.nama,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("kategori produk success ...");
|
||||
|
||||
|
||||
for (const p of posisiOrganisasi) {
|
||||
await prisma.posisiOrganisasi.upsert({
|
||||
where: {
|
||||
id: p.id,
|
||||
},
|
||||
update: {
|
||||
nama: p.nama,
|
||||
deskripsi: p.deskripsi,
|
||||
hierarki: p.hierarki,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
nama: p.nama,
|
||||
deskripsi: p.deskripsi,
|
||||
hierarki: p.hierarki,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("posisi organisasi success ...");
|
||||
|
||||
for (const p of pegawai) {
|
||||
await prisma.pegawai.upsert({
|
||||
where: {
|
||||
id: p.id,
|
||||
},
|
||||
update: {
|
||||
namaLengkap: p.namaLengkap,
|
||||
gelarAkademik: p.gelarAkademik,
|
||||
tanggalMasuk: new Date(p.tanggalMasuk),
|
||||
email: p.email,
|
||||
telepon: p.telepon,
|
||||
alamat: p.alamat,
|
||||
posisiId: p.posisiId,
|
||||
isActive: p.isActive,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
namaLengkap: p.namaLengkap,
|
||||
gelarAkademik: p.gelarAkademik,
|
||||
tanggalMasuk: new Date(p.tanggalMasuk),
|
||||
email: p.email,
|
||||
telepon: p.telepon,
|
||||
alamat: p.alamat,
|
||||
posisiId: p.posisiId,
|
||||
isActive: p.isActive,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("pegawai success ...");
|
||||
|
||||
for (const p of hubunganOrganisasi) {
|
||||
await prisma.hubunganOrganisasi.upsert({
|
||||
where: {
|
||||
atasanId_bawahanId: {
|
||||
atasanId: p.atasanId,
|
||||
bawahanId: p.bawahanId,
|
||||
},
|
||||
},
|
||||
update: {
|
||||
tipe: p.tipe,
|
||||
},
|
||||
create: {
|
||||
atasanId: p.atasanId,
|
||||
bawahanId: p.bawahanId,
|
||||
tipe: p.tipe,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("hubungan organisasi success ...");
|
||||
|
||||
for (const d of detailDataPengangguran) {
|
||||
await prisma.detailDataPengangguran.upsert({
|
||||
where: {
|
||||
month_year: { month: d.month, year: d.year },
|
||||
},
|
||||
update: {
|
||||
totalUnemployment: d.totalUnemployment,
|
||||
educatedUnemployment: d.educatedUnemployment,
|
||||
uneducatedUnemployment: d.uneducatedUnemployment,
|
||||
percentageChange: d.percentageChange,
|
||||
},
|
||||
create: {
|
||||
month: d.month,
|
||||
year: d.year,
|
||||
totalUnemployment: d.totalUnemployment,
|
||||
educatedUnemployment: d.educatedUnemployment,
|
||||
uneducatedUnemployment: d.uneducatedUnemployment,
|
||||
percentageChange: d.percentageChange,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("📊 detailDataPengangguran success ...");
|
||||
|
||||
for (const e of tujuanEdukasiLingkungan) {
|
||||
await prisma.tujuanEdukasiLingkungan.upsert({
|
||||
where: {
|
||||
id: e.id,
|
||||
},
|
||||
update: {
|
||||
judul: e.judul,
|
||||
deskripsi: e.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: e.id,
|
||||
judul: e.judul,
|
||||
deskripsi: e.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("tujuan edukasi lingkungan success ...");
|
||||
|
||||
for (const m of materiEdukasiLingkungan) {
|
||||
await prisma.materiEdukasiLingkungan.upsert({
|
||||
where: {
|
||||
id: m.id,
|
||||
},
|
||||
update: {
|
||||
judul: m.judul,
|
||||
deskripsi: m.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: m.id,
|
||||
judul: m.judul,
|
||||
deskripsi: m.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("materi edukasi lingkungan success ...");
|
||||
|
||||
for (const c of contohEdukasiLingkungan) {
|
||||
await prisma.contohEdukasiLingkungan.upsert({
|
||||
where: {
|
||||
id: c.id,
|
||||
},
|
||||
update: {
|
||||
judul: c.judul,
|
||||
deskripsi: c.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
judul: c.judul,
|
||||
deskripsi: c.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("contoh edukasi lingkungan success ...");
|
||||
|
||||
for (const f of filosofiTriHita) {
|
||||
await prisma.filosofiTriHita.upsert({
|
||||
where: {
|
||||
id: f.id,
|
||||
},
|
||||
update: {
|
||||
judul: f.judul,
|
||||
deskripsi: f.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: f.id,
|
||||
judul: f.judul,
|
||||
deskripsi: f.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("filosofi tri hita success ...");
|
||||
|
||||
for (const b of bentukKonservasiBerdasarkanAdat) {
|
||||
await prisma.bentukKonservasiBerdasarkanAdat.upsert({
|
||||
where: {
|
||||
id: b.id,
|
||||
},
|
||||
update: {
|
||||
judul: b.judul,
|
||||
deskripsi: b.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: b.id,
|
||||
judul: b.judul,
|
||||
deskripsi: b.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("bentuk konservasi berdasarkan adat success ...");
|
||||
|
||||
|
||||
for (const n of nilaiKonservasiAdat) {
|
||||
await prisma.nilaiKonservasiAdat.upsert({
|
||||
where: {
|
||||
id: n.id,
|
||||
},
|
||||
update: {
|
||||
judul: n.judul,
|
||||
deskripsi: n.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: n.id,
|
||||
judul: n.judul,
|
||||
deskripsi: n.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("nilai konservasi adat success ...");
|
||||
|
||||
for (const p of profilePejabatDesa) {
|
||||
await prisma.pejabatDesa.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
position: p.position,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
position: p.position,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ profilePejabatDesa seeded without imageId (editable later via UI)");
|
||||
|
||||
for (const t of tujuanProgram) {
|
||||
await prisma.tujuanProgram.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ tujuan program seeded (editable later via UI)");
|
||||
|
||||
for (const t of programUnggulan) {
|
||||
await prisma.programUnggulan.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ program unggulan seeded (editable later via UI)");
|
||||
|
||||
for (const t of tujuanBimbinganBelajarDesa) {
|
||||
await prisma.tujuanBimbinganBelajarDesa.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ tujuan bimbingan belajar desa seeded (editable later via UI)");
|
||||
|
||||
for (const t of lokasiJadwalBimbinganBelajarDesa) {
|
||||
await prisma.lokasiJadwalBimbinganBelajarDesa.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ lokasi jadwal bimbingan belajar desa seeded (editable later via UI)");
|
||||
|
||||
for (const t of fasilitasBimbinganBelajarDesa) {
|
||||
await prisma.fasilitasBimbinganBelajarDesa.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ fasilitas bimbingan belajar desa seeded (editable later via UI)");
|
||||
|
||||
for (const t of tujuanProgram2) {
|
||||
await prisma.tujuanPendidikanNonFormal.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ fasilitas bimbingan belajar desa seeded (editable later via UI)");
|
||||
|
||||
for (const t of tempatKegiatan) {
|
||||
await prisma.tempatKegiatan.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ fasilitas bimbingan belajar desa seeded (editable later via UI)");
|
||||
|
||||
for (const t of jenisProgramYangDiselenggarakan) {
|
||||
await prisma.jenisProgramYangDiselenggarakan.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ fasilitas bimbingan belajar desa seeded (editable later via UI)");
|
||||
|
||||
})()
|
||||
.then(() => prisma.$disconnect())
|
||||
.catch((e) => {
|
||||
|
||||
BIN
public/assets/images/sosmed/telephone-call.png
Normal file
BIN
public/assets/images/sosmed/telephone-call.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
public/pa-desa.png
Normal file
BIN
public/pa-desa.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
@@ -1,22 +1,37 @@
|
||||
import React from 'react';
|
||||
import { Grid, GridCol, Paper, TextInput, Title } from '@mantine/core';
|
||||
import { IconSearch } from '@tabler/icons-react'; // Sesuaikan jika kamu pakai icon lain
|
||||
import { IconSearch } from '@tabler/icons-react';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
type HeaderSearchProps = {
|
||||
title: string;
|
||||
placeholder?: string;
|
||||
searchIcon?: React.ReactNode;
|
||||
value?: string;
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
};
|
||||
|
||||
const HeaderSearch = ({ title = "", placeholder = "pencarian", searchIcon = <IconSearch size={20} /> }: { title: string, placeholder?: string, searchIcon?: React.ReactNode }) => {
|
||||
const HeaderSearch = ({
|
||||
title = "",
|
||||
placeholder = "pencarian",
|
||||
searchIcon = <IconSearch size={20} />,
|
||||
value,
|
||||
onChange,
|
||||
}: HeaderSearchProps) => {
|
||||
return (
|
||||
<Grid>
|
||||
<Grid mb={10}>
|
||||
<GridCol span={{ base: 12, md: 9 }}>
|
||||
<Title order={3}>{title}</Title>
|
||||
</GridCol>
|
||||
<GridCol span={{ base: 12, md: 3 }}>
|
||||
<Paper radius={"lg"} bg={colors['white-1']}>
|
||||
<Paper radius="lg" bg={colors['white-1']}>
|
||||
<TextInput
|
||||
radius="lg"
|
||||
placeholder={placeholder}
|
||||
leftSection={searchIcon}
|
||||
w="100%"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</Paper>
|
||||
</GridCol>
|
||||
@@ -24,4 +39,4 @@ const HeaderSearch = ({ title = "", placeholder = "pencarian", searchIcon = <Ico
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderSearch;
|
||||
export default HeaderSearch;
|
||||
|
||||
@@ -5,31 +5,50 @@ import { IconCircleDashedPlus, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import React from 'react';
|
||||
|
||||
const JudulListTab = ({ title = "", href = "#", placeholder = "pencarian", searchIcon = <IconSearch size={20} /> }) => {
|
||||
type JudulListTabProps = {
|
||||
title: string;
|
||||
href: string;
|
||||
placeholder: string;
|
||||
searchIcon: React.ReactNode;
|
||||
value?: string;
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const JudulListTab = ({
|
||||
title = "",
|
||||
href = "#",
|
||||
placeholder = "pencarian",
|
||||
searchIcon = <IconSearch size={20} />,
|
||||
value,
|
||||
onChange
|
||||
}: JudulListTabProps) => {
|
||||
const router = useRouter();
|
||||
|
||||
const handleNavigate = () => {
|
||||
router.push(href);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Grid mb={10}>
|
||||
<GridCol span={{ base: 12, md: 8 }}>
|
||||
<Text fz={{base: "md", md: "xl"}} fw={"bold"}>{title}</Text>
|
||||
<Text fz={{ base: "md", md: "xl" }} fw={"bold"}>{title}</Text>
|
||||
</GridCol>
|
||||
<GridCol span={{ base: 9, md: 3}} ta="right">
|
||||
<GridCol span={{ base: 9, md: 3 }} ta="right">
|
||||
<Paper radius={"lg"} bg={colors['white-1']}>
|
||||
<TextInput
|
||||
radius="lg"
|
||||
placeholder={placeholder}
|
||||
leftSection={searchIcon}
|
||||
w="100%"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</Paper>
|
||||
</GridCol>
|
||||
<GridCol span={{ base: 3, md: 1}} ta="right">
|
||||
<GridCol span={{ base: 3, md: 1 }} ta="right">
|
||||
<Button onClick={handleNavigate} bg={colors['blue-button']}>
|
||||
<IconCircleDashedPlus size={25} />
|
||||
</Button>
|
||||
59
src/app/admin/(dashboard)/_com/leafletMapCreate.tsx
Normal file
59
src/app/admin/(dashboard)/_com/leafletMapCreate.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client';
|
||||
|
||||
import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet';
|
||||
import { useEffect, useState } from 'react';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import L, { LeafletMouseEvent } from 'leaflet';
|
||||
|
||||
type Props = {
|
||||
defaultCenter: { lat: number; lng: number };
|
||||
onSelect?: (pos: { lat: number; lng: number }) => void;
|
||||
readOnly?: boolean;
|
||||
};
|
||||
|
||||
export default function LeafletMap({ defaultCenter, onSelect, readOnly = false }: Props) {
|
||||
const [markerPos, setMarkerPos] = useState(defaultCenter);
|
||||
|
||||
useEffect(() => {
|
||||
// Aman di sini, karena ini hanya jalan di client
|
||||
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',
|
||||
});
|
||||
}, []);
|
||||
|
||||
function LocationMarker() {
|
||||
useMapEvents({
|
||||
click(e: LeafletMouseEvent) {
|
||||
if (readOnly) return;
|
||||
|
||||
const { lat, lng } = e.latlng;
|
||||
setMarkerPos({ lat, lng });
|
||||
onSelect?.({ lat, lng });
|
||||
},
|
||||
});
|
||||
|
||||
return <Marker position={markerPos} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<MapContainer
|
||||
center={defaultCenter}
|
||||
zoom={16}
|
||||
scrollWheelZoom
|
||||
style={{ height: '100%', width: '100%', zIndex: 0 }}
|
||||
>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://osm.org/copyright">OpenStreetMap</a>'
|
||||
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
|
||||
/>
|
||||
<LocationMarker />
|
||||
</MapContainer>
|
||||
);
|
||||
}
|
||||
62
src/app/admin/(dashboard)/_com/leafletMapEdit.tsx
Normal file
62
src/app/admin/(dashboard)/_com/leafletMapEdit.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client';
|
||||
|
||||
import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet';
|
||||
import { useState, useEffect } from 'react';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import L, { LeafletMouseEvent } from 'leaflet';
|
||||
|
||||
type Props = {
|
||||
initialPosition: { lat: number; lng: number };
|
||||
onChange: (pos: { lat: number; lng: number }) => void;
|
||||
};
|
||||
|
||||
export default function LeafletMapEdit({ initialPosition, onChange }: Props) {
|
||||
const [markerPos, setMarkerPos] = useState(initialPosition);
|
||||
|
||||
// ✅ Pastikan icon config cuma jalan di client
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
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',
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setMarkerPos(initialPosition);
|
||||
}, [initialPosition]);
|
||||
|
||||
function LocationMarker() {
|
||||
useMapEvents({
|
||||
click(e: LeafletMouseEvent) {
|
||||
const { lat, lng } = e.latlng;
|
||||
setMarkerPos({ lat, lng });
|
||||
onChange({ lat, lng });
|
||||
},
|
||||
});
|
||||
|
||||
return <Marker position={markerPos} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<MapContainer
|
||||
center={markerPos}
|
||||
zoom={16}
|
||||
scrollWheelZoom
|
||||
style={{ height: '100%', width: '100%', zIndex: 0 }}
|
||||
>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://osm.org/copyright">OpenStreetMap</a>'
|
||||
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
|
||||
/>
|
||||
<LocationMarker />
|
||||
</MapContainer>
|
||||
);
|
||||
}
|
||||
98
src/app/admin/(dashboard)/_com/selectIcon.tsx
Normal file
98
src/app/admin/(dashboard)/_com/selectIcon.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
|
||||
import { Box, rem, Select } from '@mantine/core';
|
||||
import {
|
||||
IconChartLine,
|
||||
IconChristmasTreeFilled,
|
||||
IconClipboardTextFilled,
|
||||
IconDroplet,
|
||||
IconHome,
|
||||
IconHomeEco,
|
||||
IconLeaf,
|
||||
IconRecycle,
|
||||
IconScale,
|
||||
IconShieldFilled,
|
||||
IconTent,
|
||||
IconTrashFilled,
|
||||
IconTree,
|
||||
IconTrendingUp,
|
||||
IconTrophy,
|
||||
IconTruckFilled,
|
||||
} from '@tabler/icons-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const iconMap = {
|
||||
ekowisata: { label: 'Ekowisata', icon: IconLeaf },
|
||||
kompetisi: { label: 'Kompetisi', icon: IconTrophy },
|
||||
wisata: { label: 'Wisata', icon: IconTent },
|
||||
ekonomi: { label: 'Ekonomi', icon: IconChartLine },
|
||||
sampah: { label: 'Sampah', icon: IconRecycle },
|
||||
truck: { label: 'Truck', icon: IconTruckFilled },
|
||||
scale: { label: 'Scale', icon: IconScale },
|
||||
clipboard: { label: 'Clipboard', icon: IconClipboardTextFilled },
|
||||
trash: { label: 'Trash', icon: IconTrashFilled },
|
||||
lingkunganSehat: {label: 'Lingkungan Sehat', icon: IconHomeEco},
|
||||
sumberOksigen: {label: 'Sumber Oksigen', icon: IconChristmasTreeFilled},
|
||||
ekonomiBerkelanjutan: {label: 'Ekonomi Berkelanjutan', icon: IconTrendingUp},
|
||||
mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled},
|
||||
rumah: {label: 'Rumah', icon: IconHome},
|
||||
pohon: {label: 'Pohon', icon: IconTree},
|
||||
air: {label: 'Air', icon: IconDroplet}
|
||||
|
||||
};
|
||||
|
||||
type IconKey = keyof typeof iconMap;
|
||||
|
||||
const iconList = Object.entries(iconMap).map(([value, data]) => ({
|
||||
value,
|
||||
label: data.label,
|
||||
}));
|
||||
|
||||
export default function SelectIconProgram(
|
||||
{ onChange }: { onChange: (value: IconKey) => void }) {
|
||||
const [selectedIcon, setSelectedIcon] = useState<IconKey>('ekowisata');
|
||||
const IconComponent = iconMap[selectedIcon]?.icon || null;
|
||||
|
||||
// Push default icon ke state saat render awal
|
||||
useEffect(() => {
|
||||
onChange(selectedIcon);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box maw={300}>
|
||||
<Select
|
||||
placeholder="Pilih ikon"
|
||||
value={selectedIcon}
|
||||
onChange={(value) => {
|
||||
if (value) {
|
||||
setSelectedIcon(value as IconKey);
|
||||
onChange(value as IconKey);
|
||||
}
|
||||
}}
|
||||
data={iconList}
|
||||
leftSection={
|
||||
IconComponent && (
|
||||
<Box>
|
||||
<IconComponent size={24} stroke={1.5} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
withCheckIcon={false}
|
||||
searchable={false}
|
||||
rightSectionWidth={0}
|
||||
styles={{
|
||||
input: {
|
||||
textAlign: 'left',
|
||||
fontSize: rem(16),
|
||||
paddingLeft: 40,
|
||||
},
|
||||
section: {
|
||||
left: 10,
|
||||
right: 'auto',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
92
src/app/admin/(dashboard)/_com/selectIconEdit.tsx
Normal file
92
src/app/admin/(dashboard)/_com/selectIconEdit.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
'use client'
|
||||
|
||||
import { Box, rem, Select } from '@mantine/core';
|
||||
import {
|
||||
IconChartLine,
|
||||
IconChristmasTreeFilled,
|
||||
IconClipboardTextFilled,
|
||||
IconDroplet,
|
||||
IconHome,
|
||||
IconHomeEco,
|
||||
IconLeaf,
|
||||
IconRecycle,
|
||||
IconScale,
|
||||
IconShieldFilled,
|
||||
IconTent,
|
||||
IconTrashFilled,
|
||||
IconTree,
|
||||
IconTrendingUp,
|
||||
IconTrophy,
|
||||
IconTruckFilled,
|
||||
} from '@tabler/icons-react';
|
||||
|
||||
const iconMap = {
|
||||
ekowisata: { label: 'Ekowisata', icon: IconLeaf },
|
||||
kompetisi: { label: 'Kompetisi', icon: IconTrophy },
|
||||
wisata: { label: 'Wisata', icon: IconTent },
|
||||
ekonomi: { label: 'Ekonomi', icon: IconChartLine },
|
||||
sampah: { label: 'Sampah', icon: IconRecycle },
|
||||
truck: { label: 'Truck', icon: IconTruckFilled },
|
||||
scale: { label: 'Scale', icon: IconScale },
|
||||
clipboard: { label: 'Clipboard', icon: IconClipboardTextFilled },
|
||||
trash: { label: 'Trash', icon: IconTrashFilled },
|
||||
lingkunganSehat: {label: 'Lingkungan Sehat', icon: IconHomeEco},
|
||||
sumberOksigen: {label: 'Sumber Oksigen', icon: IconChristmasTreeFilled},
|
||||
ekonomiBerkelanjutan: {label: 'Ekonomi Berkelanjutan', icon: IconTrendingUp},
|
||||
mencegahBencana: {label: 'Mencegah Bencana', icon: IconShieldFilled},
|
||||
rumah: {label: 'Rumah', icon: IconHome},
|
||||
pohon: {label: 'Pohon', icon: IconTree},
|
||||
air: {label: 'Air', icon: IconDroplet}
|
||||
};
|
||||
|
||||
type IconKey = keyof typeof iconMap;
|
||||
|
||||
const iconList = Object.entries(iconMap).map(([value, data]) => ({
|
||||
value,
|
||||
label: data.label,
|
||||
}));
|
||||
|
||||
export default function SelectIconProgramEdit({
|
||||
onChange,
|
||||
value,
|
||||
}: {
|
||||
onChange: (value: IconKey) => void;
|
||||
value: IconKey;
|
||||
}) {
|
||||
const IconComponent = iconMap[value]?.icon || null;
|
||||
|
||||
return (
|
||||
<Box maw={300}>
|
||||
<Select
|
||||
placeholder="Pilih ikon"
|
||||
value={value}
|
||||
onChange={(value) => {
|
||||
if (value) onChange(value as IconKey);
|
||||
}}
|
||||
data={iconList}
|
||||
leftSection={
|
||||
IconComponent && (
|
||||
<Box>
|
||||
<IconComponent size={24} stroke={1.5} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
withCheckIcon={false}
|
||||
searchable={false}
|
||||
rightSectionWidth={0}
|
||||
styles={{
|
||||
input: {
|
||||
textAlign: 'left',
|
||||
fontSize: rem(16),
|
||||
paddingLeft: 40,
|
||||
},
|
||||
section: {
|
||||
left: 10,
|
||||
right: 'auto',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,13 +80,33 @@ const berita = proxy({
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.desa.berita["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
berita.findMany.data = (res.data?.data ) ?? [];
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
|
||||
async load(page = 1, limit = 10) {
|
||||
berita.findMany.loading = true;
|
||||
berita.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.desa.berita["find-many"].get({
|
||||
query: {
|
||||
page,
|
||||
limit,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
berita.findMany.data = res.data.data ?? [];
|
||||
berita.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch berita paginated:", err);
|
||||
} finally {
|
||||
berita.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
findUnique: {
|
||||
data: null as
|
||||
| Prisma.BeritaGetPayload<{
|
||||
@@ -243,6 +263,59 @@ const berita = proxy({
|
||||
berita.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findFirst: {
|
||||
data: null as Prisma.BeritaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategoriBerita: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await ApiFetch.api.desa.berita["find-first"].get();
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
// Add type assertion to ensure type safety
|
||||
berita.findFirst.data = res.data.data as Prisma.BeritaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategoriBerita: true;
|
||||
};
|
||||
}> | null;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch berita terbaru:", err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findRecent: {
|
||||
data: [] as Prisma.BeritaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategoriBerita: true;
|
||||
};
|
||||
}>[],
|
||||
loading: false,
|
||||
|
||||
async load() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.desa.berita["find-recent"].get();
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
this.data = res.data.data ?? [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal fetch berita recent:", error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -68,11 +68,11 @@ const pengumuman = proxy({
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PengumumanGetPayload<{
|
||||
include: {
|
||||
| Prisma.PengumumanGetPayload<{
|
||||
include: {
|
||||
CategoryPengumuman: true;
|
||||
}
|
||||
}>[]
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.desa.pengumuman["find-many"].get();
|
||||
@@ -82,30 +82,28 @@ const pengumuman = proxy({
|
||||
}
|
||||
},
|
||||
},
|
||||
// findUnique: {
|
||||
// data: null as
|
||||
// | Prisma.PengumumanGetPayload<{
|
||||
// include: {
|
||||
// CategoryPengumuman: true;
|
||||
// }
|
||||
// }>
|
||||
// | null,
|
||||
// async load(id: string) {
|
||||
// try {
|
||||
// const res = await fetch(`/api/desa/pengumuman/${id}`);
|
||||
// if (res.ok) {
|
||||
// const data = await res.json();
|
||||
// pengumuman.findUnique.data = data.data ?? null;
|
||||
// } else {
|
||||
// console.error('Failed to fetch pengumuman:', res.statusText);
|
||||
// pengumuman.findUnique.data = null;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('Error fetching pengumuman:', error);
|
||||
// pengumuman.findUnique.data = null;
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
findUnique: {
|
||||
data: null as Prisma.PengumumanGetPayload<{
|
||||
include: {
|
||||
CategoryPengumuman: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/desa/pengumuman/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
pengumuman.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch pengumuman:", res.statusText);
|
||||
pengumuman.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching pengumuman:", error);
|
||||
pengumuman.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
@@ -237,6 +235,55 @@ const pengumuman = proxy({
|
||||
}
|
||||
},
|
||||
},
|
||||
findFirst: {
|
||||
data: null as Prisma.PengumumanGetPayload<{
|
||||
include: {
|
||||
CategoryPengumuman: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await ApiFetch.api.desa.pengumuman["find-first"].get();
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
// Add type assertion to ensure type safety
|
||||
pengumuman.findFirst.data = res.data
|
||||
.data as Prisma.PengumumanGetPayload<{
|
||||
include: {
|
||||
CategoryPengumuman: true;
|
||||
};
|
||||
}> | null;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch pengumuman terbaru:", err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findRecent: {
|
||||
data: [] as Prisma.PengumumanGetPayload<{
|
||||
include: {
|
||||
CategoryPengumuman: true;
|
||||
};
|
||||
}>[],
|
||||
loading: false,
|
||||
|
||||
async load() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.desa.pengumuman["find-recent"].get();
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
this.data = res.data.data ?? [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal fetch pengumuman recent:", error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const stateDesaPengumuman = proxy({
|
||||
|
||||
887
src/app/admin/(dashboard)/_state/ekonomi/PADesa.ts
Normal file
887
src/app/admin/(dashboard)/_state/ekonomi/PADesa.ts
Normal file
@@ -0,0 +1,887 @@
|
||||
/* 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 templateApbDesa = z.object({
|
||||
tahun: z.number().min(4, "Tahun minimal 4 karakter"),
|
||||
pembiayaanIds: z.array(z.string().uuid()).nonempty("Pilih minimal 1 pembiayaan"),
|
||||
belanjaIds: z.array(z.string().uuid()).nonempty("Pilih minimal 1 belanja"),
|
||||
pendapatanIds: z.array(z.string().uuid()).nonempty("Pilih minimal 1 pendapatan"),
|
||||
});
|
||||
|
||||
const ApbDesaDefaultForm = {
|
||||
tahun: 0,
|
||||
pendapatanIds: [] as string[],
|
||||
belanjaIds: [] as string[],
|
||||
pembiayaanIds: [] as string[],
|
||||
};
|
||||
|
||||
const ApbDesa = proxy({
|
||||
create: {
|
||||
form: { ...ApbDesaDefaultForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const cek = templateApbDesa.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = cek.error.issues.map((v) => v.message).join("\n");
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.apbdesa[
|
||||
"create"
|
||||
].post(this.form);
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil menambahkan APB Desa");
|
||||
ApbDesa.findMany.load();
|
||||
this.reset();
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal menambahkan APB Desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Create error:", error);
|
||||
toast.error("Gagal menambahkan APB Desa");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.form = { ...ApbDesaDefaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.ApbDesaGetPayload<{
|
||||
include: {
|
||||
pendapatan: true;
|
||||
belanja: true;
|
||||
pembiayaan: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.apbdesa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal mengambil APB Desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
toast.error("Gagal mengambil APB Desa");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...ApbDesaDefaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/apbdesa/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error("Gagal mengambil APB Desa");
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.message || "Gagal memuat APB Desa");
|
||||
}
|
||||
|
||||
const data = result.data;
|
||||
|
||||
this.id = id;
|
||||
this.form = {
|
||||
tahun: data.tahun || 0,
|
||||
pendapatanIds: data.pendapatan?.map((p: any) => p.id) || [],
|
||||
belanjaIds: data.belanja?.map((b: any) => b.id) || [],
|
||||
pembiayaanIds: data.pembiayaan?.map((p: any) => p.id) || [],
|
||||
};
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error loading APB Desa:", error);
|
||||
toast.error("Gagal memuat data APB Desa");
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/apbdesa/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error("Gagal memperbarui APB Desa");
|
||||
}
|
||||
const data = await response.json();
|
||||
toast.success("APB Desa berhasil diperbarui");
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error updating APB Desa:", error);
|
||||
toast.error("Gagal memperbarui APB Desa");
|
||||
throw error;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.id = "";
|
||||
this.form = { ...ApbDesaDefaultForm };
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
try {
|
||||
this.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/apbdesa/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error("Gagal menghapus APB Desa");
|
||||
}
|
||||
toast.success("APB Desa berhasil dihapus");
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error deleting APB Desa:", error);
|
||||
toast.error("Gagal menghapus APB Desa");
|
||||
return false;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.ApbDesaGetPayload<{
|
||||
include: { pendapatan: true; belanja: true; pembiayaan: true };
|
||||
}> | null,
|
||||
|
||||
async load(id: string) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/apbdesa/${id}`
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error("Gagal mengambil detail APB Desa");
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.message || "Gagal mengambil data");
|
||||
}
|
||||
|
||||
this.data = result.data; // ✅ fix utama di sini
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error loading APB Desa detail:", error);
|
||||
toast.error("Gagal memuat detail APB Desa");
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templatePendapatan = z.object({
|
||||
name: z.string().min(2, "Nama harus diisi"),
|
||||
value: z.number().int().positive("Nilai harus angka positif"),
|
||||
});
|
||||
|
||||
const PendapatanDefaultForm = {
|
||||
name: "",
|
||||
value: 0,
|
||||
};
|
||||
|
||||
const pendapatan = proxy({
|
||||
create: {
|
||||
form: { ...PendapatanDefaultForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const cek = templatePendapatan.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = cek.error.issues.map((v) => v.message).join("\n");
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.ekonomi.pendapatanaslidesa.pendapatanasli[
|
||||
"create"
|
||||
].post(this.form);
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil menambahkan Pendapatan Asli");
|
||||
pendapatan.findMany.load();
|
||||
this.reset();
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal menambahkan Pendapatan Asli");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Create error:", error);
|
||||
toast.error("Gagal menambahkan Pendapatan Asli");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.form = { ...PendapatanDefaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
// Change to arrow function
|
||||
pendapatan.findMany.loading = true; // Use the full path to access the property
|
||||
pendapatan.findMany.page = page;
|
||||
try {
|
||||
const res =
|
||||
await ApiFetch.api.ekonomi.pendapatanaslidesa.pendapatanasli[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pendapatan.findMany.data = res.data.data || [];
|
||||
pendapatan.findMany.total = res.data.total || 0;
|
||||
pendapatan.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pendapatan:", res.data?.message);
|
||||
pendapatan.findMany.data = [];
|
||||
pendapatan.findMany.total = 0;
|
||||
pendapatan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pendapatan:", error);
|
||||
pendapatan.findMany.data = [];
|
||||
pendapatan.findMany.total = 0;
|
||||
pendapatan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pendapatan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...PendapatanDefaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
value: data.value,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pendapatan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templatePendapatan.safeParse(pendapatan.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pendapatan.update.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
});
|
||||
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 pendapatan");
|
||||
await pendapatan.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate pendapatan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating pendapatan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal mengupdate pendapatan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
pendapatan.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
pendapatan.update.id = "";
|
||||
pendapatan.update.form = { ...PendapatanDefaultForm };
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
pendapatan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/pendapatanasli/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Pendapatan Asli berhasil dihapus");
|
||||
await pendapatan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus Pendapatan Asli");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus Pendapatan Asli");
|
||||
} finally {
|
||||
pendapatan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.PendapatanGetPayload<{
|
||||
select: { isActive: boolean };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/pendapatanasli/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const json = await res.json();
|
||||
pendapatan.findUnique.data = json.data
|
||||
? {
|
||||
...json.data,
|
||||
isActive: json.data.isActive ?? true, // Fallback ke aktif:true jika tidak ada data
|
||||
}
|
||||
: null;
|
||||
} else {
|
||||
pendapatan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templateBelanja = z.object({
|
||||
name: z.string().min(2, "Nama harus diisi"),
|
||||
value: z.number().int().positive("Nilai harus angka positif"),
|
||||
});
|
||||
|
||||
const BelanjaDefaultForm = {
|
||||
name: "",
|
||||
value: 0,
|
||||
};
|
||||
|
||||
const belanja = proxy({
|
||||
create: {
|
||||
form: { ...BelanjaDefaultForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const cek = templateBelanja.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = cek.error.issues.map((v) => v.message).join("\n");
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.belanja[
|
||||
"create"
|
||||
].post(this.form);
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil menambahkan Belanja");
|
||||
belanja.findMany.load();
|
||||
this.reset();
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal menambahkan Belanja");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Create error:", error);
|
||||
toast.error("Gagal menambahkan Belanja");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.form = { ...BelanjaDefaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: [] as Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
value: number;
|
||||
}>,
|
||||
loading: false,
|
||||
async load() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.belanja[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal mengambil Belanja");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
toast.error("Gagal mengambil Belanja");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...BelanjaDefaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/belanja/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
value: data.value,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading belanja:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateBelanja.safeParse(belanja.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
belanja.update.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/belanja/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
});
|
||||
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 belanja");
|
||||
await belanja.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate belanja");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating belanja:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal mengupdate belanja"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
belanja.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
belanja.update.id = "";
|
||||
belanja.update.form = { ...BelanjaDefaultForm };
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
belanja.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/belanja/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Belanja berhasil dihapus");
|
||||
await belanja.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus Belanja");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus Belanja");
|
||||
} finally {
|
||||
belanja.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.BelanjaGetPayload<{
|
||||
select: { isActive: boolean };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
const res = await fetch(`/api/ekonomi/pendapatanaslidesa/belanja/${id}`);
|
||||
if (res.ok) {
|
||||
const json = await res.json();
|
||||
belanja.findUnique.data = json.data
|
||||
? {
|
||||
...json.data,
|
||||
isActive: json.data.isActive ?? true, // Fallback ke aktif:true jika tidak ada data
|
||||
}
|
||||
: null;
|
||||
} else {
|
||||
belanja.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templatePembiayaan = z.object({
|
||||
name: z.string().min(2, "Nama harus diisi"),
|
||||
value: z.number().int().positive("Nilai harus angka positif"),
|
||||
});
|
||||
|
||||
const PembiayaanDefaultForm = {
|
||||
name: "",
|
||||
value: 0,
|
||||
};
|
||||
|
||||
const pembiayaan = proxy({
|
||||
create: {
|
||||
form: { ...PembiayaanDefaultForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const cek = templatePembiayaan.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = cek.error.issues.map((v) => v.message).join("\n");
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.pembiayaan[
|
||||
"create"
|
||||
].post(this.form);
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil menambahkan Pembiayaan");
|
||||
pembiayaan.findMany.load();
|
||||
this.reset();
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal menambahkan Pembiayaan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Create error:", error);
|
||||
toast.error("Gagal menambahkan Pembiayaan");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.form = { ...PembiayaanDefaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: [] as Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
value: number;
|
||||
}>,
|
||||
loading: false,
|
||||
async load() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.pendapatanaslidesa.pembiayaan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal mengambil Pembiayaan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
toast.error("Gagal mengambil Pembiayaan");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...PembiayaanDefaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pembiayaan/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
value: data.value,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pembiayaan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templatePembiayaan.safeParse(pembiayaan.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pembiayaan.update.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/pendapatanaslidesa/pembiayaan/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
value: this.form.value,
|
||||
}),
|
||||
});
|
||||
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 pembiayaan");
|
||||
await pembiayaan.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate pembiayaan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating pembiayaan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal mengupdate pembiayaan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
pembiayaan.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
pembiayaan.update.id = "";
|
||||
pembiayaan.update.form = { ...PembiayaanDefaultForm };
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
pembiayaan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/pembiayaan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Pembiayaan berhasil dihapus");
|
||||
await pembiayaan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus Pembiayaan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus Pembiayaan");
|
||||
} finally {
|
||||
pembiayaan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.PembiayaanGetPayload<{
|
||||
select: { isActive: boolean };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/pendapatanaslidesa/pembiayaan/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const json = await res.json();
|
||||
pembiayaan.findUnique.data = json.data
|
||||
? {
|
||||
...json.data,
|
||||
isActive: json.data.isActive ?? true, // Fallback ke aktif:true jika tidak ada data
|
||||
}
|
||||
: null;
|
||||
} else {
|
||||
pembiayaan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const PendapatanAsliDesa = proxy({
|
||||
ApbDesa,
|
||||
belanja,
|
||||
pembiayaan,
|
||||
pendapatan,
|
||||
});
|
||||
|
||||
export default PendapatanAsliDesa;
|
||||
197
src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts
Normal file
197
src/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
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 templateDemografiPekerjaan = z.object({
|
||||
pekerjaan: z.string().min(1, "Pekerjaan harus diisi"),
|
||||
lakiLaki: z.number().min(1, "Laki - Laki harus diisi"),
|
||||
perempuan: z.number().min(1, "Perempuan harus diisi"),
|
||||
});
|
||||
|
||||
type DemografiPekerjaan = Prisma.DataDemografiPekerjaanGetPayload<{
|
||||
select: {
|
||||
pekerjaan: true;
|
||||
lakiLaki: true;
|
||||
perempuan: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const defaultForm: DemografiPekerjaan = {
|
||||
pekerjaan: "",
|
||||
lakiLaki: 0,
|
||||
perempuan: 0,
|
||||
};
|
||||
|
||||
const demografiPekerjaan = proxy({
|
||||
create: {
|
||||
form: defaultForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDemografiPekerjaan.safeParse(
|
||||
demografiPekerjaan.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
demografiPekerjaan.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.demografipekerjaan[
|
||||
"create"
|
||||
].post(demografiPekerjaan.create.form);
|
||||
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
demografiPekerjaan.create.form = { ...defaultForm };
|
||||
demografiPekerjaan.findMany.load();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
toast.error("failed create");
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
return null;
|
||||
} finally {
|
||||
demografiPekerjaan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DataDemografiPekerjaanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.demografipekerjaan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
demografiPekerjaan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
findUnique: {
|
||||
data: null as Prisma.DataDemografiPekerjaanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/ekonomi/demografipekerjaan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
demografiPekerjaan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch demografiPekerjaan:", res.statusText);
|
||||
demografiPekerjaan.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching demografiPekerjaan:", error);
|
||||
demografiPekerjaan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
const formData = {
|
||||
pekerjaan: this.form.pekerjaan,
|
||||
lakiLaki: this.form.lakiLaki,
|
||||
perempuan: this.form.perempuan,
|
||||
};
|
||||
|
||||
const cek = templateDemografiPekerjaan.safeParse(formData);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await fetch(`/api/ekonomi/demografipekerjaan/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (!res.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
|
||||
toast.success("Berhasil update data!");
|
||||
await demografiPekerjaan.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Update error:", error);
|
||||
toast.error("Gagal update data demografi pekerjaan");
|
||||
throw error;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
demografiPekerjaan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/demografipekerjaan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Demografi pekerjaan berhasil dihapus"
|
||||
);
|
||||
await demografiPekerjaan.findMany.load();
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus demografi pekerjaan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus persentase kelahiran");
|
||||
} finally {
|
||||
demografiPekerjaan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
export default demografiPekerjaan
|
||||
@@ -0,0 +1,194 @@
|
||||
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 templateJumlahPendudukMiskin = z.object({
|
||||
year: z.number().min(1, "Data tahun harus diisi"),
|
||||
totalPoorPopulation: z
|
||||
.number()
|
||||
.min(1, "Data total penduduk miskin harus diisi"),
|
||||
});
|
||||
|
||||
type JumlahPendudukMiskin = Prisma.GrafikJumlahPendudukMiskinGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
year: true;
|
||||
totalPoorPopulation: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const defaultForm: Omit<JumlahPendudukMiskin, "id"> & { id?: string } = {
|
||||
year: 0,
|
||||
totalPoorPopulation: 0,
|
||||
};
|
||||
|
||||
const jumlahPendudukMiskin = proxy({
|
||||
create: {
|
||||
form: defaultForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateJumlahPendudukMiskin.safeParse(
|
||||
jumlahPendudukMiskin.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
jumlahPendudukMiskin.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.jumlahpendudukmiskin[
|
||||
"create"
|
||||
].post(jumlahPendudukMiskin.create.form);
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
jumlahPendudukMiskin.create.form = {
|
||||
year: 0,
|
||||
totalPoorPopulation: 0,
|
||||
};
|
||||
jumlahPendudukMiskin.findMany.load();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
jumlahPendudukMiskin.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.GrafikJumlahPendudukMiskinGetPayload<{
|
||||
select: { id: true; year: true; totalPoorPopulation: true };
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.jumlahpendudukmiskin[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
jumlahPendudukMiskin.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.GrafikJumlahPendudukMiskinGetPayload<{
|
||||
select: { id: true; year: true; totalPoorPopulation: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/ekonomi/jumlahpendudukmiskin/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
jumlahPendudukMiskin.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
jumlahPendudukMiskin.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik jumlah penduduk miskin:", error);
|
||||
jumlahPendudukMiskin.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async byId() {
|
||||
// Method implementation if needed
|
||||
},
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateJumlahPendudukMiskin.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => (v.path as string[]).join("."))
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/jumlahpendudukmiskin/${id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
}
|
||||
);
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await jumlahPendudukMiskin.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Error update data grafik jumlah penduduk miskin:",
|
||||
error
|
||||
);
|
||||
toast.error("Gagal update data grafik jumlah penduduk miskin");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
jumlahPendudukMiskin.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/jumlahpendudukmiskin/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Grafik jumlah penduduk miskin berhasil dihapus"
|
||||
);
|
||||
await jumlahPendudukMiskin.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(
|
||||
result?.message || "Gagal menghapus grafik jumlah penduduk miskin"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete grafik jumlah penduduk miskin:", error);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat menghapus grafik jumlah penduduk miskin"
|
||||
);
|
||||
} finally {
|
||||
jumlahPendudukMiskin.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
export default jumlahPendudukMiskin;
|
||||
243
src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.ts
Normal file
243
src/app/admin/(dashboard)/_state/ekonomi/jumlah-pengangguran.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
/* 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 templateJumlahPengngguran = z.object({
|
||||
month: z.string().min(1, "Bulan harus diisi"),
|
||||
year: z.number().min(1, "Tahun harus diisi"),
|
||||
totalUnemployment: z.number().min(1, "Total pengangguran harus diisi"),
|
||||
educatedUnemployment: z
|
||||
.number()
|
||||
.min(1, "Pengangguran pendidikan harus diisi"),
|
||||
uneducatedUnemployment: z
|
||||
.number()
|
||||
.min(1, "Pengangguran tidak pendidikan harus diisi"),
|
||||
percentageChange: z.number().min(0, "Persentase perubahan harus diisi"),
|
||||
});
|
||||
|
||||
type JumlahPengangguran = {
|
||||
month: string;
|
||||
year: number;
|
||||
totalUnemployment: number;
|
||||
educatedUnemployment: number;
|
||||
uneducatedUnemployment: number;
|
||||
percentageChange: number;
|
||||
};
|
||||
|
||||
const jumlahPengangguranForm: JumlahPengangguran = {
|
||||
month: "",
|
||||
year: 0,
|
||||
totalUnemployment: 0,
|
||||
educatedUnemployment: 0,
|
||||
uneducatedUnemployment: 0,
|
||||
percentageChange: 0,
|
||||
};
|
||||
|
||||
const jumlahPengangguran = proxy({
|
||||
findByMonthYear: {
|
||||
data: null as any,
|
||||
loading: false,
|
||||
load: async ({ month, year }: { month: string; year: number }) => {
|
||||
jumlahPengangguran.findByMonthYear.loading = true;
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/jumlahpengangguran/detaildatapengangguran/month/${month}/year/${year}`
|
||||
);
|
||||
const json = await res.json();
|
||||
jumlahPengangguran.findByMonthYear.data = json.data;
|
||||
return json.data;
|
||||
} catch (err) {
|
||||
console.error("Gagal ambil data bulan/tahun:", err);
|
||||
} finally {
|
||||
jumlahPengangguran.findByMonthYear.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
create: {
|
||||
form: jumlahPengangguranForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateJumlahPengngguran.safeParse(
|
||||
jumlahPengangguran.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
jumlahPengangguran.create.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.ekonomi.jumlahpengangguran.detaildatapengangguran[
|
||||
"create"
|
||||
].post(jumlahPengangguran.create.form);
|
||||
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
jumlahPengangguran.create.form = { ...jumlahPengangguranForm };
|
||||
jumlahPengangguran.findMany.load();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
toast.error("failed create");
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
return null;
|
||||
} finally {
|
||||
jumlahPengangguran.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DetailDataPengangguranGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.ekonomi.jumlahpengangguran.detaildatapengangguran[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
jumlahPengangguran.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
findUnique: {
|
||||
data: null as Prisma.DetailDataPengangguranGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/jumlahpengangguran/detaildatapengangguran/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
jumlahPengangguran.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch jumlahPengangguran:", res.statusText);
|
||||
jumlahPengangguran.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching jumlahPengangguran:", error);
|
||||
jumlahPengangguran.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...jumlahPengangguranForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
const formData = {
|
||||
month: this.form.month,
|
||||
year: this.form.year,
|
||||
totalUnemployment: this.form.totalUnemployment,
|
||||
educatedUnemployment: this.form.educatedUnemployment,
|
||||
uneducatedUnemployment: this.form.uneducatedUnemployment,
|
||||
percentageChange: this.form.percentageChange,
|
||||
};
|
||||
|
||||
const cek = templateJumlahPengngguran.safeParse(formData);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/jumlahpengangguran/detaildatapengangguran/${id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (!res.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
|
||||
toast.success("Berhasil update data!");
|
||||
await jumlahPengangguran.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Update error:", error);
|
||||
toast.error("Gagal update data jumlah pengangguran");
|
||||
throw error;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
jumlahPengangguran.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/jumlahpengangguran/detaildatapengangguran/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Jumlah pengangguran berhasil dihapus"
|
||||
);
|
||||
await jumlahPengangguran.findMany.load();
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus jumlah pengangguran");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus jumlah pengangguran");
|
||||
} finally {
|
||||
jumlahPengangguran.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const jumlahPengangguranState = proxy({
|
||||
jumlahPengangguran,
|
||||
});
|
||||
|
||||
export default jumlahPengangguranState;
|
||||
225
src/app/admin/(dashboard)/_state/ekonomi/lowongan-kerja.ts
Normal file
225
src/app/admin/(dashboard)/_state/ekonomi/lowongan-kerja.ts
Normal file
@@ -0,0 +1,225 @@
|
||||
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({
|
||||
posisi: z.string(),
|
||||
namaPerusahaan: z.string(),
|
||||
lokasi: z.string(),
|
||||
tipePekerjaan: z.string(),
|
||||
gaji: z.string(),
|
||||
deskripsi: z.string(),
|
||||
kualifikasi: z.string(),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
posisi: "",
|
||||
namaPerusahaan: "",
|
||||
lokasi: "",
|
||||
tipePekerjaan: "",
|
||||
gaji: "",
|
||||
deskripsi: "",
|
||||
kualifikasi: "",
|
||||
};
|
||||
|
||||
const lowonganKerjaState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(lowonganKerjaState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
lowonganKerjaState.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.lowongankerja["create"].post(
|
||||
lowonganKerjaState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
lowonganKerjaState.create.loading = false;
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
lowonganKerjaState.create.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
lowonganKerjaState.create.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.LowonganPekerjaanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.lowongankerja["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
lowonganKerjaState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.LowonganPekerjaanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/ekonomi/lowongankerja/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
lowonganKerjaState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
lowonganKerjaState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
lowonganKerjaState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
lowonganKerjaState.delete.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/lowongankerja/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Lowongan kerja berhasil dihapus");
|
||||
await lowonganKerjaState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus lowongan kerja");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting data:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus lowongan kerja");
|
||||
} finally {
|
||||
lowonganKerjaState.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/ekonomi/lowongankerja/${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 = {
|
||||
posisi: data.posisi,
|
||||
namaPerusahaan: data.namaPerusahaan,
|
||||
lokasi: data.lokasi,
|
||||
tipePekerjaan: data.tipePekerjaan,
|
||||
gaji: data.gaji,
|
||||
deskripsi: data.deskripsi,
|
||||
kualifikasi: data.kualifikasi,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(
|
||||
result?.message || "Gagal memuat data lowongan kerja"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(lowonganKerjaState.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
lowonganKerjaState.update.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/lowongankerja/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
posisi: this.form.posisi,
|
||||
namaPerusahaan: this.form.namaPerusahaan,
|
||||
lokasi: this.form.lokasi,
|
||||
tipePekerjaan: this.form.tipePekerjaan,
|
||||
gaji: this.form.gaji,
|
||||
deskripsi: this.form.deskripsi,
|
||||
kualifikasi: this.form.kualifikasi,
|
||||
}),
|
||||
});
|
||||
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 lowongan kerja");
|
||||
await lowonganKerjaState.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update lowongan kerja");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating data:", error);
|
||||
toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat mengupdate lowongan kerja");
|
||||
return false;
|
||||
} finally {
|
||||
lowonganKerjaState.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
lowonganKerjaState.update.id = "";
|
||||
lowonganKerjaState.update.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default lowonganKerjaState;
|
||||
@@ -0,0 +1,468 @@
|
||||
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 templatePasarDesaForm = z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
harga: z.number().min(1, "Harga minimal 1"),
|
||||
alamatUsaha: z.string().min(1, "Alamat minimal 1 karakter"),
|
||||
imageId: z.string().min(1, "Gambar wajib dipilih"),
|
||||
rating: z.number().min(1, "Rating minimal 1"),
|
||||
kategoriId: z.array(z.string()).min(1, "Minimal pilih satu kategori"),
|
||||
});
|
||||
|
||||
const defaultPasarDesaForm = {
|
||||
nama: "",
|
||||
harga: 0,
|
||||
alamatUsaha: "",
|
||||
imageId: "",
|
||||
rating: 0,
|
||||
kategoriId: [] as string[],
|
||||
};
|
||||
|
||||
const pasarDesa = proxy({
|
||||
create: {
|
||||
form: { ...defaultPasarDesaForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templatePasarDesaForm.safeParse(pasarDesa.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
pasarDesa.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.pasardesa["create"].post(
|
||||
pasarDesa.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
pasarDesa.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
pasarDesa.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.PasarDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
KategoriToPasar: {
|
||||
include: {
|
||||
kategori: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.pasardesa["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
pasarDesa.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.PasarDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
KategoriToPasar: {
|
||||
include: {
|
||||
kategori: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/ekonomi/pasardesa/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
pasarDesa.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
pasarDesa.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
pasarDesa.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
pasarDesa.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/ekonomi/pasardesa/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Pasar desa berhasil dihapus");
|
||||
await pasarDesa.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus pasar desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus pasar desa");
|
||||
} finally {
|
||||
pasarDesa.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultPasarDesaForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/pasardesa/${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,
|
||||
harga: data.harga,
|
||||
alamatUsaha: data.alamatUsaha,
|
||||
imageId: data.imageId,
|
||||
rating: data.rating,
|
||||
kategoriId: data.kategoriId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pasar desa:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templatePasarDesaForm.safeParse(pasarDesa.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pasarDesa.edit.loading = true;
|
||||
const response = await fetch(`/api/ekonomi/pasardesa/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
harga: this.form.harga,
|
||||
alamatUsaha: this.form.alamatUsaha,
|
||||
imageId: this.form.imageId,
|
||||
rating: this.form.rating,
|
||||
kategoriId: this.form.kategoriId,
|
||||
}),
|
||||
});
|
||||
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 pasar desa");
|
||||
await pasarDesa.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate pasar desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating pasar desa:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal mengupdate pasar desa"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
pasarDesa.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
pasarDesa.edit.id = "";
|
||||
pasarDesa.edit.form = { ...defaultPasarDesaForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= KATEGORI PRODUK ========================================= //
|
||||
const kategoriProdukForm = z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const kategoriProdukDefaultForm = {
|
||||
nama: "",
|
||||
};
|
||||
|
||||
const kategoriProduk = proxy({
|
||||
create: {
|
||||
form: { ...kategoriProdukDefaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = kategoriProdukForm.safeParse(kategoriProduk.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
kategoriProduk.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.kategoriproduk["create"].post(
|
||||
kategoriProduk.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
kategoriProduk.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
kategoriProduk.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
nama: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
kategoriProduk.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KategoriProdukGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/ekonomi/kategoriproduk/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kategoriProduk.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
kategoriProduk.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
kategoriProduk.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
kategoriProduk.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/ekonomi/kategoriproduk/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kategori produk berhasil dihapus");
|
||||
await kategoriProduk.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kategori produk");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kategori produk");
|
||||
} finally {
|
||||
kategoriProduk.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...kategoriProdukDefaultForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/kategoriproduk/${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,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kategori produk:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = kategoriProdukForm.safeParse(kategoriProduk.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
kategoriProduk.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/kategoriproduk/${kategoriProduk.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: kategoriProduk.edit.form.nama,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Clone the response to avoid 'body already read' error
|
||||
const responseClone = response.clone();
|
||||
|
||||
try {
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
"Update failed with status:",
|
||||
response.status,
|
||||
"Response:",
|
||||
result
|
||||
);
|
||||
throw new Error(
|
||||
result?.message ||
|
||||
`Gagal mengupdate kategori produk (${response.status})`
|
||||
);
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
toast.success(
|
||||
result.message || "Berhasil memperbarui kategori produk"
|
||||
);
|
||||
await kategoriProduk.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate kategori produk"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// If JSON parsing fails, try to get the response text for better error messages
|
||||
try {
|
||||
const text = await responseClone.text();
|
||||
console.error("Error response text:", text);
|
||||
throw new Error(`Gagal memproses respons dari server: ${text}`);
|
||||
} catch (textError) {
|
||||
console.error("Error parsing response as text:", textError);
|
||||
console.error("Original error:", error);
|
||||
throw new Error("Gagal memproses respons dari server");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating kategori produk:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate kategori produk"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
kategoriProduk.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
kategoriProduk.edit.id = "";
|
||||
kategoriProduk.edit.form = { ...kategoriProdukDefaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const pasarDesaState = proxy({
|
||||
pasarDesa,
|
||||
kategoriProduk,
|
||||
});
|
||||
export default pasarDesaState;
|
||||
249
src/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan.ts
Normal file
249
src/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan.ts
Normal file
@@ -0,0 +1,249 @@
|
||||
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({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
ikonUrl: z.string().optional(),
|
||||
statistik: z.object({
|
||||
tahun: z.string().min(1, "Tahun minimal 1 karakter"),
|
||||
jumlah: z.string().min(1, "Jumlah minimal 1 karakter"),
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
nama: "",
|
||||
deskripsi: "",
|
||||
ikonUrl: "",
|
||||
statistik: {
|
||||
tahun: "",
|
||||
jumlah: ""
|
||||
}
|
||||
};
|
||||
|
||||
const programKemiskinanState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(programKemiskinanState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
programKemiskinanState.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.programkemiskinan["create"].post(
|
||||
programKemiskinanState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
programKemiskinanState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return toast.error("failed create");
|
||||
} finally {
|
||||
programKemiskinanState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: [] as Prisma.ProgramKemiskinanGetPayload<{
|
||||
include: {
|
||||
statistik: true;
|
||||
};
|
||||
}>[],
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.programkemiskinan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
programKemiskinanState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.ProgramKemiskinanGetPayload<{
|
||||
include: {
|
||||
statistik: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/ekonomi/programkemiskinan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
programKemiskinanState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
programKemiskinanState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
programKemiskinanState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
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/ekonomi/programkemiskinan/${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,
|
||||
deskripsi: data.deskripsi,
|
||||
ikonUrl: data.ikonUrl || "",
|
||||
statistik: {
|
||||
tahun: data.statistik.tahun,
|
||||
jumlah: data.statistik.jumlah,
|
||||
},
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading program kemiskinan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(programKemiskinanState.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
programKemiskinanState.update.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/programkemiskinan/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
deskripsi: this.form.deskripsi,
|
||||
ikonUrl: this.form.ikonUrl,
|
||||
statistik: {
|
||||
tahun: this.form.statistik.tahun,
|
||||
jumlah: this.form.statistik.jumlah,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
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 program kemiskinan");
|
||||
await programKemiskinanState.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update program kemiskinan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating program kemiskinan:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update program kemiskinan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
programKemiskinanState.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
programKemiskinanState.update.id = "";
|
||||
programKemiskinanState.update.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async delete(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
programKemiskinanState.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/programkemiskinan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Program kemiskinan berhasil dihapus"
|
||||
);
|
||||
await programKemiskinanState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus program kemiskinan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus program kemiskinan");
|
||||
} finally {
|
||||
programKemiskinanState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default programKemiskinanState;
|
||||
202
src/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa.ts
Normal file
202
src/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
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 templateGrafikSektorUnggulan = z.object({
|
||||
name: z.string().min(2, "Nama harus diisi"),
|
||||
description: z.string().min(2, "Deskripsi harus diisi"),
|
||||
value: z.number().min(1, "Nilai harus diisi"),
|
||||
});
|
||||
|
||||
interface SektorUnggulanForm {
|
||||
id?: string;
|
||||
name: string;
|
||||
description: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
const defaultForm: SektorUnggulanForm = {
|
||||
name: "",
|
||||
description: "",
|
||||
value: 0,
|
||||
};
|
||||
|
||||
const grafikSektorUnggulan = proxy({
|
||||
create: {
|
||||
form: defaultForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateGrafikSektorUnggulan.safeParse(
|
||||
grafikSektorUnggulan.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
grafikSektorUnggulan.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.sektourunggulandesa[
|
||||
"create"
|
||||
].post(grafikSektorUnggulan.create.form);
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
grafikSektorUnggulan.create.form = {
|
||||
name: "",
|
||||
description: "",
|
||||
value: 0,
|
||||
};
|
||||
grafikSektorUnggulan.findMany.load();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
grafikSektorUnggulan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.SektorUnggulanDesaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
name: true;
|
||||
description: true;
|
||||
value: true;
|
||||
createdAt: true;
|
||||
updatedAt: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.sektourunggulandesa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
grafikSektorUnggulan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.SektorUnggulanDesaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
name: true;
|
||||
description: true;
|
||||
value: true;
|
||||
createdAt: true;
|
||||
updatedAt: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/ekonomi/sektourunggulandesa/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
grafikSektorUnggulan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
grafikSektorUnggulan.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik sektor unggulan desa:", error);
|
||||
grafikSektorUnggulan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async byId() {
|
||||
// Method implementation if needed
|
||||
},
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateGrafikSektorUnggulan.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(`/api/ekonomi/sektourunggulandesa/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await grafikSektorUnggulan.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data grafik sektor unggulan desa");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
grafikSektorUnggulan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/sektourunggulandesa/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Grafik sektor unggulan desa berhasil dihapus"
|
||||
);
|
||||
await grafikSektorUnggulan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(
|
||||
result?.message || "Gagal menghapus grafik sektor unggulan desa"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat menghapus grafik sektor unggulan desa"
|
||||
);
|
||||
} finally {
|
||||
grafikSektorUnggulan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
export default grafikSektorUnggulan;
|
||||
@@ -0,0 +1,785 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
import { toast } from "react-toastify";
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
const templatePosisiOrganisasi = z.object({
|
||||
nama: z.string().min(1, "Nama harus diisi"),
|
||||
deskripsi: z.string().optional(),
|
||||
hierarki: z.number().int().positive("Hierarki harus angka positif"),
|
||||
});
|
||||
|
||||
const posisiOrganisasiDefaultForm = {
|
||||
nama: "",
|
||||
deskripsi: "",
|
||||
hierarki: 0,
|
||||
};
|
||||
|
||||
const posisiOrganisasi = proxy({
|
||||
create: {
|
||||
form: { ...posisiOrganisasiDefaultForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const cek = templatePosisiOrganisasi.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = cek.error.issues.map((v) => v.message).join("\n");
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||
"posisi-organisasi"
|
||||
]["create"].post(this.form);
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil menambahkan posisi organisasi");
|
||||
posisiOrganisasi.findMany.load();
|
||||
this.reset();
|
||||
} else {
|
||||
toast.error(res.data?.message || "Gagal menambahkan posisi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Create error:", error);
|
||||
toast.error("Terjadi kesalahan saat menambahkan posisi");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.form = { ...posisiOrganisasiDefaultForm };
|
||||
},
|
||||
},
|
||||
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...posisiOrganisasiDefaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/posisi-organisasi/${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,
|
||||
deskripsi: data.deskripsi,
|
||||
hierarki: data.hierarki,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading posisi organisasi:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templatePosisiOrganisasi.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/posisi-organisasi/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
deskripsi: this.form.deskripsi,
|
||||
hierarki: this.form.hierarki,
|
||||
}),
|
||||
}
|
||||
);
|
||||
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 posisi organisasi");
|
||||
await posisiOrganisasi.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate posisi organisasi"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating posisi organisasi:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate posisi organisasi"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.id = "";
|
||||
this.form = { ...posisiOrganisasiDefaultForm };
|
||||
},
|
||||
},
|
||||
|
||||
findMany: {
|
||||
data: [] as Array<{
|
||||
id: string;
|
||||
nama: string;
|
||||
deskripsi: string | null;
|
||||
hierarki: number;
|
||||
}>,
|
||||
async load() {
|
||||
try {
|
||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||
"posisi-organisasi"
|
||||
]["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
// The API now returns the id field, so we can use it directly
|
||||
this.data = res.data?.data ?? [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
this.data = [];
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
posisiOrganisasi.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/posisi-organisasi/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Posisi organisasi berhasil dihapus");
|
||||
await posisiOrganisasi.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus posisi organisasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus posisi organisasi");
|
||||
} finally {
|
||||
posisiOrganisasi.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templatePegawai = z.object({
|
||||
namaLengkap: z.string().min(1, "Nama wajib diisi"),
|
||||
gelarAkademik: z.string().optional(),
|
||||
imageId: z.string().nullable().optional(),
|
||||
tanggalMasuk: z.string().optional(), // ISO format
|
||||
email: z.string().email("Email tidak valid").optional(),
|
||||
telepon: z.string().optional(),
|
||||
alamat: z.string().optional(),
|
||||
posisiId: z.string().min(1, "Posisi wajib diisi"),
|
||||
isActive: z.boolean().default(true),
|
||||
});
|
||||
|
||||
const pegawaiDefaultForm = {
|
||||
namaLengkap: "",
|
||||
gelarAkademik: "",
|
||||
imageId: "",
|
||||
tanggalMasuk: "",
|
||||
email: "",
|
||||
telepon: "",
|
||||
alamat: "",
|
||||
posisiId: "",
|
||||
isActive: true,
|
||||
};
|
||||
|
||||
const pegawai = proxy({
|
||||
create: {
|
||||
form: { ...pegawaiDefaultForm },
|
||||
loading: false,
|
||||
async submit() {
|
||||
const cek = templatePegawai.safeParse(pegawai.create.form);
|
||||
if (!cek.success) {
|
||||
const err = cek.error.issues.map((i) => i.message).join("\n");
|
||||
toast.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
pegawai.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||
"pegawai"
|
||||
]["create"].post(pegawai.create.form);
|
||||
if (res.status === 200) {
|
||||
toast.success("Pegawai berhasil ditambahkan");
|
||||
await pegawai.findMany.load();
|
||||
} else {
|
||||
toast.error(res.data?.message ?? "Gagal tambah pegawai");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal create:", error);
|
||||
toast.error("Terjadi kesalahan saat menambahkan pegawai");
|
||||
} finally {
|
||||
pegawai.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// In struktur-organisasi.ts
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
pegawai.findMany.loading = true; // Use the full path to access the property
|
||||
pegawai.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||
"pegawai"
|
||||
]["find-many"].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pegawai.findMany.data = res.data.data || [];
|
||||
pegawai.findMany.total = res.data.total || 0;
|
||||
pegawai.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pegawai:", res.data?.message);
|
||||
pegawai.findMany.data = [];
|
||||
pegawai.findMany.total = 0;
|
||||
pegawai.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pegawai:", error);
|
||||
pegawai.findMany.data = [];
|
||||
pegawai.findMany.total = 0;
|
||||
pegawai.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pegawai.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as
|
||||
| (Prisma.PegawaiGetPayload<{
|
||||
include: { posisi: true; image: true };
|
||||
}> & { isActive: boolean })
|
||||
| null,
|
||||
async load(id: string) {
|
||||
const res = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${id}`);
|
||||
if (res.ok) {
|
||||
const json = await res.json();
|
||||
pegawai.findUnique.data = json.data
|
||||
? {
|
||||
...json.data,
|
||||
isActive: json.data.isActive ?? json.data.aktif ?? true, // Fallback ke aktif:true jika tidak ada data
|
||||
}
|
||||
: null;
|
||||
} else {
|
||||
pegawai.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
pegawai.delete.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/pegawai/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
const json = await res.json();
|
||||
if (res.ok) {
|
||||
toast.success(json.message ?? "Berhasil hapus pegawai");
|
||||
await pegawai.findMany.load();
|
||||
} else {
|
||||
toast.error(json.message ?? "Gagal hapus pegawai");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus");
|
||||
} finally {
|
||||
pegawai.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...pegawaiDefaultForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/pegawai/${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 = {
|
||||
namaLengkap: data.namaLengkap,
|
||||
gelarAkademik: data.gelarAkademik,
|
||||
imageId: data.imageId,
|
||||
tanggalMasuk: data.tanggalMasuk,
|
||||
email: data.email,
|
||||
telepon: data.telepon,
|
||||
alamat: data.alamat,
|
||||
posisiId: data.posisiId,
|
||||
isActive: data.isActive,
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading berita:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async submit() {
|
||||
const cek = templatePegawai.safeParse(pegawai.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
pegawai.edit.loading = true;
|
||||
|
||||
// Format tanggalMasuk to ISO string if it exists
|
||||
const formattedTanggalMasuk = this.form.tanggalMasuk
|
||||
? new Date(this.form.tanggalMasuk).toISOString()
|
||||
: undefined;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/pegawai/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: this.id,
|
||||
namaLengkap: this.form.namaLengkap,
|
||||
gelarAkademik: this.form.gelarAkademik,
|
||||
imageId: this.form.imageId || null,
|
||||
tanggalMasuk: formattedTanggalMasuk,
|
||||
email: this.form.email,
|
||||
telepon: this.form.telepon,
|
||||
alamat: this.form.alamat,
|
||||
posisiId: this.form.posisiId,
|
||||
isActive: this.form.isActive,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
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 pegawai");
|
||||
await pegawai.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update pegawai");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating pegawai:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update pegawai"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
pegawai.edit.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
pegawai.edit.id = "";
|
||||
pegawai.edit.form = { ...pegawaiDefaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Schema Zod untuk form validasi
|
||||
const templateHubunganOrganisasiForm = z.object({
|
||||
atasanId: z.string().min(1, "Atasan wajib dipilih"),
|
||||
bawahanId: z.string().min(1, "Bawahan wajib dipilih"),
|
||||
tipe: z.string().optional(),
|
||||
});
|
||||
|
||||
// Default form state
|
||||
const defaultHubunganOrganisasiForm = {
|
||||
atasanId: "",
|
||||
bawahanId: "",
|
||||
tipe: "",
|
||||
};
|
||||
|
||||
// ====================== STATE ===========================
|
||||
const hubunganOrganisasi = proxy({
|
||||
create: {
|
||||
form: { ...defaultHubunganOrganisasiForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateHubunganOrganisasiForm.safeParse(
|
||||
hubunganOrganisasi.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
.join("\n")}]`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
hubunganOrganisasi.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||
"hubungan-organisasi"
|
||||
]["create"].post(hubunganOrganisasi.create.form);
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
hubunganOrganisasi.findMany.load();
|
||||
return toast.success("Berhasil menambahkan hubungan organisasi");
|
||||
} else {
|
||||
return toast.error(res.data?.message || "Gagal menambahkan data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal create:", error);
|
||||
toast.error("Terjadi kesalahan saat menambahkan");
|
||||
} finally {
|
||||
hubunganOrganisasi.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
atasanId: string;
|
||||
bawahanId: string;
|
||||
tipe?: string | null;
|
||||
atasan: {
|
||||
id: string;
|
||||
namaLengkap: string;
|
||||
gelarAkademik: string | null;
|
||||
imageId: string | null;
|
||||
tanggalMasuk: Date | null;
|
||||
email: string | null;
|
||||
telepon: string | null;
|
||||
alamat: string | null;
|
||||
posisiId: string;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
bawahan: {
|
||||
id: string;
|
||||
namaLengkap: string;
|
||||
gelarAkademik: string | null;
|
||||
imageId: string | null;
|
||||
tanggalMasuk: Date | null;
|
||||
email: string | null;
|
||||
telepon: string | null;
|
||||
alamat: string | null;
|
||||
posisiId: string;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
}> | null,
|
||||
|
||||
async load() {
|
||||
try {
|
||||
const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
|
||||
"hubungan-organisasi"
|
||||
]["find-many"].get();
|
||||
|
||||
if (res.status === 200) {
|
||||
hubunganOrganisasi.findMany.data = (res.data?.data ?? []).map(
|
||||
(item: any) => ({
|
||||
...item,
|
||||
atasan: item.atasan
|
||||
? {
|
||||
...item.atasan,
|
||||
isActive: item.atasan.isActive ?? item.atasan.aktif ?? true,
|
||||
}
|
||||
: null,
|
||||
bawahan: item.bawahan
|
||||
? {
|
||||
...item.bawahan,
|
||||
isActive:
|
||||
item.bawahan.isActive ?? item.bawahan.aktif ?? true,
|
||||
}
|
||||
: null,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
hubunganOrganisasi.findMany.data = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fetch list error:", error);
|
||||
toast.error("Gagal memuat data hubungan organisasi");
|
||||
hubunganOrganisasi.findMany.data = [];
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
findUnique: {
|
||||
data: null as {
|
||||
id: string;
|
||||
atasanId: string;
|
||||
bawahanId: string;
|
||||
tipe?: string | null;
|
||||
atasan?: {
|
||||
id: string;
|
||||
namaLengkap: string;
|
||||
gelarAkademik: string | null;
|
||||
imageId: string;
|
||||
tanggalMasuk: Date | null;
|
||||
email: string | null;
|
||||
telepon: string | null;
|
||||
alamat: string | null;
|
||||
posisiId: string;
|
||||
aktif: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
bawahan?: {
|
||||
id: string;
|
||||
namaLengkap: string;
|
||||
gelarAkademik: string | null;
|
||||
imageId: string;
|
||||
tanggalMasuk: Date | null;
|
||||
email: string | null;
|
||||
telepon: string | null;
|
||||
alamat: string | null;
|
||||
posisiId: string;
|
||||
aktif: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
} | null,
|
||||
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`
|
||||
);
|
||||
const result = await res.json();
|
||||
|
||||
if (res.ok && result?.success) {
|
||||
hubunganOrganisasi.findUnique.data = result.data;
|
||||
} else {
|
||||
hubunganOrganisasi.findUnique.data = null;
|
||||
toast.error(result?.message || "Gagal mengambil data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Find unique error:", error);
|
||||
hubunganOrganisasi.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultHubunganOrganisasiForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`
|
||||
);
|
||||
const result = await res.json();
|
||||
|
||||
if (res.ok && result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
atasanId: data.atasanId,
|
||||
bawahanId: data.bawahanId,
|
||||
tipe: data.tipe || "",
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateHubunganOrganisasiForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
.join("\n")}]`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await res.json();
|
||||
if (res.ok && result.success) {
|
||||
await hubunganOrganisasi.findMany.load();
|
||||
toast.success("Berhasil mengupdate hubungan organisasi");
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal mengupdate");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Update error:", error);
|
||||
toast.error(error instanceof Error ? error.message : "Gagal update");
|
||||
return false;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
hubunganOrganisasi.edit.id = "";
|
||||
hubunganOrganisasi.edit.form = { ...defaultHubunganOrganisasiForm };
|
||||
},
|
||||
},
|
||||
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
hubunganOrganisasi.delete.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
|
||||
const result = await res.json();
|
||||
if (res.ok && result?.success) {
|
||||
toast.success("Hubungan organisasi berhasil dihapus");
|
||||
hubunganOrganisasi.findMany.load();
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus hubungan organisasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Delete error:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus");
|
||||
} finally {
|
||||
hubunganOrganisasi.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const strukturorganisasiState = proxy({
|
||||
posisiOrganisasi,
|
||||
pegawai,
|
||||
hubunganOrganisasi,
|
||||
});
|
||||
|
||||
export default strukturorganisasiState;
|
||||
376
src/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur.ts
Normal file
376
src/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur.ts
Normal file
@@ -0,0 +1,376 @@
|
||||
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 templateGrafikUsiaKerjaYangMenganggur = z.object({
|
||||
usia18_25: z.string().min(1, "Data usia 18-25 harus diisi"),
|
||||
usia26_35: z.string().min(1, "Data usia 26-35 harus diisi"),
|
||||
usia36_45: z.string().min(1, "Data usia 36-45 harus diisi"),
|
||||
usia46_keatas: z.string().min(1, "Data usia 46 keatas harus diisi"),
|
||||
});
|
||||
|
||||
type GrafikUsiaKerjaYangMenganggur = Prisma.GrafikMenganggurBerdasarkanUsiaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
usia18_25: true;
|
||||
usia26_35: true;
|
||||
usia36_45: true;
|
||||
usia46_keatas: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const defaultForm: Omit<GrafikUsiaKerjaYangMenganggur, 'id'> & { id?: string } = {
|
||||
usia18_25: "",
|
||||
usia26_35: "",
|
||||
usia36_45: "",
|
||||
usia46_keatas: "",
|
||||
};
|
||||
|
||||
const grafikBerdasarkanUsiaKerjaNganggur = proxy({
|
||||
create: {
|
||||
form: defaultForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateGrafikUsiaKerjaYangMenganggur.safeParse(
|
||||
grafikBerdasarkanUsiaKerjaNganggur.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.grafikusiakerjayangmenganggur[
|
||||
"create"
|
||||
].post(grafikBerdasarkanUsiaKerjaNganggur.create.form);
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
grafikBerdasarkanUsiaKerjaNganggur.create.form = {
|
||||
usia18_25: "",
|
||||
usia26_35: "",
|
||||
usia36_45: "",
|
||||
usia46_keatas: "",
|
||||
};
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.load();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.GrafikMenganggurBerdasarkanUsiaGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.grafikusiakerjayangmenganggur[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.GrafikMenganggurBerdasarkanUsiaGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/grafikusiakerjayangmenganggur/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik berdasarkan usia kerja yang menganggur:", error);
|
||||
grafikBerdasarkanUsiaKerjaNganggur.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: {...defaultForm},
|
||||
loading: false,
|
||||
async byId() {
|
||||
// Method implementation if needed
|
||||
},
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateGrafikUsiaKerjaYangMenganggur.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues.map((v) => `${v.path.join(".")}`).join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/grafikusiakerjayangmenganggur/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await grafikBerdasarkanUsiaKerjaNganggur.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data grafik berdasarkan usia kerja yang menganggur");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/ekonomi/grafikusiakerjayangmenganggur/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Grafik berdasarkan usia kerja yang menganggur berhasil dihapus");
|
||||
await grafikBerdasarkanUsiaKerjaNganggur.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus grafik berdasarkan usia kerja yang menganggur");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus grafik berdasarkan usia kerja yang menganggur");
|
||||
} finally {
|
||||
grafikBerdasarkanUsiaKerjaNganggur.delete.loading = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const templateGrafikBerpendidikanYangMenganggur = z.object({
|
||||
SD: z.string().min(1, "Data SD harus diisi"),
|
||||
SMP: z.string().min(1, "Data SMP harus diisi"),
|
||||
SMA: z.string().min(1, "Data SMA harus diisi"),
|
||||
D3: z.string().min(1, "Data D3 harus diisi"),
|
||||
S1: z.string().min(1, "Data S1 harus diisi"),
|
||||
});
|
||||
|
||||
type GrafikBerpendidikanYangMenganggur = Prisma.GrafikMenganggurBerdasarkanPendidikanGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
SD: true;
|
||||
SMP: true;
|
||||
SMA: true;
|
||||
D3: true;
|
||||
S1: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const defaultFormBerpendidikan: Omit<GrafikBerpendidikanYangMenganggur, 'id'> & { id?: string } = {
|
||||
SD: "",
|
||||
SMP: "",
|
||||
SMA: "",
|
||||
D3: "",
|
||||
S1: "",
|
||||
};
|
||||
|
||||
const grafikBerdasarkanPendidikan = proxy({
|
||||
create: {
|
||||
form: defaultFormBerpendidikan,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateGrafikBerpendidikanYangMenganggur.safeParse(
|
||||
grafikBerdasarkanPendidikan.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
grafikBerdasarkanPendidikan.create.loading = true;
|
||||
const res = await ApiFetch.api.ekonomi.grafikmenganggurberdasarkanpendidikan[
|
||||
"create"
|
||||
].post(grafikBerdasarkanPendidikan.create.form);
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
grafikBerdasarkanPendidikan.create.form = {
|
||||
SD: "",
|
||||
SMP: "",
|
||||
SMA: "",
|
||||
D3: "",
|
||||
S1: "",
|
||||
};
|
||||
grafikBerdasarkanPendidikan.findMany.load();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
grafikBerdasarkanPendidikan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.GrafikMenganggurBerdasarkanPendidikanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.ekonomi.grafikmenganggurberdasarkanpendidikan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
grafikBerdasarkanPendidikan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.GrafikMenganggurBerdasarkanPendidikanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/ekonomi/grafikmenganggurberdasarkanpendidikan/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
grafikBerdasarkanPendidikan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
grafikBerdasarkanPendidikan.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik berdasarkan usia kerja yang menganggur:", error);
|
||||
grafikBerdasarkanPendidikan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: {...defaultFormBerpendidikan},
|
||||
loading: false,
|
||||
async byId() {
|
||||
// Method implementation if needed
|
||||
},
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateGrafikBerpendidikanYangMenganggur.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues.map((v) => `${v.path.join(".")}`).join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/ekonomi/grafikmenganggurberdasarkanpendidikan/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await grafikBerdasarkanPendidikan.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data grafik berdasarkan pendidikan yang menganggur");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
grafikBerdasarkanPendidikan.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/ekonomi/grafikmenganggurberdasarkanpendidikan/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Grafik berdasarkan pendidikan yang menganggur berhasil dihapus");
|
||||
await grafikBerdasarkanPendidikan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus grafik berdasarkan pendidikan yang menganggur");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus grafik berdasarkan pendidikan yang menganggur");
|
||||
} finally {
|
||||
grafikBerdasarkanPendidikan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const grafikNganggur = proxy({
|
||||
grafikBerdasarkanUsiaKerjaNganggur,
|
||||
grafikBerdasarkanPendidikan
|
||||
})
|
||||
|
||||
export default grafikNganggur;
|
||||
123
src/app/admin/(dashboard)/_state/inovasi/ajukan-ide-inovatif.ts
Normal file
123
src/app/admin/(dashboard)/_state/inovasi/ajukan-ide-inovatif.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
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).max(50),
|
||||
deskripsi: z.string().min(1).max(5000),
|
||||
alamat: z.string().min(1).max(5000),
|
||||
namaIde: z.string().min(1).max(5000),
|
||||
masalah: z.string().min(1).max(5000),
|
||||
benefit: z.string().min(1).max(5000),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
alamat: "",
|
||||
namaIde: "",
|
||||
masalah: "",
|
||||
benefit: "",
|
||||
};
|
||||
|
||||
const ajukanIdeInovatifState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(ajukanIdeInovatifState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
ajukanIdeInovatifState.create.loading = true;
|
||||
const res = await ApiFetch.api.inovasi.ajukanideinovatif["create"].post(
|
||||
ajukanIdeInovatifState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
ajukanIdeInovatifState.findMany.load();
|
||||
return toast.success("Ajukan Ide Inovatif berhasil di kirim");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
ajukanIdeInovatifState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.AjukanIdeInovatifGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.inovasi.ajukanideinovatif["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
ajukanIdeInovatifState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.AjukanIdeInovatifGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/inovasi/ajukanideinovatif/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
ajukanIdeInovatifState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
ajukanIdeInovatifState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading ajukan ide inovatif:", error);
|
||||
ajukanIdeInovatifState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
ajukanIdeInovatifState.delete.loading = true;
|
||||
const response = await fetch(`/api/inovasi/ajukanideinovatif/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
toast.success(result.message || "Ajukan Ide Inovatif berhasil dihapus");
|
||||
await ajukanIdeInovatifState.findMany.load();
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus ajukan ide inovatif");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat menghapus ajukan ide inovatif");
|
||||
} finally {
|
||||
ajukanIdeInovatifState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
export default ajukanIdeInovatifState;
|
||||
216
src/app/admin/(dashboard)/_state/inovasi/desa-digital.ts
Normal file
216
src/app/admin/(dashboard)/_state/inovasi/desa-digital.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
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).max(50),
|
||||
deskripsi: z.string().min(1).max(5000),
|
||||
imageId: z.string().min(1).max(50),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const desaDigitalState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(desaDigitalState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
desaDigitalState.create.loading = true;
|
||||
const res = await ApiFetch.api.inovasi.desadigital["create"].post(
|
||||
desaDigitalState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
desaDigitalState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
desaDigitalState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DesaDigitalGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.inovasi.desadigital["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
desaDigitalState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.DesaDigitalGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/inovasi/desadigital/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
desaDigitalState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
desaDigitalState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading desa digital:", error);
|
||||
desaDigitalState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
desaDigitalState.delete.loading = true;
|
||||
const response = await fetch(`/api/inovasi/desadigital/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
toast.success(result.message || "Desa Digital berhasil dihapus");
|
||||
await desaDigitalState.findMany.load();
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus desa digital");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat menghapus desa digital");
|
||||
} finally {
|
||||
desaDigitalState.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/inovasi/desadigital/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
imageId: data.imageId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading desa digital:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(desaDigitalState.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
desaDigitalState.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/inovasi/desadigital/${desaDigitalState.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
deskripsi: this.form.deskripsi,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success("Berhasil update desa digital");
|
||||
await desaDigitalState.findMany.load();
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal update desa digital");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating desa digital:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update desa digital"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
desaDigitalState.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
desaDigitalState.edit.id = "";
|
||||
desaDigitalState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
export default desaDigitalState;
|
||||
216
src/app/admin/(dashboard)/_state/inovasi/info-tekno.ts
Normal file
216
src/app/admin/(dashboard)/_state/inovasi/info-tekno.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
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).max(50),
|
||||
deskripsi: z.string().min(1).max(5000),
|
||||
imageId: z.string().min(1).max(50),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const infoTeknoState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(infoTeknoState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
infoTeknoState.create.loading = true;
|
||||
const res = await ApiFetch.api.inovasi.infotekno["create"].post(
|
||||
infoTeknoState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
infoTeknoState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
infoTeknoState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.InfoTeknoGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.inovasi.infotekno["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
infoTeknoState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.InfoTeknoGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/inovasi/infotekno/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
infoTeknoState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
infoTeknoState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading desa digital:", error);
|
||||
infoTeknoState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
infoTeknoState.delete.loading = true;
|
||||
const response = await fetch(`/api/inovasi/infotekno/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
toast.success(result.message || "Info Tekno berhasil dihapus");
|
||||
await infoTeknoState.findMany.load();
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus info tekno");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat menghapus info tekno");
|
||||
} finally {
|
||||
infoTeknoState.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/inovasi/infotekno/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
imageId: data.imageId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading info tekno:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(infoTeknoState.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
infoTeknoState.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/inovasi/infotekno/${infoTeknoState.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
deskripsi: this.form.deskripsi,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success("Berhasil update info tekno");
|
||||
await infoTeknoState.findMany.load();
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal update info tekno");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating info tekno:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update info tekno"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
infoTeknoState.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
infoTeknoState.edit.id = "";
|
||||
infoTeknoState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
export default infoTeknoState;
|
||||
234
src/app/admin/(dashboard)/_state/inovasi/kolaborasi-inovasi.ts
Normal file
234
src/app/admin/(dashboard)/_state/inovasi/kolaborasi-inovasi.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
/* 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, "Nama minimal 1 karakter"),
|
||||
tahun: z.number().min(4, "Tahun minimal 4 karakter"),
|
||||
slug: z.string().min(1, "Deskripsi singkat minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
kolaborator: z.string().min(1, "Kolaborator minimal 1 karakter"),
|
||||
imageId: z.string().min(1, "Image ID minimal 1 karakter"),
|
||||
})
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
tahun: 0,
|
||||
slug: "",
|
||||
deskripsi: "",
|
||||
kolaborator: "",
|
||||
imageId: "",
|
||||
}
|
||||
|
||||
const kolaborasiInovasiState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(kolaborasiInovasiState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
kolaborasiInovasiState.create.loading = true;
|
||||
const res = await ApiFetch.api.inovasi.kolaborasiinovasi["create"].post(
|
||||
kolaborasiInovasiState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
kolaborasiInovasiState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
kolaborasiInovasiState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
// Change to arrow function
|
||||
kolaborasiInovasiState.findMany.loading = true; // Use the full path to access the property
|
||||
kolaborasiInovasiState.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.inovasi.kolaborasiinovasi["find-many"].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kolaborasiInovasiState.findMany.data = res.data.data || [];
|
||||
kolaborasiInovasiState.findMany.total = res.data.total || 0;
|
||||
kolaborasiInovasiState.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load grafik berdasarkan jenis kelamin:",
|
||||
res.data?.message
|
||||
);
|
||||
kolaborasiInovasiState.findMany.data = [];
|
||||
kolaborasiInovasiState.findMany.total = 0;
|
||||
kolaborasiInovasiState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik berdasarkan jenis kelamin:", error);
|
||||
kolaborasiInovasiState.findMany.data = [];
|
||||
kolaborasiInovasiState.findMany.total = 0;
|
||||
kolaborasiInovasiState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kolaborasiInovasiState.findMany.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/kolaborasiinovasi/${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,
|
||||
tahun: data.tahun,
|
||||
slug: data.slug,
|
||||
deskripsi: data.deskripsi,
|
||||
kolaborator: data.kolaborator,
|
||||
imageId: data.imageId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal mengambil data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kolaborasi inovasi:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(`/api/inovasi/kolaborasiinovasi/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await kolaborasiInovasiState.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data kolaborasi inovasi");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KolaborasiInovasiGetPayload<{
|
||||
include: { image: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/inovasi/kolaborasiinovasi/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kolaborasiInovasiState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
kolaborasiInovasiState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kolaborasi inovasi:", error);
|
||||
kolaborasiInovasiState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
kolaborasiInovasiState.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/inovasi/kolaborasiinovasi/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kolaborasi inovasi berhasil dihapus");
|
||||
await kolaborasiInovasiState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kolaborasi inovasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kolaborasi inovasi");
|
||||
} finally {
|
||||
kolaborasiInovasiState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default kolaborasiInovasiState;
|
||||
|
||||
803
src/app/admin/(dashboard)/_state/inovasi/layanan-online-desa.ts
Normal file
803
src/app/admin/(dashboard)/_state/inovasi/layanan-online-desa.ts
Normal file
@@ -0,0 +1,803 @@
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
// ========================================= ADMINISTRASI ONLINE ========================================= //
|
||||
const templateAdministrasiOnlineForm = z.object({
|
||||
name: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
alamat: z.string().min(1, "Alamat minimal 1 karakter"),
|
||||
nomorTelepon: z.string().min(1, "Nomor telepon minimal 1 karakter"),
|
||||
jenisLayananId: z.string().min(1, "Jenis layanan minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultAdministrasiOnlineForm = {
|
||||
name: "",
|
||||
alamat: "",
|
||||
nomorTelepon: "",
|
||||
jenisLayananId: "",
|
||||
};
|
||||
|
||||
const administrasiOnline = proxy({
|
||||
create: {
|
||||
form: { ...defaultAdministrasiOnlineForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateAdministrasiOnlineForm.safeParse(
|
||||
administrasiOnline.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
administrasiOnline.create.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.inovasi.layananonlinedesa.administrasionline[
|
||||
"create"
|
||||
].post(administrasiOnline.create.form);
|
||||
if (res.status === 200) {
|
||||
administrasiOnline.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
administrasiOnline.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.AdministrasiOnlineGetPayload<{
|
||||
include: {
|
||||
jenisLayanan: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
|
||||
async load(page = 1, limit = 10) {
|
||||
administrasiOnline.findMany.loading = true;
|
||||
administrasiOnline.findMany.page = page;
|
||||
try {
|
||||
const res =
|
||||
await ApiFetch.api.inovasi.layananonlinedesa.administrasionline[
|
||||
"find-many"
|
||||
].get({
|
||||
query: {
|
||||
page,
|
||||
limit,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
administrasiOnline.findMany.data = res.data.data ?? [];
|
||||
administrasiOnline.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch administrasi online paginated:", err);
|
||||
} finally {
|
||||
administrasiOnline.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.AdministrasiOnlineGetPayload<{
|
||||
include: {
|
||||
jenisLayanan: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/administrasionline/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
administrasiOnline.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch administrasi online:", res.statusText);
|
||||
administrasiOnline.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching administrasi online:", error);
|
||||
administrasiOnline.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
administrasiOnline.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/administrasionline/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Administrasi online berhasil dihapus"
|
||||
);
|
||||
await administrasiOnline.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus administrasi online");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus administrasi online");
|
||||
} finally {
|
||||
administrasiOnline.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= JENIS LAYANAN ========================================= //
|
||||
const templateJenisLayananForm = z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultJenisLayananForm = {
|
||||
nama: "",
|
||||
deskripsi: "",
|
||||
};
|
||||
|
||||
const jenisLayanan = proxy({
|
||||
create: {
|
||||
form: { ...defaultJenisLayananForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateJenisLayananForm.safeParse(jenisLayanan.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
jenisLayanan.create.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.inovasi.layananonlinedesa.administrasionline.jenislayanan[
|
||||
"create"
|
||||
].post(jenisLayanan.create.form);
|
||||
if (res.status === 200) {
|
||||
jenisLayanan.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
jenisLayanan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
nama: string;
|
||||
deskripsi: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.inovasi.layananonlinedesa.administrasionline.jenislayanan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
jenisLayanan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.JenisLayananGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/administrasionline/jenislayanan/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
jenisLayanan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
jenisLayanan.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
jenisLayanan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
jenisLayanan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/administrasionline/jenislayanan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Jenis layanan berhasil dihapus");
|
||||
await jenisLayanan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus jenis layanan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus jenis layanan");
|
||||
} finally {
|
||||
jenisLayanan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultJenisLayananForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/administrasionline/jenislayanan/${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,
|
||||
deskripsi: data.deskripsi,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading jenis layanan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateJenisLayananForm.safeParse(jenisLayanan.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
jenisLayanan.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/administrasionline/jenislayanan/${jenisLayanan.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: jenisLayanan.edit.form.nama,
|
||||
deskripsi: jenisLayanan.edit.form.deskripsi,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Clone the response to avoid 'body already read' error
|
||||
const responseClone = response.clone();
|
||||
|
||||
try {
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
"Update failed with status:",
|
||||
response.status,
|
||||
"Response:",
|
||||
result
|
||||
);
|
||||
throw new Error(
|
||||
result?.message ||
|
||||
`Gagal mengupdate jenis layanan (${response.status})`
|
||||
);
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
toast.success(
|
||||
result.message || "Berhasil memperbarui jenis layanan"
|
||||
);
|
||||
await jenisLayanan.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate jenis layanan");
|
||||
}
|
||||
} catch (error) {
|
||||
// If JSON parsing fails, try to get the response text for better error messages
|
||||
try {
|
||||
const text = await responseClone.text();
|
||||
console.error("Error response text:", text);
|
||||
throw new Error(`Gagal memproses respons dari server: ${text}`);
|
||||
} catch (textError) {
|
||||
console.error("Error parsing response as text:", textError);
|
||||
console.error("Original error:", error);
|
||||
throw new Error("Gagal memproses respons dari server");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating jenis layanan:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate jenis layanan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
jenisLayanan.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
jenisLayanan.edit.id = "";
|
||||
jenisLayanan.edit.form = { ...defaultJenisLayananForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= PENGADUAN MASYARAKAT ========================================= //
|
||||
const templatePengaduanMasyarakatForm = z.object({
|
||||
name: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
email: z.string().min(1, "Alamat minimal 1 karakter"),
|
||||
nomorTelepon: z.string().min(1, "Nomor telepon minimal 1 karakter"),
|
||||
nik: z.string().min(1, "NIK minimal 1 karakter"),
|
||||
judulPengaduan: z.string().min(1, "Judul pengaduan minimal 1 karakter"),
|
||||
lokasiKejadian: z.string().min(1, "Lokasi kejadian minimal 1 karakter"),
|
||||
deskripsiPengaduan: z.string().min(1, "Deskripsi pengaduan minimal 1 karakter"),
|
||||
jenisPengaduanId: z.string().min(1, "Jenis pengaduan minimal 1 karakter"),
|
||||
imageId: z.string().min(1, "Image minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultPengaduanMasyarakatForm = {
|
||||
name: "",
|
||||
email: "",
|
||||
nomorTelepon: "",
|
||||
nik: "",
|
||||
judulPengaduan: "",
|
||||
lokasiKejadian: "",
|
||||
deskripsiPengaduan: "",
|
||||
jenisPengaduanId: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const pengaduanMasyarakat = proxy({
|
||||
create: {
|
||||
form: { ...defaultPengaduanMasyarakatForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templatePengaduanMasyarakatForm.safeParse(
|
||||
pengaduanMasyarakat.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
pengaduanMasyarakat.create.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.inovasi.layananonlinedesa.pengaduanmasyarakat[
|
||||
"create"
|
||||
].post(pengaduanMasyarakat.create.form);
|
||||
if (res.status === 200) {
|
||||
pengaduanMasyarakat.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
pengaduanMasyarakat.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.PengaduanMasyarakatGetPayload<{
|
||||
include: {
|
||||
jenisPengaduan: true;
|
||||
image: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
|
||||
async load(page = 1, limit = 10) {
|
||||
pengaduanMasyarakat.findMany.loading = true;
|
||||
pengaduanMasyarakat.findMany.page = page;
|
||||
try {
|
||||
const res =
|
||||
await ApiFetch.api.inovasi.layananonlinedesa.pengaduanmasyarakat[
|
||||
"find-many"
|
||||
].get({
|
||||
query: {
|
||||
page,
|
||||
limit,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pengaduanMasyarakat.findMany.data = res.data.data ?? [];
|
||||
pengaduanMasyarakat.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch pengaduan masyarakat paginated:", err);
|
||||
} finally {
|
||||
pengaduanMasyarakat.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.PengaduanMasyarakatGetPayload<{
|
||||
include: {
|
||||
jenisPengaduan: true;
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/pengaduanmasyarakat/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
pengaduanMasyarakat.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch pengaduan masyarakat:", res.statusText);
|
||||
pengaduanMasyarakat.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching pengaduan masyarakat:", error);
|
||||
pengaduanMasyarakat.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
pengaduanMasyarakat.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/pengaduanmasyarakat/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Pengaduan masyarakat berhasil dihapus"
|
||||
);
|
||||
await pengaduanMasyarakat.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus pengaduan masyarakat");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus pengaduan masyarakat");
|
||||
} finally {
|
||||
pengaduanMasyarakat.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
// ========================================= JENIS PENGADUAN ========================================= //
|
||||
const templateJenisPengaduanForm = z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultJenisPengaduanForm = {
|
||||
nama: "",
|
||||
};
|
||||
|
||||
const jenisPengaduan = proxy({
|
||||
create: {
|
||||
form: { ...defaultJenisPengaduanForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateJenisPengaduanForm.safeParse(jenisPengaduan.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
jenisPengaduan.create.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.inovasi.layananonlinedesa.pengaduanmasyarakat.jenispengaduan[
|
||||
"create"
|
||||
].post(jenisPengaduan.create.form);
|
||||
if (res.status === 200) {
|
||||
jenisPengaduan.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
jenisPengaduan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
nama: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res =
|
||||
await ApiFetch.api.inovasi.layananonlinedesa.pengaduanmasyarakat.jenispengaduan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
jenisPengaduan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.JenisPengaduanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/pengaduanmasyarakat/jenispengaduan/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
jenisPengaduan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
jenisPengaduan.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
jenisPengaduan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
jenisPengaduan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/pengaduanmasyarakat/jenispengaduan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Jenis pengduan berhasil dihapus");
|
||||
await jenisPengaduan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus jenis pengaduan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus jenis pengaduan");
|
||||
} finally {
|
||||
jenisPengaduan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultJenisPengaduanForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/pengaduanmasyarakat/jenispengaduan/${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
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading jenis pengaduan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateJenisPengaduanForm.safeParse(jenisPengaduan.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
jenisPengaduan.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/inovasi/layananonlinedesa/pengaduanmasyarakat/jenispengaduan/${jenisPengaduan.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: jenisPengaduan.edit.form.nama,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Clone the response to avoid 'body already read' error
|
||||
const responseClone = response.clone();
|
||||
|
||||
try {
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
"Update failed with status:",
|
||||
response.status,
|
||||
"Response:",
|
||||
result
|
||||
);
|
||||
throw new Error(
|
||||
result?.message ||
|
||||
`Gagal mengupdate jenis pengaduan (${response.status})`
|
||||
);
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
toast.success(
|
||||
result.message || "Berhasil memperbarui jenis pengaduan"
|
||||
);
|
||||
await jenisPengaduan.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate jenis pengaduan");
|
||||
}
|
||||
} catch (error) {
|
||||
// If JSON parsing fails, try to get the response text for better error messages
|
||||
try {
|
||||
const text = await responseClone.text();
|
||||
console.error("Error response text:", text);
|
||||
throw new Error(`Gagal memproses respons dari server: ${text}`);
|
||||
} catch (textError) {
|
||||
console.error("Error parsing response as text:", textError);
|
||||
console.error("Original error:", error);
|
||||
throw new Error("Gagal memproses respons dari server");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating jenis pengaduan:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate jenis pengaduan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
jenisPengaduan.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
jenisPengaduan.edit.id = "";
|
||||
jenisPengaduan.edit.form = { ...defaultJenisPengaduanForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const layananonlineDesa = proxy({
|
||||
administrasiOnline,
|
||||
jenisLayanan,
|
||||
pengaduanMasyarakat,
|
||||
jenisPengaduan,
|
||||
});
|
||||
|
||||
export default layananonlineDesa;
|
||||
227
src/app/admin/(dashboard)/_state/inovasi/program-kreatif.ts
Normal file
227
src/app/admin/(dashboard)/_state/inovasi/program-kreatif.ts
Normal file
@@ -0,0 +1,227 @@
|
||||
/* 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, "Nama minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
slug: z.string().min(1, "Deskripsi singkat minimal 1 karakter"),
|
||||
icon: z.string().min(1, "Icon minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
slug: "",
|
||||
icon: "",
|
||||
};
|
||||
|
||||
const programKreatifState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(programKreatifState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
programKreatifState.create.loading = true;
|
||||
const res = await ApiFetch.api.inovasi.programkreatif["create"].post(
|
||||
programKreatifState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
programKreatifState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
programKreatifState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
// Change to arrow function
|
||||
programKreatifState.findMany.loading = true; // Use the full path to access the property
|
||||
programKreatifState.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.inovasi.programkreatif["find-many"].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
programKreatifState.findMany.data = res.data.data || [];
|
||||
programKreatifState.findMany.total = res.data.total || 0;
|
||||
programKreatifState.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load grafik berdasarkan jenis kelamin:",
|
||||
res.data?.message
|
||||
);
|
||||
programKreatifState.findMany.data = [];
|
||||
programKreatifState.findMany.total = 0;
|
||||
programKreatifState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik berdasarkan jenis kelamin:", error);
|
||||
programKreatifState.findMany.data = [];
|
||||
programKreatifState.findMany.total = 0;
|
||||
programKreatifState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
programKreatifState.findMany.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/programkreatif/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
slug: data.slug,
|
||||
icon: data.icon,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal mengambil data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading program kreatif:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(`/api/inovasi/programkreatif/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await programKreatifState.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data program kreatif");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.ProgramKreatifGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/inovasi/programkreatif/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
programKreatifState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
programKreatifState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading program kreatif:", error);
|
||||
programKreatifState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
programKreatifState.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/inovasi/programkreatif/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Program kreatif berhasil dihapus");
|
||||
await programKreatifState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus program kreatif");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus program kreatif");
|
||||
} finally {
|
||||
programKreatifState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default programKreatifState;
|
||||
232
src/app/admin/(dashboard)/_state/keamanan/keamanan-lingkungan.ts
Normal file
232
src/app/admin/(dashboard)/_state/keamanan/keamanan-lingkungan.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
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(3, "Nama minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const keamananLingkunganState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(keamananLingkunganState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
keamananLingkunganState.create.loading = true;
|
||||
const res = await ApiFetch.api.keamanan.keamananlingkungan[
|
||||
"create"
|
||||
].post(keamananLingkunganState.create.form);
|
||||
if (res.status === 200) {
|
||||
keamananLingkunganState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
keamananLingkunganState.create.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
keamananLingkunganState.create.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.KeamananLingkunganGetPayload<{
|
||||
include: { image: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.keamananlingkungan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
keamananLingkunganState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KeamananLingkunganGetPayload<{
|
||||
include: { image: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/keamanan/keamananlingkungan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
keamananLingkunganState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
keamananLingkunganState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
keamananLingkunganState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
keamananLingkunganState.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/keamanan/keamananlingkungan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Keamanan ingkungan berhasil dihapus"
|
||||
);
|
||||
await keamananLingkunganState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus keamanan ingkungan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus keamanan ingkungan");
|
||||
} finally {
|
||||
keamananLingkunganState.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/keamanan/keamananlingkungan/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
imageId: data.imageId || "",
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading keamanan lingkungan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(keamananLingkunganState.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
keamananLingkunganState.edit.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/keamanan/keamananlingkungan/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
deskripsi: this.form.deskripsi,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
toast.success("Berhasil update keamanan lingkungan");
|
||||
await keamananLingkunganState.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update keamanan lingkungan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating keamanan lingkungan:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update keamanan lingkungan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
keamananLingkunganState.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
keamananLingkunganState.edit.id = "";
|
||||
keamananLingkunganState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default keamananLingkunganState;
|
||||
@@ -0,0 +1,259 @@
|
||||
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({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
kontakItems: z.array(
|
||||
z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
nomorTelepon: z.string().min(1, "Nomor Telepon minimal 1 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
nama: "",
|
||||
imageId: "",
|
||||
kontakItems: [
|
||||
{
|
||||
nama: "",
|
||||
nomorTelepon: "",
|
||||
imageId: "",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const kontakDaruratKeamananState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(
|
||||
kontakDaruratKeamananState.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
kontakDaruratKeamananState.create.loading = true;
|
||||
const res = await ApiFetch.api.keamanan.kontakdaruratkeamanan[
|
||||
"create"
|
||||
].post(kontakDaruratKeamananState.create.form);
|
||||
if (res.status === 200) {
|
||||
kontakDaruratKeamananState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
kontakDaruratKeamananState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.KontakDaruratKeamananGetPayload<{
|
||||
include: {
|
||||
kontakItems: true;
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.kontakdaruratkeamanan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
kontakDaruratKeamananState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KontakDaruratKeamananGetPayload<{
|
||||
include: {
|
||||
kontakItems: {
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
};
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/keamanan/kontakdaruratkeamanan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kontakDaruratKeamananState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
kontakDaruratKeamananState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
kontakDaruratKeamananState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
kontakDaruratKeamananState.delete.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/kontakdaruratkeamanan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kontak darurat berhasil dihapus");
|
||||
await kontakDaruratKeamananState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kontak darurat");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kontak darurat");
|
||||
} finally {
|
||||
kontakDaruratKeamananState.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/keamanan/kontakdaruratkeamanan/${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,
|
||||
imageId: data.imageId,
|
||||
kontakItems: [
|
||||
{
|
||||
nama: data.kontakItems.nama,
|
||||
nomorTelepon: data.kontakItems.nomorTelepon,
|
||||
imageId: data.kontakItems.imageId,
|
||||
},
|
||||
],
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kontak darurat:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(
|
||||
kontakDaruratKeamananState.update.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
kontakDaruratKeamananState.update.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/kontakdaruratkeamanan/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
imageId: this.form.imageId,
|
||||
kontakItems: [
|
||||
{
|
||||
nama: this.form.kontakItems[0].nama,
|
||||
nomorTelepon: this.form.kontakItems[0].nomorTelepon,
|
||||
imageId: this.form.kontakItems[0].imageId,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
);
|
||||
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 darurat");
|
||||
await kontakDaruratKeamananState.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate kontak darurat");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating kontak darurat:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate kontak darurat"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
kontakDaruratKeamananState.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
kontakDaruratKeamananState.update.id = "";
|
||||
kontakDaruratKeamananState.update.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default kontakDaruratKeamananState;
|
||||
273
src/app/admin/(dashboard)/_state/keamanan/laporan-publik.ts
Normal file
273
src/app/admin/(dashboard)/_state/keamanan/laporan-publik.ts
Normal file
@@ -0,0 +1,273 @@
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
export type Status = "Selesai" | "Proses" | "Gagal";
|
||||
|
||||
const templateForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
lokasi: z.string().min(3, "Lokasi 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(),
|
||||
});
|
||||
|
||||
interface FormData {
|
||||
judul: string;
|
||||
lokasi: string;
|
||||
tanggalWaktu: string;
|
||||
status: Status;
|
||||
penanganan: string;
|
||||
kronologi: string;
|
||||
}
|
||||
|
||||
const defaultForm: FormData = {
|
||||
judul: "",
|
||||
lokasi: "",
|
||||
tanggalWaktu: new Date().toISOString(),
|
||||
status: "Proses",
|
||||
penanganan: "",
|
||||
kronologi: "",
|
||||
};
|
||||
|
||||
const laporanPublikState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(laporanPublikState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
laporanPublikState.create.loading = true;
|
||||
|
||||
// Ensure we have a valid date
|
||||
if (!laporanPublikState.create.form.tanggalWaktu) {
|
||||
return toast.error("Tanggal laporan harus diisi");
|
||||
}
|
||||
|
||||
// Format the data before sending
|
||||
const formData = {
|
||||
...laporanPublikState.create.form,
|
||||
// Ensure the date is in the correct format for the API
|
||||
tanggalWaktu: new Date(laporanPublikState.create.form.tanggalWaktu).toISOString()
|
||||
};
|
||||
|
||||
console.log("Sending form data:", formData); // Debug log
|
||||
|
||||
const res = await ApiFetch.api.keamanan.laporanpublik["create"].post(
|
||||
formData
|
||||
);
|
||||
|
||||
if (res.error) {
|
||||
console.error("API Error:", res.error);
|
||||
throw new Error("Failed to create laporan publik");
|
||||
}
|
||||
|
||||
if (res.status === 200) {
|
||||
laporanPublikState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.error("Error creating laporan publik:", error);
|
||||
toast.error(error instanceof Error ? error.message : "Gagal membuat laporan publik");
|
||||
throw error; // Re-throw to be handled by the caller
|
||||
} finally {
|
||||
laporanPublikState.create.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
laporanPublikState.create.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.LaporanPublikGetPayload<{
|
||||
include: { penanganan: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.laporanpublik["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
laporanPublikState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.LaporanPublikGetPayload<{
|
||||
include: { penanganan: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/keamanan/laporanpublik/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
laporanPublikState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
laporanPublikState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
laporanPublikState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
laporanPublikState.findUnique.data = null;
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
laporanPublikState.delete.loading = true;
|
||||
const response = await fetch(`/api/keamanan/laporanpublik/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Laporan publik berhasil dihapus"
|
||||
);
|
||||
await laporanPublikState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus laporan publik");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus laporan publik");
|
||||
} finally {
|
||||
laporanPublikState.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/keamanan/laporanpublik/${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,
|
||||
lokasi: data.lokasi,
|
||||
tanggalWaktu: data.tanggalWaktu,
|
||||
status: data.status,
|
||||
penanganan: data.penanganan,
|
||||
kronologi: data.kronologi,
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading keamanan lingkungan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(laporanPublikState.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
laporanPublikState.edit.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/keamanan/laporanpublik/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
judul: this.form.judul,
|
||||
lokasi: this.form.lokasi,
|
||||
tanggalWaktu: this.form.tanggalWaktu,
|
||||
status: this.form.status,
|
||||
penanganan: this.form.penanganan,
|
||||
kronologi: this.form.kronologi,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
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 laporan publik");
|
||||
await laporanPublikState.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update laporan publik");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating laporan publik:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update laporan publik"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
laporanPublikState.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
laporanPublikState.edit.id = "";
|
||||
laporanPublikState.edit.form = { ...defaultForm };
|
||||
},
|
||||
}
|
||||
});
|
||||
export default laporanPublikState;
|
||||
@@ -0,0 +1,314 @@
|
||||
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({
|
||||
pencegahanKriminalitas: z.object({
|
||||
programKeamanan: z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi 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 = {
|
||||
pencegahanKriminalitas: {
|
||||
programKeamanan: {
|
||||
nama: "",
|
||||
deskripsi: "",
|
||||
slug: "",
|
||||
},
|
||||
tipsKeamanan: {
|
||||
judul: "",
|
||||
konten: "",
|
||||
slug: "",
|
||||
},
|
||||
videoKeamanan: {
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
videoUrl: "",
|
||||
slug: "",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const pencegahanKriminalitasState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(
|
||||
pencegahanKriminalitasState.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
pencegahanKriminalitasState.create.loading = true;
|
||||
const res = await ApiFetch.api.keamanan.pencegahankriminalitas[
|
||||
"create"
|
||||
].post(pencegahanKriminalitasState.create.form.pencegahanKriminalitas);
|
||||
if (res.status === 200) {
|
||||
pencegahanKriminalitasState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
pencegahanKriminalitasState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PencegahanKriminalitasGetPayload<{
|
||||
include: {
|
||||
programKeamanan: true;
|
||||
tipsKeamanan: true;
|
||||
videoKeamanan: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.pencegahankriminalitas[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
pencegahanKriminalitasState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.PencegahanKriminalitasGetPayload<{
|
||||
include: {
|
||||
programKeamanan: true;
|
||||
tipsKeamanan: true;
|
||||
videoKeamanan: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/keamanan/pencegahankriminalitas/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
pencegahanKriminalitasState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
pencegahanKriminalitasState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
pencegahanKriminalitasState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
pencegahanKriminalitasState.delete.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/pencegahankriminalitas/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Pencegahan kriminalitas berhasil dihapus"
|
||||
);
|
||||
await pencegahanKriminalitasState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(
|
||||
result?.message || "Gagal menghapus pencegahan kriminalitas"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus pencegahan kriminalitas");
|
||||
} finally {
|
||||
pencegahanKriminalitasState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
pencegahanKriminalitasState.update.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/pencegahankriminalitas/${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;
|
||||
pencegahanKriminalitasState.update.id = data.id;
|
||||
pencegahanKriminalitasState.update.form = {
|
||||
pencegahanKriminalitas: {
|
||||
programKeamanan: {
|
||||
nama: data.programKeamanan.nama,
|
||||
deskripsi: data.programKeamanan.deskripsi,
|
||||
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;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal update:", error);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat mengupdate pencegahan kriminalitas"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(
|
||||
pencegahanKriminalitasState.update.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pencegahanKriminalitasState.update.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/pencegahankriminalitas/${pencegahanKriminalitasState.update.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
pencegahanKriminalitas: {
|
||||
programKeamanan: {
|
||||
nama: pencegahanKriminalitasState.update.form
|
||||
.pencegahanKriminalitas.programKeamanan.nama,
|
||||
deskripsi:
|
||||
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,
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
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 pencegahan kriminalitas");
|
||||
await pencegahanKriminalitasState.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate pencegahan kriminalitas"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal update:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate pencegahan kriminalitas"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
pencegahanKriminalitasState.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
pencegahanKriminalitasState.update.id = "";
|
||||
pencegahanKriminalitasState.update.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
export default pencegahanKriminalitasState;
|
||||
242
src/app/admin/(dashboard)/_state/keamanan/polsek-terdekat.ts
Normal file
242
src/app/admin/(dashboard)/_state/keamanan/polsek-terdekat.ts
Normal file
@@ -0,0 +1,242 @@
|
||||
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({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
jarakKeDesa: z.string().min(1, "Jarak minimal 1 karakter"),
|
||||
alamat: z.string().min(1, "Alamat minimal 1 karakter"),
|
||||
nomorTelepon: z.string().min(1, "Nomor Telepon minimal 1 karakter"),
|
||||
jamOperasional: z.string().min(1, "Jam Operasional minimal 1 karakter"),
|
||||
embedMapUrl: z.string().min(1, "Embed Map Url minimal 1 karakter"),
|
||||
namaTempatMaps: z.string().min(1, "Nama Tempat Maps minimal 1 karakter"),
|
||||
alamatMaps: z.string().min(1, "Alamat Maps minimal 1 karakter"),
|
||||
linkPetunjukArah: z.string().min(1, "Link Petunjuk Arah minimal 1 karakter"),
|
||||
layananPolsekId: z.string().min(1, "Layanan Polsek Id minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
nama: "",
|
||||
jarakKeDesa: "",
|
||||
alamat: "",
|
||||
nomorTelepon: "",
|
||||
jamOperasional: "",
|
||||
embedMapUrl: "",
|
||||
namaTempatMaps: "",
|
||||
alamatMaps: "",
|
||||
linkPetunjukArah: "",
|
||||
layananPolsekId: "",
|
||||
};
|
||||
|
||||
const polsekTerdekatState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(polsekTerdekatState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
polsekTerdekatState.create.loading = true;
|
||||
const res = await ApiFetch.api.keamanan.polsekterdekat["create"].post(
|
||||
polsekTerdekatState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
polsekTerdekatState.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
polsekTerdekatState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PolsekTerdekatGetPayload<{
|
||||
include: { layananPolsek: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.polsekterdekat["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
polsekTerdekatState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.PolsekTerdekatGetPayload<{
|
||||
include: { layananPolsek: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/keamanan/polsekterdekat/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
polsekTerdekatState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
polsekTerdekatState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
polsekTerdekatState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
polsekTerdekatState.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/keamanan/polsekterdekat/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Polsek terdekat berhasil dihapus");
|
||||
await polsekTerdekatState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus polsek terdekat");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus polsek terdekat");
|
||||
} finally {
|
||||
polsekTerdekatState.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/keamanan/polsekterdekat/${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,
|
||||
jarakKeDesa: data.jarakKeDesa,
|
||||
alamat: data.alamat,
|
||||
nomorTelepon: data.nomorTelepon,
|
||||
jamOperasional: data.jamOperasional,
|
||||
embedMapUrl: data.embedMapUrl,
|
||||
namaTempatMaps: data.namaTempatMaps,
|
||||
alamatMaps: data.alamatMaps,
|
||||
linkPetunjukArah: data.linkPetunjukArah,
|
||||
layananPolsekId: data.layananPolsekId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading polsek terdekat:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(polsekTerdekatState.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
polsekTerdekatState.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/polsekterdekat/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
jarakKeDesa: this.form.jarakKeDesa,
|
||||
alamat: this.form.alamat,
|
||||
nomorTelepon: this.form.nomorTelepon,
|
||||
jamOperasional: this.form.jamOperasional,
|
||||
embedMapUrl: this.form.embedMapUrl,
|
||||
namaTempatMaps: this.form.namaTempatMaps,
|
||||
alamatMaps: this.form.alamatMaps,
|
||||
linkPetunjukArah: this.form.linkPetunjukArah,
|
||||
layananPolsekId: this.form.layananPolsekId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
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 polsek terdekat");
|
||||
await polsekTerdekatState.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate polsek terdekat");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating polsek terdekat:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate polsek terdekat"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
polsekTerdekatState.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
polsekTerdekatState.edit.id = "";
|
||||
polsekTerdekatState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default polsekTerdekatState;
|
||||
212
src/app/admin/(dashboard)/_state/keamanan/tips-keamanan.ts
Normal file
212
src/app/admin/(dashboard)/_state/keamanan/tips-keamanan.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
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({
|
||||
judul: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const tipsKeamananState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(tipsKeamananState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
tipsKeamananState.create.loading = true;
|
||||
const res = await ApiFetch.api.keamanan.menutipskeamanan["create"].post(
|
||||
tipsKeamananState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
tipsKeamananState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
tipsKeamananState.create.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
tipsKeamananState.create.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.MenuTipsKeamananGetPayload<{
|
||||
include: { image: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.keamanan.menutipskeamanan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
tipsKeamananState.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.MenuTipsKeamananGetPayload<{
|
||||
include: { image: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/keamanan/menutipskeamanan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
tipsKeamananState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
tipsKeamananState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
tipsKeamananState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
tipsKeamananState.delete.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/menutipskeamanan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const result = await response.json();
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Tips keamanan berhasil dihapus");
|
||||
await tipsKeamananState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus tips keamanan");
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error("Terjadi kesalahan saat menghapus tips keamanan");
|
||||
console.error("Gagal delete:", error);
|
||||
} finally {
|
||||
tipsKeamananState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
loading: false,
|
||||
form: { ...defaultForm },
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
tipsKeamananState.update.loading = true;
|
||||
const response = await fetch(`/api/keamanan/menutipskeamanan/${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,
|
||||
imageId: data.imageId || "",
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
toast.error("Gagal memuat data");
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templateForm.safeParse(tipsKeamananState.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
tipsKeamananState.update.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/keamanan/menutipskeamanan/${tipsKeamananState.update.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
judul: this.form.judul,
|
||||
deskripsi: this.form.deskripsi,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
toast.success("Berhasil update tips keamanan");
|
||||
await tipsKeamananState.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update tips keamanan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating data:", error);
|
||||
toast.error("Gagal update data");
|
||||
return false;
|
||||
} finally {
|
||||
tipsKeamananState.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
tipsKeamananState.update.id = "";
|
||||
tipsKeamananState.update.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
export default tipsKeamananState;
|
||||
@@ -1,339 +1,306 @@
|
||||
/* 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";
|
||||
|
||||
/* Introduction */
|
||||
const templateIntroduction = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
const templateForm = z.object({
|
||||
title: z.string().min(1, "Judul harus diisi"),
|
||||
content: z.string().min(1, "Content harus diisi"),
|
||||
introduction: z.object({
|
||||
content: z.string().min(1, "Content harus diisi"),
|
||||
}),
|
||||
symptom: z.object({
|
||||
title: z.string().min(1, "Judul harus diisi"),
|
||||
content: z.string().min(1, "Content harus diisi"),
|
||||
}),
|
||||
prevention: z.object({
|
||||
title: z.string().min(1, "Judul harus diisi"),
|
||||
content: z.string().min(1, "Content harus diisi"),
|
||||
}),
|
||||
firstAid: z.object({
|
||||
title: z.string().min(1, "Judul harus diisi"),
|
||||
content: z.string().min(1, "Content harus diisi"),
|
||||
}),
|
||||
mythVsFact: z.object({
|
||||
title: z.string().min(1, "Judul harus diisi"),
|
||||
mitos: z.string().min(1, "Mitos harus diisi"),
|
||||
fakta: z.string().min(1, "Fakta harus diisi"),
|
||||
}),
|
||||
doctorSign: z.object({
|
||||
content: z.string().min(1, "Content harus diisi"),
|
||||
}),
|
||||
});
|
||||
|
||||
type Introduction = Prisma.IntroductionGetPayload<{
|
||||
select: {
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
const defaultForm = {
|
||||
title: "",
|
||||
content: "",
|
||||
introduction: {
|
||||
content: "",
|
||||
},
|
||||
symptom: {
|
||||
title: "",
|
||||
content: "",
|
||||
},
|
||||
prevention: {
|
||||
title: "",
|
||||
content: "",
|
||||
},
|
||||
firstAid: {
|
||||
title: "",
|
||||
content: "",
|
||||
},
|
||||
mythVsFact: {
|
||||
title: "",
|
||||
mitos: "",
|
||||
fakta: "",
|
||||
},
|
||||
doctorSign: {
|
||||
content: "",
|
||||
},
|
||||
};
|
||||
|
||||
const introduction = proxy({
|
||||
const artikelKesehatanState = proxy({
|
||||
create: {
|
||||
form: {} as Introduction,
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateIntroduction.safeParse(introduction.create.form);
|
||||
async submit() {
|
||||
const cek = templateForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
const errMsg = cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
.join("\n");
|
||||
toast.error(errMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
introduction.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.introduction["create"].post(introduction.create.form);
|
||||
this.loading = true;
|
||||
const payload = { ...this.form };
|
||||
|
||||
const res = await (ApiFetch.api.kesehatan as any)[
|
||||
"artikel-kesehatan"
|
||||
].create.post(payload);
|
||||
|
||||
if (res.status === 200) {
|
||||
introduction.findMany.load();
|
||||
return toast.success("success create");
|
||||
toast.success("Berhasil menambahkan artikel kesehatan");
|
||||
this.resetForm();
|
||||
await artikelKesehatanState.findMany.load();
|
||||
return res.data;
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} catch (err: any) {
|
||||
const msg = err?.message || "Terjadi kesalahan saat mengirim data";
|
||||
toast.error(msg);
|
||||
console.error("SUBMIT ERROR:", err);
|
||||
return null;
|
||||
} finally {
|
||||
introduction.create.loading = false;
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.IntroductionGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.introduction["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
introduction.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* symptom */
|
||||
const templateSymptom = z.object({
|
||||
title: z.string().min(3, "Title minimal 3 karakter"),
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type Symptom = Prisma.SymptomGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const symptom = proxy({
|
||||
create: {
|
||||
form: {} as Symptom,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateSymptom.safeParse(symptom.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
symptom.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.symptom["create"].post(symptom.create.form);
|
||||
if (res.status === 200) {
|
||||
symptom.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
symptom.create.loading = false;
|
||||
}
|
||||
resetForm() {
|
||||
this.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.SymptomGetPayload<{ omit: { isActive: true } }>[]
|
||||
| Prisma.ArtikelKesehatanGetPayload<{
|
||||
include: {
|
||||
introduction: true;
|
||||
symptom: true;
|
||||
prevention: true;
|
||||
firstaid: true;
|
||||
mythvsfact: true;
|
||||
doctorsign: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.symptom["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
symptom.findMany.data = res.data?.data ?? [];
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await (ApiFetch.api.kesehatan as any)["artikel-kesehatan"][
|
||||
"find-many"
|
||||
].get();
|
||||
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
} else {
|
||||
toast.error("Gagal memuat data artikel kesehatan");
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
toast.error("Terjadi error saat load data");
|
||||
console.error("LOAD ERROR:", err);
|
||||
throw err;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.ArtikelKesehatanGetPayload<{
|
||||
include: {
|
||||
introduction: true;
|
||||
symptom: true;
|
||||
prevention: true;
|
||||
firstaid: true;
|
||||
mythvsfact: true;
|
||||
doctorsign: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
const res = await fetch(`/api/kesehatan/artikel-kesehatan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
artikelKesehatanState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal load data artikel kesehatan");
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
const res = await fetch(`/api/kesehatan/artikel-kesehatan/${id}`);
|
||||
if (!res.ok) {
|
||||
toast.error("Gagal load data artikel kesehatan");
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await res.json();
|
||||
const data = result.data;
|
||||
|
||||
artikelKesehatanState.edit.id = data.id;
|
||||
artikelKesehatanState.edit.form = {
|
||||
title: data.title,
|
||||
content: data.content,
|
||||
introduction: {
|
||||
content: data.introduction.content,
|
||||
},
|
||||
symptom: {
|
||||
title: data.symptom.title,
|
||||
content: data.symptom.content,
|
||||
},
|
||||
prevention: {
|
||||
title: data.prevention.title,
|
||||
content: data.prevention.content,
|
||||
},
|
||||
firstAid: {
|
||||
title: data.firstaid.title,
|
||||
content: data.firstaid.content,
|
||||
},
|
||||
mythVsFact: {
|
||||
title: data.mythvsfact.title,
|
||||
mitos: data.mythvsfact.mitos,
|
||||
fakta: data.mythvsfact.fakta,
|
||||
},
|
||||
doctorSign: {
|
||||
content: data.doctorsign.content,
|
||||
},
|
||||
};
|
||||
},
|
||||
async submit() {
|
||||
const cek = templateForm.safeParse(artikelKesehatanState.edit.form);
|
||||
if (!cek.success) {
|
||||
const errMsg = cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
.join("\n");
|
||||
toast.error(errMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
artikelKesehatanState.edit.loading = true;
|
||||
const payload = {
|
||||
title: artikelKesehatanState.edit.form.title,
|
||||
content: artikelKesehatanState.edit.form.content,
|
||||
introduction: {
|
||||
content: artikelKesehatanState.edit.form.introduction.content,
|
||||
},
|
||||
symptom: {
|
||||
title: artikelKesehatanState.edit.form.symptom.title,
|
||||
content: artikelKesehatanState.edit.form.symptom.content,
|
||||
},
|
||||
prevention: {
|
||||
title: artikelKesehatanState.edit.form.prevention.title,
|
||||
content: artikelKesehatanState.edit.form.prevention.content,
|
||||
},
|
||||
firstAid: {
|
||||
title: artikelKesehatanState.edit.form.firstAid.title,
|
||||
content: artikelKesehatanState.edit.form.firstAid.content,
|
||||
},
|
||||
mythVsFact: {
|
||||
title: artikelKesehatanState.edit.form.mythVsFact.title,
|
||||
mitos: artikelKesehatanState.edit.form.mythVsFact.mitos,
|
||||
fakta: artikelKesehatanState.edit.form.mythVsFact.fakta,
|
||||
},
|
||||
doctorSign: {
|
||||
content: artikelKesehatanState.edit.form.doctorSign.content,
|
||||
},
|
||||
};
|
||||
|
||||
const res = await fetch(
|
||||
`/api/kesehatan/artikel-kesehatan/${artikelKesehatanState.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
}
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
const error = await res.json();
|
||||
throw new Error(error.message || "Update gagal");
|
||||
}
|
||||
|
||||
toast.success("Berhasil update artikel kesehatan");
|
||||
await artikelKesehatanState.findMany.load();
|
||||
return true;
|
||||
} catch (err) {
|
||||
toast.error(
|
||||
err instanceof Error ? err.message : "Terjadi kesalahan saat update"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
artikelKesehatanState.edit.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
artikelKesehatanState.edit.id = "";
|
||||
artikelKesehatanState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
try {
|
||||
artikelKesehatanState.delete.loading = true;
|
||||
const res = await fetch(
|
||||
`/api/kesehatan/artikel-kesehatan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
|
||||
const result = await res.json();
|
||||
if (res.ok && result.success) {
|
||||
toast.success("Artikel kesehatan berhasil dihapus");
|
||||
await artikelKesehatanState.findMany.load();
|
||||
} else {
|
||||
toast.error(result.message || "Gagal menghapus");
|
||||
}
|
||||
} catch {
|
||||
toast.error("Terjadi kesalahan saat menghapus");
|
||||
} finally {
|
||||
artikelKesehatanState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Prevention */
|
||||
const templatePrevention = z.object({
|
||||
title: z.string().min(3, "Title minimal 3 karakter"),
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type Prevention = Prisma.PreventionGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const prevention = proxy({
|
||||
create: {
|
||||
form: {} as Prevention,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templatePrevention.safeParse(prevention.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
prevention.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.prevention["create"].post(prevention.create.form);
|
||||
if (res.status === 200) {
|
||||
prevention.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
prevention.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PreventionGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.prevention["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
prevention.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* First Aid */
|
||||
const templateFirstAid = z.object({
|
||||
title: z.string().min(3, "Title minimal 3 karakter"),
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type FirstAid = Prisma.FirstAidGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const firstAid = proxy({
|
||||
create: {
|
||||
form: {} as FirstAid,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateFirstAid.safeParse(firstAid.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
firstAid.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.firstaid["create"].post(firstAid.create.form);
|
||||
if (res.status === 200) {
|
||||
firstAid.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
firstAid.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.FirstAidGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.firstaid["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
firstAid.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Myth vs Fact */
|
||||
const templateMythFact = z.object({
|
||||
title: z.string().min(3, "Title minimal 3 karakter"),
|
||||
mitos: z.string().min(3, "Mitos minimal 3 karakter"),
|
||||
fakta: z.string().min(3, "Fakta minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type MythFact = Prisma.MythVsFactGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
mitos: true;
|
||||
fakta: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const mythFact = proxy({
|
||||
create: {
|
||||
form: {} as MythFact,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateMythFact.safeParse(mythFact.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
mythFact.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.mythvsfact["create"].post(mythFact.create.form);
|
||||
if (res.status === 200) {
|
||||
mythFact.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
mythFact.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.MythVsFactGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.mythvsfact["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
mythFact.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Doctor Sign */
|
||||
const templateDoctorSign = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type DoctorSign = Prisma.DoctorSignGetPayload<{
|
||||
select: {
|
||||
content: true
|
||||
}
|
||||
}>
|
||||
|
||||
const doctorSign = proxy({
|
||||
create: {
|
||||
form: {} as DoctorSign,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDoctorSign.safeParse(doctorSign.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
doctorSign.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.doctor_sign["create"].post(doctorSign.create.form);
|
||||
if (res.status === 200) {
|
||||
doctorSign.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
doctorSign.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DoctorSignGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.doctor_sign["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
doctorSign.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
const stateArtikelKesehatan = proxy({
|
||||
introduction,
|
||||
symptom,
|
||||
prevention,
|
||||
firstAid,
|
||||
mythFact,
|
||||
doctorSign
|
||||
})
|
||||
|
||||
export default stateArtikelKesehatan
|
||||
export default artikelKesehatanState;
|
||||
|
||||
@@ -1,333 +1,308 @@
|
||||
/* 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";
|
||||
|
||||
/* Informasi Umum */
|
||||
const templateInformasiUmum = z.object({
|
||||
fasilitas: z.string().min(3, "Fasilitas minimal 3 karakter"),
|
||||
alamat: z.string().min(3, "Alamat minimal 3 karakter"),
|
||||
jamOperasional: z.string().min(3, "Jam Operasional minimal 3 karakter"),
|
||||
// Validasi form
|
||||
const templateForm = z.object({
|
||||
name: z.string().min(1, "Nama harus diisi"),
|
||||
informasiUmum: z.object({
|
||||
fasilitas: z.string().min(1, "Fasilitas harus diisi"),
|
||||
alamat: z.string().min(1, "Alamat harus diisi"),
|
||||
jamOperasional: z.string().min(1, "Jam operasional harus diisi"),
|
||||
}),
|
||||
layananUnggulan: z.object({
|
||||
content: z.string().min(1, "Layanan unggulan harus diisi"),
|
||||
}),
|
||||
dokterdanTenagaMedis: z.object({
|
||||
name: z.string().min(1, "Nama dokter harus diisi"),
|
||||
specialist: z.string().min(1, "Spesialis harus diisi"),
|
||||
jadwal: z.string().min(1, "Jadwal harus diisi"),
|
||||
}),
|
||||
fasilitasPendukung: z.object({
|
||||
content: z.string().min(1, "Fasilitas pendukung harus diisi"),
|
||||
}),
|
||||
prosedurPendaftaran: z.object({
|
||||
content: z.string().min(1, "Prosedur pendaftaran harus diisi"),
|
||||
}),
|
||||
tarifDanLayanan: z.object({
|
||||
layanan: z.string().min(1, "Layanan harus diisi"),
|
||||
tarif: z.string().min(1, "Tarif harus diisi"),
|
||||
}),
|
||||
});
|
||||
|
||||
type InfromasiUmum = Prisma.InformasiUmumGetPayload<{
|
||||
select: {
|
||||
fasilitas: true;
|
||||
alamat: true;
|
||||
jamOperasional: true;
|
||||
};
|
||||
}>;
|
||||
// Default form kosong
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
informasiUmum: {
|
||||
fasilitas: "",
|
||||
alamat: "",
|
||||
jamOperasional: "",
|
||||
},
|
||||
layananUnggulan: {
|
||||
content: "",
|
||||
},
|
||||
dokterdanTenagaMedis: {
|
||||
name: "",
|
||||
specialist: "",
|
||||
jadwal: "",
|
||||
},
|
||||
fasilitasPendukung: {
|
||||
content: "",
|
||||
},
|
||||
prosedurPendaftaran: {
|
||||
content: "",
|
||||
},
|
||||
tarifDanLayanan: {
|
||||
layanan: "",
|
||||
tarif: "",
|
||||
},
|
||||
};
|
||||
|
||||
const informasiumum = proxy({
|
||||
const fasilitasKesehatanState = proxy({
|
||||
create: {
|
||||
form: {} as InfromasiUmum,
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateInformasiUmum.safeParse(informasiumum.create.form);
|
||||
async submit() {
|
||||
const cek = templateForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
const errMsg = cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
.join("\n");
|
||||
toast.error(errMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
informasiumum.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.informasiumum["create"].post(
|
||||
informasiumum.create.form
|
||||
this.loading = true;
|
||||
const payload = { ...this.form };
|
||||
|
||||
const res = await (ApiFetch.api.kesehatan as any)[
|
||||
"fasilitas-kesehatan"
|
||||
].create.post(payload);
|
||||
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil menambahkan fasilitas kesehatan");
|
||||
this.resetForm();
|
||||
await fasilitasKesehatanState.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.FasilitasKesehatanGetPayload<{
|
||||
include: {
|
||||
informasiumum: true;
|
||||
layananunggulan: true;
|
||||
dokterdantenagamedis: true;
|
||||
fasilitaspendukung: true;
|
||||
prosedurpendaftaran: true;
|
||||
tarifdanlayanan: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const res = await (ApiFetch.api.kesehatan as any)[
|
||||
"fasilitas-kesehatan"
|
||||
]["find-many"].get();
|
||||
|
||||
if (res.status === 200) {
|
||||
this.data = res.data?.data ?? [];
|
||||
} else {
|
||||
toast.error("Gagal memuat data fasilitas kesehatan");
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
toast.error("Terjadi error saat load data");
|
||||
console.error("LOAD ERROR:", err);
|
||||
throw err;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.FasilitasKesehatanGetPayload<{
|
||||
include: {
|
||||
informasiumum: true;
|
||||
layananunggulan: true;
|
||||
dokterdantenagamedis: true;
|
||||
fasilitaspendukung: true;
|
||||
prosedurpendaftaran: true;
|
||||
tarifdanlayanan: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
const res = await fetch(`/api/kesehatan/fasilitas-kesehatan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
fasilitasKesehatanState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal load data fasilitas kesehatan");
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
const res = await fetch(`/api/kesehatan/fasilitas-kesehatan/${id}`);
|
||||
if (!res.ok) {
|
||||
toast.error("Gagal load data fasilitas kesehatan");
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await res.json();
|
||||
const data = result.data;
|
||||
|
||||
fasilitasKesehatanState.edit.id = data.id;
|
||||
fasilitasKesehatanState.edit.form = {
|
||||
name: data.name,
|
||||
informasiUmum: {
|
||||
fasilitas: data.informasiumum.fasilitas,
|
||||
alamat: data.informasiumum.alamat,
|
||||
jamOperasional: data.informasiumum.jamOperasional,
|
||||
},
|
||||
layananUnggulan: {
|
||||
content: data.layananunggulan.content,
|
||||
},
|
||||
dokterdanTenagaMedis: {
|
||||
name: data.dokterdantenagamedis.name,
|
||||
specialist: data.dokterdantenagamedis.specialist,
|
||||
jadwal: data.dokterdantenagamedis.jadwal,
|
||||
},
|
||||
fasilitasPendukung: {
|
||||
content: data.fasilitaspendukung.content,
|
||||
},
|
||||
prosedurPendaftaran: {
|
||||
content: data.prosedurpendaftaran.content,
|
||||
},
|
||||
tarifDanLayanan: {
|
||||
layanan: data.tarifdanlayanan.layanan,
|
||||
tarif: data.tarifdanlayanan.tarif,
|
||||
},
|
||||
};
|
||||
},
|
||||
async submit() {
|
||||
const cek = templateForm.safeParse(fasilitasKesehatanState.edit.form);
|
||||
if (!cek.success) {
|
||||
const errMsg = cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
.join("\n");
|
||||
toast.error(errMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
fasilitasKesehatanState.edit.loading = true;
|
||||
const payload = {
|
||||
name: fasilitasKesehatanState.edit.form.name,
|
||||
informasiUmum: {
|
||||
fasilitas:
|
||||
fasilitasKesehatanState.edit.form.informasiUmum.fasilitas,
|
||||
alamat: fasilitasKesehatanState.edit.form.informasiUmum.alamat,
|
||||
jamOperasional:
|
||||
fasilitasKesehatanState.edit.form.informasiUmum.jamOperasional,
|
||||
},
|
||||
layananUnggulan: {
|
||||
content: fasilitasKesehatanState.edit.form.layananUnggulan.content,
|
||||
},
|
||||
dokterdanTenagaMedis: {
|
||||
name: fasilitasKesehatanState.edit.form.dokterdanTenagaMedis.name,
|
||||
specialist:
|
||||
fasilitasKesehatanState.edit.form.dokterdanTenagaMedis.specialist,
|
||||
jadwal:
|
||||
fasilitasKesehatanState.edit.form.dokterdanTenagaMedis.jadwal,
|
||||
},
|
||||
fasilitasPendukung: {
|
||||
content:
|
||||
fasilitasKesehatanState.edit.form.fasilitasPendukung.content,
|
||||
},
|
||||
prosedurPendaftaran: {
|
||||
content:
|
||||
fasilitasKesehatanState.edit.form.prosedurPendaftaran.content,
|
||||
},
|
||||
tarifDanLayanan: {
|
||||
layanan: fasilitasKesehatanState.edit.form.tarifDanLayanan.layanan,
|
||||
tarif: fasilitasKesehatanState.edit.form.tarifDanLayanan.tarif,
|
||||
},
|
||||
};
|
||||
|
||||
const res = await fetch(
|
||||
`/api/kesehatan/fasilitas-kesehatan/${fasilitasKesehatanState.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
}
|
||||
);
|
||||
if (res.status === 200) {
|
||||
informasiumum.findMany.load();
|
||||
return toast.success("success create");
|
||||
|
||||
if (!res.ok) {
|
||||
const error = await res.json();
|
||||
throw new Error(error.message || "Update gagal");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
informasiumum.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.InformasiUmumGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.
|
||||
informasiumum["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
informasiumum.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Layanan Unggulan */
|
||||
const templateLayananUnggulanForm = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type LayananUnggulan = Prisma.LayananUnggulanGetPayload<{
|
||||
select: {
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const layananunggulan = proxy({
|
||||
create: {
|
||||
form: {} as LayananUnggulan,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateLayananUnggulanForm.safeParse(layananunggulan.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
layananunggulan.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.layananunggulan["create"].post(
|
||||
layananunggulan.create.form
|
||||
toast.success("Berhasil update fasilitas kesehatan");
|
||||
await fasilitasKesehatanState.findMany.load();
|
||||
return true;
|
||||
} catch (err) {
|
||||
toast.error(
|
||||
err instanceof Error ? err.message : "Terjadi kesalahan saat update"
|
||||
);
|
||||
if (res.status === 200) {
|
||||
layananunggulan.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
return false;
|
||||
} finally {
|
||||
layananunggulan.create.loading = false;
|
||||
fasilitasKesehatanState.edit.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.LayananUnggulanGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.
|
||||
layananunggulan["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
layananunggulan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
resetForm() {
|
||||
fasilitasKesehatanState.edit.id = "";
|
||||
fasilitasKesehatanState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
})
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Dokter dan Tenaga Medis */
|
||||
const templateDokterdanTenagaMedis = z.object({
|
||||
name: z.string().min(3, "Name minimal 3 karakter"),
|
||||
specialist: z.string().min(3, "Specialist minimal 3 karakter"),
|
||||
jadwal: z.string().min(3, "Jadwal minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type DokterdanTenagaMedis = Prisma.DokterdanTenagaMedisGetPayload<{
|
||||
select: {
|
||||
name: true;
|
||||
specialist: true;
|
||||
jadwal: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const dokterdantenagamedis = proxy({
|
||||
create: {
|
||||
form: {} as DokterdanTenagaMedis,
|
||||
delete: {
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDokterdanTenagaMedis.safeParse(dokterdantenagamedis.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
async byId(id: string){
|
||||
try {
|
||||
dokterdantenagamedis.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.dokterdantenagamedis["create"].post(dokterdantenagamedis.create.form);
|
||||
if (res.status === 200) {
|
||||
dokterdantenagamedis.findMany.load();
|
||||
return toast.success("success create");
|
||||
fasilitasKesehatanState.delete.loading = true;
|
||||
const res = await fetch(`/api/kesehatan/fasilitas-kesehatan/del/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
if (res.ok && result.success) {
|
||||
toast.success("Fasilitas kesehatan berhasil dihapus");
|
||||
await fasilitasKesehatanState.findMany.load();
|
||||
} else {
|
||||
toast.error(result.message || "Gagal menghapus");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} catch {
|
||||
toast.error("Terjadi kesalahan saat menghapus");
|
||||
} finally {
|
||||
dokterdantenagamedis.create.loading = false;
|
||||
fasilitasKesehatanState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DokterdanTenagaMedisGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.dokterdantenagamedis["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
dokterdantenagamedis.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
/* ======================================================================= */
|
||||
});
|
||||
|
||||
/* Fasilitas Pendukung */
|
||||
const templateFasilitasPendukung = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type FasilitasPendukung = Prisma.FasilitasPendukungGetPayload<{
|
||||
select: {
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const fasilitaspendukung = proxy({
|
||||
create: {
|
||||
form: {} as FasilitasPendukung,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateFasilitasPendukung.safeParse(fasilitaspendukung.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
fasilitaspendukung.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.fasilitaspendukung["create"].post(fasilitaspendukung.create.form);
|
||||
if (res.status === 200) {
|
||||
fasilitaspendukung.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
fasilitaspendukung.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.FasilitasPendukungGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.
|
||||
fasilitaspendukung["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
fasilitaspendukung.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Tarif dan Layanan */
|
||||
const templateTarifDanLayanan = z.object({
|
||||
layanan: z.string().min(3, "Layanan minimal 3 karakter"),
|
||||
tarif: z.string().min(3, "Tarif minimal 3 karakter"),
|
||||
})
|
||||
|
||||
const tarifdanlayanan = proxy({
|
||||
create: {
|
||||
form: {} as Prisma.TarifDanLayananGetPayload<{ select: { layanan: true; tarif: true } }>,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateTarifDanLayanan.safeParse(tarifdanlayanan.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
tarifdanlayanan.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.tarifdanlayanan["create"].post(tarifdanlayanan.create.form);
|
||||
if (res.status === 200) {
|
||||
tarifdanlayanan.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
tarifdanlayanan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.TarifDanLayananGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.
|
||||
tarifdanlayanan["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
tarifdanlayanan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Prosedur Pendaftaran */
|
||||
const templateProsedurPendaftaran = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
const prosedurpendaftaran = proxy({
|
||||
create: {
|
||||
form: {} as Prisma.ProsedurPendaftaranGetPayload<{ select: { content: true } }>,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateProsedurPendaftaran.safeParse(prosedurpendaftaran.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
prosedurpendaftaran.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.prosedurpendaftaran["create"].post(prosedurpendaftaran.create.form);
|
||||
if (res.status === 200) {
|
||||
prosedurpendaftaran.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
prosedurpendaftaran.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.ProsedurPendaftaranGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.
|
||||
prosedurpendaftaran["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
prosedurpendaftaran.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const stateFasilitasKesehatan = proxy({
|
||||
informasiumum,
|
||||
layananunggulan,
|
||||
dokterdantenagamedis,
|
||||
fasilitaspendukung,
|
||||
tarifdanlayanan,
|
||||
prosedurpendaftaran
|
||||
})
|
||||
|
||||
export default stateFasilitasKesehatan
|
||||
export default fasilitasKesehatanState;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -5,362 +6,307 @@ import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
/* Informasi Kegiatan */
|
||||
const templateInformasiKegiatan = z.object({
|
||||
name: z.string().min(3, "Name minimal 3 karakter"),
|
||||
tanggal: z.string().min(3, "Tanggal minimal 3 karakter"),
|
||||
waktu: z.string().min(3, "Waktu minimal 3 karakter"),
|
||||
lokasi: z.string().min(3, "Lokasi minimal 3 karakter"),
|
||||
const templateForm = z.object({
|
||||
content: z.string().min(1, "Content minimal 1 karakter"),
|
||||
informasiJadwalKegiatan: z.object({
|
||||
name: z.string().min(1, "Name minimal 1 karakter"),
|
||||
tanggal: z.string().min(1, "Tanggal minimal 1 karakter"),
|
||||
waktu: z.string().min(1, "Waktu minimal 1 karakter"),
|
||||
lokasi: z.string().min(1, "Lokasi minimal 1 karakter"),
|
||||
}),
|
||||
deskripsiJadwalKegiatan: z.object({
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
}),
|
||||
layananJadwalKegiatan: z.object({
|
||||
content: z.string().min(1, "Content minimal 1 karakter"),
|
||||
}),
|
||||
syaratKetentuanJadwalKegiatan: z.object({
|
||||
content: z.string().min(1, "Content minimal 1 karakter"),
|
||||
}),
|
||||
dokumenJadwalKegiatan: z.object({
|
||||
content: z.string().min(1, "Content minimal 1 karakter"),
|
||||
}),
|
||||
pendaftaranJadwalKegiatan: 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"),
|
||||
}),
|
||||
});
|
||||
|
||||
type InformasiKegiatan = Prisma.InformasiJadwalKegiatanGetPayload<{
|
||||
select: {
|
||||
name: true;
|
||||
tanggal: true;
|
||||
waktu: true;
|
||||
lokasi: true;
|
||||
};
|
||||
}>;
|
||||
const defaultForm = {
|
||||
content: "",
|
||||
informasiJadwalKegiatan: {
|
||||
name: "",
|
||||
tanggal: "",
|
||||
waktu: "",
|
||||
lokasi: "",
|
||||
},
|
||||
deskripsiJadwalKegiatan: {
|
||||
deskripsi: "",
|
||||
},
|
||||
layananJadwalKegiatan: {
|
||||
content: "",
|
||||
},
|
||||
syaratKetentuanJadwalKegiatan: {
|
||||
content: "",
|
||||
},
|
||||
dokumenJadwalKegiatan: {
|
||||
content: "",
|
||||
},
|
||||
pendaftaranJadwalKegiatan: {
|
||||
name: "",
|
||||
tanggal: "",
|
||||
namaOrangtua: "",
|
||||
nomor: "",
|
||||
alamat: "",
|
||||
catatan: "",
|
||||
},
|
||||
};
|
||||
|
||||
const informasiKegiatan = proxy({
|
||||
const jadwalkegiatanState = proxy({
|
||||
create: {
|
||||
form: {} as InformasiKegiatan,
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateInformasiKegiatan.safeParse(
|
||||
informasiKegiatan.create.form
|
||||
);
|
||||
async submit() {
|
||||
const cek = templateForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
const errMsg = cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
.join("\n");
|
||||
toast.error(errMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
informasiKegiatan.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.informasiJadwalKegiatan[
|
||||
"create"
|
||||
].post(informasiKegiatan.create.form);
|
||||
this.loading = true;
|
||||
const payload = { ...this.form };
|
||||
|
||||
const res = await (ApiFetch.api.kesehatan as any)[
|
||||
"jadwal-kegiatan"
|
||||
].create.post(payload);
|
||||
|
||||
if (res.status === 200) {
|
||||
informasiKegiatan.findMany.load();
|
||||
return toast.success("success create");
|
||||
toast.success("Berhasil menambahkan jadwal kegiatan");
|
||||
this.resetForm();
|
||||
await jadwalkegiatanState.findMany.load();
|
||||
return res.data;
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} catch (err: any) {
|
||||
const msg = err?.message || "Terjadi kesalahan saat mengirim data";
|
||||
toast.error(msg);
|
||||
console.error("SUBMIT ERROR:", err);
|
||||
return null;
|
||||
} finally {
|
||||
informasiKegiatan.create.loading = false;
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.InformasiJadwalKegiatanGetPayload<{ omit: { isActive: true } }>[]
|
||||
| Prisma.JadwalKegiatanGetPayload<{
|
||||
include: {
|
||||
informasijadwalkegiatan: true;
|
||||
deskripsijadwalkegiatan: true;
|
||||
layananjadwalkegiatan: true;
|
||||
dokumenjadwalkegiatan: true;
|
||||
pendaftaranjadwalkegiatan: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.informasiJadwalKegiatan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
informasiKegiatan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Deskripsi Kegiatan */
|
||||
const templateDeskripsiKegiatan = z.object({
|
||||
deskripsi: z.string().min(3, "Content minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type DeskripsiKegiatan = Prisma.DeskripsiJadwalKegiatanGetPayload<{
|
||||
select: { deskripsi: true };
|
||||
}>;
|
||||
|
||||
const deskripsiKegiatan = proxy({
|
||||
create: {
|
||||
form: {} as DeskripsiKegiatan,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDeskripsiKegiatan.safeParse(
|
||||
deskripsiKegiatan.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
async load() {
|
||||
try {
|
||||
deskripsiKegiatan.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.deskripsikegiatan[
|
||||
"create"
|
||||
].post(deskripsiKegiatan.create.form);
|
||||
this.loading = true;
|
||||
const res = await (ApiFetch.api.kesehatan as any)[
|
||||
"jadwal-kegiatan"
|
||||
]["find-many"].get();
|
||||
|
||||
if (res.status === 200) {
|
||||
deskripsiKegiatan.findMany.load();
|
||||
return toast.success("success create");
|
||||
this.data = res.data?.data ?? [];
|
||||
} else {
|
||||
toast.error("Gagal memuat data jadwal kegiatan");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
toast.error("Terjadi error saat load data");
|
||||
console.error("LOAD ERROR:", err);
|
||||
throw err;
|
||||
} finally {
|
||||
deskripsiKegiatan.create.loading = false;
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DeskripsiJadwalKegiatanGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.deskripsikegiatan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
deskripsiKegiatan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Layanan Tersedia */
|
||||
const templateLayananTersedia = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type LayananTersedia = Prisma.LayananJadwalKegiatanGetPayload<{
|
||||
select: { content: true };
|
||||
}>;
|
||||
|
||||
const layanantersedia = proxy({
|
||||
create: {
|
||||
form: {} as LayananTersedia,
|
||||
findUnique: {
|
||||
data: null as Prisma.JadwalKegiatanGetPayload<{
|
||||
include: {
|
||||
informasijadwalkegiatan: true;
|
||||
deskripsijadwalkegiatan: true;
|
||||
layananjadwalkegiatan: true;
|
||||
syaratketentuanjadwalkegiatan: true;
|
||||
dokumenjadwalkegiatan: true;
|
||||
pendaftaranjadwalkegiatan: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateLayananTersedia.safeParse(
|
||||
layanantersedia.create.form
|
||||
);
|
||||
async load(id: string) {
|
||||
const res = await fetch(`/api/kesehatan/jadwal-kegiatan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
jadwalkegiatanState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal load data jadwal kegiatan");
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
const res = await fetch(`/api/kesehatan/jadwal-kegiatan/${id}`);
|
||||
if (!res.ok) {
|
||||
toast.error("Gagal load data jadwal kegiatan");
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await res.json();
|
||||
const data = result.data;
|
||||
|
||||
jadwalkegiatanState.edit.id = data.id;
|
||||
jadwalkegiatanState.edit.form = {
|
||||
content: data.content,
|
||||
informasiJadwalKegiatan: {
|
||||
name: data.informasijadwalkegiatan.name,
|
||||
tanggal: data.informasijadwalkegiatan.tanggal,
|
||||
waktu: data.informasijadwalkegiatan.waktu,
|
||||
lokasi: data.informasijadwalkegiatan.lokasi,
|
||||
},
|
||||
layananJadwalKegiatan: {
|
||||
content: data.layananjadwalkegiatan.content,
|
||||
},
|
||||
deskripsiJadwalKegiatan: {
|
||||
deskripsi: data.deskripsijadwalkegiatan.deskripsi,
|
||||
},
|
||||
syaratKetentuanJadwalKegiatan: {
|
||||
content: data.syaratketentuanjadwalkegiatan.content,
|
||||
},
|
||||
dokumenJadwalKegiatan: {
|
||||
content: data.dokumenjadwalkegiatan.content,
|
||||
},
|
||||
pendaftaranJadwalKegiatan: {
|
||||
name: data.pendaftaranjadwalkegiatan.name,
|
||||
tanggal: data.pendaftaranjadwalkegiatan.tanggal,
|
||||
namaOrangtua: data.pendaftaranjadwalkegiatan.namaOrangtua,
|
||||
nomor: data.pendaftaranjadwalkegiatan.nomor,
|
||||
alamat: data.pendaftaranjadwalkegiatan.alamat,
|
||||
catatan: data.pendaftaranjadwalkegiatan.catatan,
|
||||
},
|
||||
};
|
||||
},
|
||||
async submit() {
|
||||
const cek = templateForm.safeParse(jadwalkegiatanState.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
const errMsg = cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}: ${v.message}`)
|
||||
.join("\n");
|
||||
toast.error(errMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
layanantersedia.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.layanantersedia["create"].post(
|
||||
layanantersedia.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
layanantersedia.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
layanantersedia.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.LayananJadwalKegiatanGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.layanantersedia[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
layanantersedia.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
jadwalkegiatanState.edit.loading = true;
|
||||
const payload = {
|
||||
content: jadwalkegiatanState.edit.form.content,
|
||||
informasiJadwalKegiatan: {
|
||||
name: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.name,
|
||||
tanggal: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.tanggal,
|
||||
waktu: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.waktu,
|
||||
lokasi: jadwalkegiatanState.edit.form.informasiJadwalKegiatan.lokasi,
|
||||
},
|
||||
layananJadwalKegiatan: {
|
||||
content: jadwalkegiatanState.edit.form.layananJadwalKegiatan.content,
|
||||
},
|
||||
deskripsiJadwalKegiatan: {
|
||||
deskripsi: jadwalkegiatanState.edit.form.deskripsiJadwalKegiatan.deskripsi,
|
||||
},
|
||||
syaratKetentuanJadwalKegiatan: {
|
||||
content: jadwalkegiatanState.edit.form.syaratKetentuanJadwalKegiatan.content,
|
||||
},
|
||||
dokumenJadwalKegiatan: {
|
||||
content: jadwalkegiatanState.edit.form.dokumenJadwalKegiatan.content,
|
||||
},
|
||||
pendaftaranJadwalKegiatan: {
|
||||
name: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.name,
|
||||
tanggal: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.tanggal,
|
||||
namaOrangtua: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.namaOrangtua,
|
||||
nomor: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.nomor,
|
||||
alamat: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.alamat,
|
||||
catatan: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.catatan,
|
||||
},
|
||||
};
|
||||
|
||||
/* Syarat dan Ketentuan */
|
||||
const templateSyaratKetentuan = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type SyaratKetentuan = Prisma.SyaratKetentuanJadwalKegiatanGetPayload<{
|
||||
select: { content: true };
|
||||
}>;
|
||||
|
||||
const syaratketentuan = proxy({
|
||||
create: {
|
||||
form: {} as SyaratKetentuan,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateSyaratKetentuan.safeParse(
|
||||
syaratketentuan.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
syaratketentuan.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.syaratketentuan[
|
||||
"create"
|
||||
].post(syaratketentuan.create.form);
|
||||
if (res.status === 200) {
|
||||
syaratketentuan.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
syaratketentuan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.SyaratKetentuanJadwalKegiatanGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.syaratketentuan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
syaratketentuan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Dokumen Yang Diperlukan */
|
||||
const templateDokumenDiperlukan = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type DokumenDiperlukan = Prisma.DokumenJadwalKegiatanGetPayload<{
|
||||
select: { content: true };
|
||||
}>;
|
||||
|
||||
const dokumenjadwalkegiatan = proxy({
|
||||
create: {
|
||||
form: {} as DokumenDiperlukan,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDokumenDiperlukan.safeParse(
|
||||
dokumenjadwalkegiatan.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
dokumenjadwalkegiatan.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.dokumendiperlukan[
|
||||
"create"
|
||||
].post(dokumenjadwalkegiatan.create.form);
|
||||
if (res.status === 200) {
|
||||
dokumenjadwalkegiatan.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
dokumenjadwalkegiatan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DokumenJadwalKegiatanGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.dokumendiperlukan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
dokumenjadwalkegiatan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Pendaftaran */
|
||||
const templatePendaftaran = z.object({
|
||||
name: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
tanggal: z.string().min(1),
|
||||
namaOrangtua: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
nomor: z.string().min(9, "Nama minimal 9 karakter"),
|
||||
alamat: z.string().min(7, "Alamat minimal 7 karakter"),
|
||||
catatan: z.string().min(3, "Catatan minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type Pendaftaran = Prisma.PendaftaranJadwalKegiatanGetPayload<{
|
||||
select: {
|
||||
name: true;
|
||||
tanggal: true;
|
||||
namaOrangtua: true;
|
||||
nomor: true;
|
||||
alamat: true;
|
||||
catatan: true;
|
||||
}
|
||||
}>
|
||||
|
||||
const pendaftaranjadwal = proxy({
|
||||
create: {
|
||||
form: {} as Pendaftaran,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templatePendaftaran.safeParse(pendaftaranjadwal.create.form);
|
||||
if(!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
pendaftaranjadwal.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.pendaftaranJadwalKegiatan["create"].post(
|
||||
pendaftaranjadwal.create.form);
|
||||
if (res.status === 200) {
|
||||
pendaftaranjadwal.findMany.load();
|
||||
return toast.success("success create")
|
||||
const res = await fetch(
|
||||
`/api/kesehatan/jadwal-kegiatan/${jadwalkegiatanState.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
}
|
||||
return toast.error("failed create")
|
||||
} catch (error) {
|
||||
console.log((error as Error).message)
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
const error = await res.json();
|
||||
throw new Error(error.message || "Update gagal");
|
||||
}
|
||||
|
||||
toast.success("Berhasil update jadwal kegiatan");
|
||||
await jadwalkegiatanState.findMany.load();
|
||||
return true;
|
||||
} catch (err) {
|
||||
toast.error(
|
||||
err instanceof Error ? err.message : "Terjadi kesalahan saat update"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
pendaftaranjadwal.create.loading = false;
|
||||
jadwalkegiatanState.edit.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
jadwalkegiatanState.edit.id = "";
|
||||
jadwalkegiatanState.edit.form = { ...defaultForm };
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string){
|
||||
try {
|
||||
jadwalkegiatanState.delete.loading = true;
|
||||
const res = await fetch(`/api/kesehatan/jadwal-kegiatan/del/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
if (res.ok && result.success) {
|
||||
toast.success("Jadwal kegiatan berhasil dihapus");
|
||||
await jadwalkegiatanState.findMany.load();
|
||||
} else {
|
||||
toast.error(result.message || "Gagal menghapus");
|
||||
}
|
||||
} catch {
|
||||
toast.error("Terjadi kesalahan saat menghapus");
|
||||
} finally {
|
||||
jadwalkegiatanState.delete.loading = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PendaftaranJadwalKegiatanGetPayload<{omit: {isActive: true}}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.
|
||||
pendaftaranJadwalKegiatan["find-many"].get();
|
||||
if(res.status === 200) {
|
||||
pendaftaranjadwal.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const stateJadwalKegiatan = proxy({
|
||||
informasiKegiatan,
|
||||
deskripsiKegiatan,
|
||||
layanantersedia,
|
||||
syaratketentuan,
|
||||
dokumenjadwalkegiatan,
|
||||
pendaftaranjadwal
|
||||
});
|
||||
export default stateJadwalKegiatan;
|
||||
|
||||
export default jadwalkegiatanState;
|
||||
|
||||
@@ -42,18 +42,15 @@ const persentasekelahiran = proxy({
|
||||
}
|
||||
try {
|
||||
persentasekelahiran.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.persentasekelahiran["create"].post(persentasekelahiran.create.form);
|
||||
|
||||
const res = await ApiFetch.api.kesehatan.persentasekelahiran[
|
||||
"create"
|
||||
].post(persentasekelahiran.create.form);
|
||||
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
persentasekelahiran.create.form = {
|
||||
tahun: "",
|
||||
kematianKasar: "",
|
||||
kelahiranKasar: "",
|
||||
kematianBayi: "",
|
||||
};
|
||||
persentasekelahiran.create.form = { ...defaultForm };
|
||||
persentasekelahiran.findMany.load();
|
||||
return id;
|
||||
}
|
||||
@@ -68,9 +65,12 @@ const persentasekelahiran = proxy({
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DataKematian_KelahiranGetPayload<{ omit: { isActive: true } }>[]
|
||||
| Prisma.DataKematian_KelahiranGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.persentasekelahiran[
|
||||
@@ -101,53 +101,63 @@ const persentasekelahiran = proxy({
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async byId() {},
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templatePersentase.safeParse(persentasekelahiran.update.form);
|
||||
|
||||
const formData = {
|
||||
tahun: this.form.tahun,
|
||||
kematianKasar: this.form.kematianKasar,
|
||||
kelahiranKasar: this.form.kelahiranKasar,
|
||||
kematianBayi: this.form.kematianBayi,
|
||||
};
|
||||
|
||||
const cek = templatePersentase.safeParse(formData);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const response = await fetch(`/api/kesehatan/persentasekelahiran/${id}`, {
|
||||
const res = await fetch(`/api/kesehatan/persentasekelahiran/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
body: JSON.stringify(formData),
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok || !result?.success) {
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (!res.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
|
||||
|
||||
toast.success("Berhasil update data!");
|
||||
|
||||
// ✅ Optional: refresh list kalau kamu langsung ke halaman list
|
||||
await persentasekelahiran.findMany.load();
|
||||
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
console.error("Update error:", error);
|
||||
toast.error("Gagal update data persentase kelahiran");
|
||||
throw error;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
@@ -165,14 +175,13 @@ const persentasekelahiran = proxy({
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "Persentase kelahiran berhasil dihapus"
|
||||
);
|
||||
await persentasekelahiran.findMany.load(); // refresh list
|
||||
await persentasekelahiran.findMany.load();
|
||||
} else {
|
||||
toast.error(
|
||||
result?.message || "Gagal menghapus persentase kelahiran"
|
||||
|
||||
224
src/app/admin/(dashboard)/_state/landing-page/apbdes.ts
Normal file
224
src/app/admin/(dashboard)/_state/landing-page/apbdes.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
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 templateapbDesaForm = z.object({
|
||||
name: z.string().min(1, "Judul minimal 1 karakter"),
|
||||
jumlah: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
imageId: z.string().min(1, "File minimal 1"),
|
||||
fileId: z.string().min(1, "File minimal 1"),
|
||||
});
|
||||
|
||||
const defaultapbdesForm = {
|
||||
name: "",
|
||||
jumlah: "",
|
||||
imageId: "",
|
||||
fileId: "",
|
||||
};
|
||||
|
||||
const apbdes = proxy({
|
||||
create: {
|
||||
form: { ...defaultapbdesForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateapbDesaForm.safeParse(apbdes.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
apbdes.create.loading = true;
|
||||
const res = await ApiFetch.api.landingpage.apbdes["create"].post({
|
||||
...apbdes.create.form,
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
apbdes.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
apbdes.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.APBDesGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
file: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.apbdes["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
apbdes.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.APBDesGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
file: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/landingpage/apbdes/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
apbdes.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
apbdes.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
apbdes.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
apbdes.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/landingpage/apbdes/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "apbdes berhasil dihapus");
|
||||
await apbdes.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus apbdes");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus apbdes");
|
||||
} finally {
|
||||
apbdes.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultapbdesForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
apbdes.edit.loading = true;
|
||||
|
||||
const response = await fetch(`/api/landingpage/apbdes/${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,
|
||||
jumlah: data.jumlah,
|
||||
imageId: data.imageId,
|
||||
fileId: data.fileId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading apbdes:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
} finally {
|
||||
apbdes.edit.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateapbDesaForm.safeParse(apbdes.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
apbdes.edit.loading = true;
|
||||
const response = await fetch(`/api/landingpage/apbdes/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
jumlah: this.form.jumlah,
|
||||
imageId: this.form.imageId,
|
||||
fileId: this.form.fileId,
|
||||
}),
|
||||
});
|
||||
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 apbdes");
|
||||
await apbdes.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate apbdes");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating apbdes:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal mengupdate apbdes"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
apbdes.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
apbdes.edit.id = "";
|
||||
apbdes.edit.form = { ...defaultapbdesForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default apbdes;
|
||||
@@ -0,0 +1,485 @@
|
||||
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 templateDesaAntiKorupsiForm = z.object({
|
||||
name: z.string().min(1, "Judul minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
kategoriId: z.string().min(1, "Kategori minimal 1"),
|
||||
fileId: z.string().min(1, "File minimal 1"),
|
||||
});
|
||||
|
||||
const defaultDesaAntiKorupsiForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
kategoriId: "",
|
||||
fileId: "",
|
||||
};
|
||||
|
||||
const desaAntikorupsi = proxy({
|
||||
create: {
|
||||
form: { ...defaultDesaAntiKorupsiForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDesaAntiKorupsiForm.safeParse(
|
||||
desaAntikorupsi.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
desaAntikorupsi.create.loading = true;
|
||||
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
||||
"create"
|
||||
].post({
|
||||
...desaAntikorupsi.create.form,
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
desaAntikorupsi.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
desaAntikorupsi.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.DesaAntiKorupsiGetPayload<{
|
||||
include: {
|
||||
file: true;
|
||||
kategori: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
desaAntikorupsi.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.DesaAntiKorupsiGetPayload<{
|
||||
include: {
|
||||
file: true;
|
||||
kategori: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/landingpage/desaantikorupsi/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
desaAntikorupsi.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
desaAntikorupsi.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
desaAntikorupsi.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
desaAntikorupsi.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/desaantikorupsi/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "desa anti korupsi berhasil dihapus");
|
||||
await desaAntikorupsi.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus desa anti korupsi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus desa anti korupsi");
|
||||
} finally {
|
||||
desaAntikorupsi.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultDesaAntiKorupsiForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
desaAntikorupsi.edit.loading = true;
|
||||
|
||||
const response = await fetch(`/api/landingpage/desaantikorupsi/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
kategoriId: data.kategoriId,
|
||||
fileId: data.fileId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading desa anti korupsi:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
} finally {
|
||||
desaAntikorupsi.edit.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateDesaAntiKorupsiForm.safeParse(
|
||||
desaAntikorupsi.edit.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
desaAntikorupsi.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/landingpage/desaantikorupsi/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
deskripsi: this.form.deskripsi,
|
||||
kategoriId: this.form.kategoriId,
|
||||
fileId: this.form.fileId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
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 desa anti korupsi");
|
||||
await desaAntikorupsi.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate desa anti korupsi"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating desa anti korupsi:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate desa anti korupsi"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
desaAntikorupsi.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
desaAntikorupsi.edit.id = "";
|
||||
desaAntikorupsi.edit.form = { ...defaultDesaAntiKorupsiForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= KATEGORI desa anti korupsi ========================================= //
|
||||
const kategoriDesaAntiKorupsiForm = z.object({
|
||||
name: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const kategoriDesaAntiKorupsiDefaultForm = {
|
||||
name: "",
|
||||
};
|
||||
|
||||
const kategoriDesaAntiKorupsi = proxy({
|
||||
create: {
|
||||
form: { ...kategoriDesaAntiKorupsiDefaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = kategoriDesaAntiKorupsiForm.safeParse(
|
||||
kategoriDesaAntiKorupsi.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
kategoriDesaAntiKorupsi.create.loading = true;
|
||||
const res = await ApiFetch.api.landingpage.kategoridak["create"].post(
|
||||
kategoriDesaAntiKorupsi.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
kategoriDesaAntiKorupsi.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
kategoriDesaAntiKorupsi.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.kategoridak["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
kategoriDesaAntiKorupsi.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KategoriDesaAntiKorupsiGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/landingpage/kategoridak/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kategoriDesaAntiKorupsi.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
kategoriDesaAntiKorupsi.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
kategoriDesaAntiKorupsi.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
kategoriDesaAntiKorupsi.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/kategoridak/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kategori desa anti korupsi berhasil dihapus");
|
||||
await kategoriDesaAntiKorupsi.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kategori desa anti korupsi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kategori desa anti korupsi");
|
||||
} finally {
|
||||
kategoriDesaAntiKorupsi.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...kategoriDesaAntiKorupsiDefaultForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/landingpage/kategoridak/${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,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kategori desa anti korupsi:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = kategoriDesaAntiKorupsiForm.safeParse(
|
||||
kategoriDesaAntiKorupsi.edit.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
kategoriDesaAntiKorupsi.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/landingpage/kategoridak/${kategoriDesaAntiKorupsi.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: kategoriDesaAntiKorupsi.edit.form.name,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Clone the response to avoid 'body already read' error
|
||||
const responseClone = response.clone();
|
||||
|
||||
try {
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
"Update failed with status:",
|
||||
response.status,
|
||||
"Response:",
|
||||
result
|
||||
);
|
||||
throw new Error(
|
||||
result?.message ||
|
||||
`Gagal mengupdate kategori desa anti korupsi (${response.status})`
|
||||
);
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
toast.success(
|
||||
result.message ||
|
||||
"Berhasil memperbarui kategori desa anti korupsi"
|
||||
);
|
||||
await kategoriDesaAntiKorupsi.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate kategori desa anti korupsi"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// If JSON parsing fails, try to get the response text for better error messages
|
||||
try {
|
||||
const text = await responseClone.text();
|
||||
console.error("Error response text:", text);
|
||||
throw new Error(`Gagal memproses respons dari server: ${text}`);
|
||||
} catch (textError) {
|
||||
console.error("Error parsing response as text:", textError);
|
||||
console.error("Original error:", error);
|
||||
throw new Error("Gagal memproses respons dari server");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating kategori desa anti korupsi:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate kategori desa anti korupsi"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
kategoriDesaAntiKorupsi.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
kategoriDesaAntiKorupsi.edit.id = "";
|
||||
kategoriDesaAntiKorupsi.edit.form = {
|
||||
...kategoriDesaAntiKorupsiDefaultForm,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const korupsiState = proxy({
|
||||
desaAntikorupsi,
|
||||
kategoriDesaAntiKorupsi,
|
||||
});
|
||||
export default korupsiState;
|
||||
File diff suppressed because it is too large
Load Diff
486
src/app/admin/(dashboard)/_state/landing-page/prestasi-desa.ts
Normal file
486
src/app/admin/(dashboard)/_state/landing-page/prestasi-desa.ts
Normal file
@@ -0,0 +1,486 @@
|
||||
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 templateprestasiDesaForm = z.object({
|
||||
name: z.string().min(1, "Judul minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
imageId: z.string().min(1, "File minimal 1"),
|
||||
kategoriId: z.string().min(1, "Kategori minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultprestasiDesaForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
imageId: "",
|
||||
kategoriId: "",
|
||||
};
|
||||
|
||||
const prestasiDesa = proxy({
|
||||
create: {
|
||||
form: { ...defaultprestasiDesaForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateprestasiDesaForm.safeParse(
|
||||
prestasiDesa.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
prestasiDesa.create.loading = true;
|
||||
const res = await ApiFetch.api.landingpage.prestasidesa[
|
||||
"create"
|
||||
].post({
|
||||
...prestasiDesa.create.form,
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
prestasiDesa.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
prestasiDesa.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.PrestasiDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategori: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.prestasidesa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
prestasiDesa.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.PrestasiDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategori: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/landingpage/prestasidesa/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
prestasiDesa.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
prestasiDesa.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
prestasiDesa.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
prestasiDesa.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/prestasidesa/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "prestasi desa berhasil dihapus");
|
||||
await prestasiDesa.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus prestasi desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus prestasi desa");
|
||||
} finally {
|
||||
prestasiDesa.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultprestasiDesaForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
prestasiDesa.edit.loading = true;
|
||||
|
||||
const response = await fetch(`/api/landingpage/prestasidesa/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
imageId: data.imageId,
|
||||
kategoriId: data.kategoriId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading prestasi desa:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
} finally {
|
||||
prestasiDesa.edit.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateprestasiDesaForm.safeParse(
|
||||
prestasiDesa.edit.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
prestasiDesa.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/landingpage/prestasidesa/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
deskripsi: this.form.deskripsi,
|
||||
imageId: this.form.imageId,
|
||||
kategoriId: this.form.kategoriId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
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 prestasi desa");
|
||||
await prestasiDesa.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate prestasi desa"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating prestasi desa:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate prestasi desa"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
prestasiDesa.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
prestasiDesa.edit.id = "";
|
||||
prestasiDesa.edit.form = { ...defaultprestasiDesaForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= KATEGORI kegiatan ========================================= //
|
||||
const kategoriPrestasiForm = z.object({
|
||||
name: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const kategoriPrestasiDefaultForm = {
|
||||
name: "",
|
||||
};
|
||||
|
||||
const kategoriPrestasi = proxy({
|
||||
create: {
|
||||
form: { ...kategoriPrestasiDefaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = kategoriPrestasiForm.safeParse(kategoriPrestasi.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
kategoriPrestasi.create.loading = true;
|
||||
const res = await ApiFetch.api.landingpage.kategoriprestasi[
|
||||
"create"
|
||||
].post(kategoriPrestasi.create.form);
|
||||
if (res.status === 200) {
|
||||
kategoriPrestasi.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
kategoriPrestasi.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.kategoriprestasi[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
kategoriPrestasi.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KategoriPrestasiDesaGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/landingpage/kategoriprestasi/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kategoriPrestasi.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
kategoriPrestasi.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
kategoriPrestasi.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
kategoriPrestasi.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/kategoriprestasi/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kategori prestasi berhasil dihapus");
|
||||
await kategoriPrestasi.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kategori prestasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kategori prestasi");
|
||||
} finally {
|
||||
kategoriPrestasi.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...kategoriPrestasiDefaultForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/landingpage/kategoriprestasi/${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,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kategori prestasi:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = kategoriPrestasiForm.safeParse(kategoriPrestasi.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
kategoriPrestasi.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/landingpage/kategoriprestasi/${kategoriPrestasi.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: kategoriPrestasi.edit.form.name,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Clone the response to avoid 'body already read' error
|
||||
const responseClone = response.clone();
|
||||
|
||||
try {
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
"Update failed with status:",
|
||||
response.status,
|
||||
"Response:",
|
||||
result
|
||||
);
|
||||
throw new Error(
|
||||
result?.message ||
|
||||
`Gagal mengupdate kategori prestasi (${response.status})`
|
||||
);
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
toast.success(
|
||||
result.message || "Berhasil memperbarui kategori prestasi"
|
||||
);
|
||||
await kategoriPrestasi.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate kategori prestasi"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// If JSON parsing fails, try to get the response text for better error messages
|
||||
try {
|
||||
const text = await responseClone.text();
|
||||
console.error("Error response text:", text);
|
||||
throw new Error(`Gagal memproses respons dari server: ${text}`);
|
||||
} catch (textError) {
|
||||
console.error("Error parsing response as text:", textError);
|
||||
console.error("Original error:", error);
|
||||
throw new Error("Gagal memproses respons dari server");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating kategori prestasi:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate kategori prestasi"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
kategoriPrestasi.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
kategoriPrestasi.edit.id = "";
|
||||
kategoriPrestasi.edit.form = { ...kategoriPrestasiDefaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const prestasiState = proxy({
|
||||
prestasiDesa,
|
||||
kategoriPrestasi,
|
||||
});
|
||||
|
||||
export default prestasiState;
|
||||
634
src/app/admin/(dashboard)/_state/landing-page/profile.ts
Normal file
634
src/app/admin/(dashboard)/_state/landing-page/profile.ts
Normal file
@@ -0,0 +1,634 @@
|
||||
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 templateProgramInovasi = z.object({
|
||||
name: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
description: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
imageId: z.string().min(1, "Gambar wajib dipilih"),
|
||||
link: z.string().min(3, "Link minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type ProgramInovasiForm = Prisma.ProgramInovasiGetPayload<{
|
||||
select: {
|
||||
name: true;
|
||||
description: true;
|
||||
imageId: true;
|
||||
link: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const programInovasi = proxy({
|
||||
create: {
|
||||
form: {} as ProgramInovasiForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
// Ensure all required fields are non-null
|
||||
const formData = {
|
||||
name: programInovasi.create.form.name || "",
|
||||
description: programInovasi.create.form.description || "",
|
||||
imageId: programInovasi.create.form.imageId || "",
|
||||
link: programInovasi.create.form.link || "",
|
||||
};
|
||||
|
||||
const cek = templateProgramInovasi.safeParse(formData);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
programInovasi.create.loading = true;
|
||||
const res = await ApiFetch.api.landingpage.programinovasi[
|
||||
"create"
|
||||
].post(formData);
|
||||
if (res.status === 200) {
|
||||
programInovasi.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
programInovasi.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.ProgramInovasiGetPayload<{ include: { image: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.programinovasi[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
programInovasi.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.ProgramInovasiGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/landingpage/programinovasi/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
programInovasi.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch program inovasi:", res.statusText);
|
||||
programInovasi.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching program inovasi:", error);
|
||||
programInovasi.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
programInovasi.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/programinovasi/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Program inovasi berhasil dihapus");
|
||||
await programInovasi.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus program inovasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus program inovasi");
|
||||
} finally {
|
||||
programInovasi.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: {} as ProgramInovasiForm,
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/landingpage/programinovasi/${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,
|
||||
description: data.description,
|
||||
imageId: data.imageId,
|
||||
link: data.link,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(
|
||||
result?.message || "Gagal mengambil data program inovasi"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data program inovasi");
|
||||
} finally {
|
||||
programInovasi.update.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateProgramInovasi.safeParse(programInovasi.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
programInovasi.update.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/programinovasi/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
description: this.form.description,
|
||||
imageId: this.form.imageId,
|
||||
link: this.form.link,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
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 program inovasi");
|
||||
await programInovasi.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update program inovasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating program inovasi:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update program inovasi"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
programInovasi.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templatePejabatDesa = z.object({
|
||||
name: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
position: z.string().min(3, "Posisi minimal 3 karakter"),
|
||||
imageId: z.string().min(1, "Gambar wajib dipilih"),
|
||||
});
|
||||
|
||||
const defaultFormPejabatDesa = {
|
||||
name: "",
|
||||
position: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
type PejabatDesaForm = {
|
||||
id: string;
|
||||
name: string;
|
||||
position: string;
|
||||
imageId: string | null;
|
||||
image?: {
|
||||
id: string;
|
||||
name: string;
|
||||
link: string;
|
||||
path: string;
|
||||
mimeType: string;
|
||||
realName: string;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
deletedAt: Date | null;
|
||||
} | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
deletedAt: Date | null;
|
||||
isActive: boolean;
|
||||
};
|
||||
|
||||
const pejabatDesa = proxy({
|
||||
findUnique: {
|
||||
data: null as PejabatDesaForm | null,
|
||||
loading: false,
|
||||
error: null as string | null,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/landingpage/pejabatdesa/${id}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
this.data = result.data;
|
||||
return result.data;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengambil data pejabat desa"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = (error as Error).message;
|
||||
this.error = errorMessage;
|
||||
console.error("Load pejabat desa error:", errorMessage);
|
||||
toast.error("Terjadi kesalahan saat mengambil data pejabat desa");
|
||||
return null;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.data = null;
|
||||
this.error = null;
|
||||
this.loading = false;
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultFormPejabatDesa },
|
||||
loading: false,
|
||||
error: null as string | null,
|
||||
isReadOnly: false,
|
||||
|
||||
initialize(profileData: PejabatDesaForm) {
|
||||
this.id = profileData.id;
|
||||
this.isReadOnly = false; // Semua data bisa diedit
|
||||
this.form = {
|
||||
name: profileData.name || "",
|
||||
position: profileData.position || "",
|
||||
imageId: profileData.imageId || "",
|
||||
};
|
||||
},
|
||||
|
||||
// Update form field
|
||||
updateField(field: keyof typeof defaultFormPejabatDesa, value: string) {
|
||||
this.form[field] = value;
|
||||
},
|
||||
|
||||
// Submit form
|
||||
async submit() {
|
||||
// Validate form
|
||||
const validation = templatePejabatDesa.safeParse(this.form);
|
||||
|
||||
if (!validation.success) {
|
||||
const errors = validation.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/landingpage/pejabatdesa/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
}
|
||||
);
|
||||
|
||||
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 profile");
|
||||
// Refresh profile data
|
||||
await pejabatDesa.findUnique.load(this.id);
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update profile");
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = (error as Error).message;
|
||||
this.error = errorMessage;
|
||||
console.error("Update profile error:", errorMessage);
|
||||
toast.error("Terjadi kesalahan saat update profile");
|
||||
return false;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.id = "";
|
||||
this.form = { ...defaultFormPejabatDesa };
|
||||
this.error = null;
|
||||
this.loading = false;
|
||||
this.isReadOnly = false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templateMediaSosial = z.object({
|
||||
name: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
imageId: z.string().min(1, "Gambar wajib dipilih"),
|
||||
iconUrl: z.string().min(3, "Icon URL minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type MediaSosialForm = {
|
||||
name: string;
|
||||
imageId: string;
|
||||
iconUrl: string;
|
||||
};
|
||||
|
||||
const mediaSosial = proxy({
|
||||
create: {
|
||||
form: {} as MediaSosialForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
// Ensure all required fields are non-null
|
||||
const formData = {
|
||||
name: mediaSosial.create.form.name || "",
|
||||
imageId: mediaSosial.create.form.imageId || "",
|
||||
iconUrl: mediaSosial.create.form.iconUrl || "",
|
||||
};
|
||||
|
||||
const cek = templateMediaSosial.safeParse(formData);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
mediaSosial.create.loading = true;
|
||||
const res = await ApiFetch.api.landingpage.mediasosial["create"].post(
|
||||
formData
|
||||
);
|
||||
if (res.status === 200) {
|
||||
mediaSosial.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
mediaSosial.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.MediaSosialGetPayload<{ include: { image: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.mediasosial["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
mediaSosial.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.MediaSosialGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
mediaSosial.update.loading = true;
|
||||
try {
|
||||
const res = await fetch(`/api/landingpage/mediasosial/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
mediaSosial.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch media sosial:", res.statusText);
|
||||
mediaSosial.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching media sosial:", error);
|
||||
mediaSosial.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
mediaSosial.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/landingpage/mediasosial/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Media Sosial berhasil dihapus");
|
||||
await mediaSosial.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus media sosial");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus media sosial");
|
||||
} finally {
|
||||
mediaSosial.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: {} as MediaSosialForm,
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
mediaSosial.update.loading = true; // ✅ Tambahkan ini di awal
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/landingpage/mediasosial/${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 || "",
|
||||
iconUrl: data.iconUrl || "",
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal mengambil data media sosial");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data media sosial");
|
||||
} finally {
|
||||
mediaSosial.update.loading = false; // ✅ Supaya berhenti loading walau error
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateMediaSosial.safeParse(mediaSosial.update.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
mediaSosial.update.loading = true;
|
||||
|
||||
const response = await fetch(`/api/landingpage/mediasosial/${this.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
imageId: this.form.imageId,
|
||||
iconUrl: this.form.iconUrl,
|
||||
}),
|
||||
});
|
||||
|
||||
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 media sosial");
|
||||
await mediaSosial.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update media sosial");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating media sosial:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update media sosial"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
mediaSosial.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const profileLandingPageState = proxy({
|
||||
programInovasi,
|
||||
pejabatDesa,
|
||||
mediaSosial,
|
||||
});
|
||||
|
||||
export default profileLandingPageState;
|
||||
236
src/app/admin/(dashboard)/_state/landing-page/sdgs-desa.ts
Normal file
236
src/app/admin/(dashboard)/_state/landing-page/sdgs-desa.ts
Normal file
@@ -0,0 +1,236 @@
|
||||
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 templatesdgsDesaForm = z.object({
|
||||
name: z.string().min(1, "Judul minimal 1 karakter"),
|
||||
jumlah: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
imageId: z.string().min(1, "File minimal 1"),
|
||||
});
|
||||
|
||||
const defaultsdgsDesaForm = {
|
||||
name: "",
|
||||
jumlah: "",
|
||||
imageId: "",
|
||||
};
|
||||
|
||||
const sdgsDesa = proxy({
|
||||
create: {
|
||||
form: { ...defaultsdgsDesaForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templatesdgsDesaForm.safeParse(
|
||||
sdgsDesa.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
sdgsDesa.create.loading = true;
|
||||
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
||||
"create"
|
||||
].post({
|
||||
...sdgsDesa.create.form,
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
sdgsDesa.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
sdgsDesa.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.SDGSDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
sdgsDesa.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.SDGSDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/landingpage/sdgsdesa/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
sdgsDesa.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
sdgsDesa.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
sdgsDesa.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
sdgsDesa.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/landingpage/sdgsdesa/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "sdgs desa berhasil dihapus");
|
||||
await sdgsDesa.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus sdgs desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus sdgs desa");
|
||||
} finally {
|
||||
sdgsDesa.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultsdgsDesaForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
sdgsDesa.edit.loading = true;
|
||||
|
||||
const response = await fetch(`/api/landingpage/sdgsdesa/${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,
|
||||
jumlah: data.jumlah,
|
||||
imageId: data.imageId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading sdgs desa:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
} finally {
|
||||
sdgsDesa.edit.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templatesdgsDesaForm.safeParse(
|
||||
sdgsDesa.edit.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
sdgsDesa.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/landingpage/sdgsdesa/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
jumlah: this.form.jumlah,
|
||||
imageId: this.form.imageId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success("Berhasil update sdgs desa");
|
||||
await sdgsDesa.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate sdgs desa"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating sdgs desa:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate sdgs desa"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
sdgsDesa.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
sdgsDesa.edit.id = "";
|
||||
sdgsDesa.edit.form = { ...defaultsdgsDesaForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default sdgsDesa;
|
||||
@@ -0,0 +1,227 @@
|
||||
/* 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, "Nama minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
jumlah: z.string().min(1, "Jumlah minimal 1 karakter"),
|
||||
icon: z.string().min(1, "Icon minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
jumlah: "",
|
||||
icon: "",
|
||||
};
|
||||
|
||||
const dataLingkunganDesaState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(dataLingkunganDesaState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
dataLingkunganDesaState.create.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.datalingkungandesa["create"].post(
|
||||
dataLingkunganDesaState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
dataLingkunganDesaState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
dataLingkunganDesaState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
// Change to arrow function
|
||||
dataLingkunganDesaState.findMany.loading = true; // Use the full path to access the property
|
||||
dataLingkunganDesaState.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.lingkungan.datalingkungandesa["find-many"].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
dataLingkunganDesaState.findMany.data = res.data.data || [];
|
||||
dataLingkunganDesaState.findMany.total = res.data.total || 0;
|
||||
dataLingkunganDesaState.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load berdasarkan data lingkungan desa :",
|
||||
res.data?.message
|
||||
);
|
||||
dataLingkunganDesaState.findMany.data = [];
|
||||
dataLingkunganDesaState.findMany.total = 0;
|
||||
dataLingkunganDesaState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading berdasarkan data lingkungan desa :", error);
|
||||
dataLingkunganDesaState.findMany.data = [];
|
||||
dataLingkunganDesaState.findMany.total = 0;
|
||||
dataLingkunganDesaState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
dataLingkunganDesaState.findMany.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/lingkungan/datalingkungandesa/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
jumlah: data.jumlah,
|
||||
icon: data.icon,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal mengambil data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading data lingkungan desa :", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(`/api/lingkungan/datalingkungandesa/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await dataLingkunganDesaState.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data data lingkungan desa");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.DataLingkunganDesaGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/lingkungan/datalingkungandesa/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
dataLingkunganDesaState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
dataLingkunganDesaState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading data lingkungan desa:", error);
|
||||
dataLingkunganDesaState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
dataLingkunganDesaState.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/lingkungan/datalingkungandesa/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Data lingkungan desa berhasil dihapus");
|
||||
await dataLingkunganDesaState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus data lingkungan desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus data lingkungan desa");
|
||||
} finally {
|
||||
dataLingkunganDesaState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default dataLingkunganDesaState;
|
||||
@@ -0,0 +1,240 @@
|
||||
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 templateTujuanEdukasiForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type TujuanEdukasiForm = Prisma.TujuanEdukasiLingkunganGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const stateTujuanEdukasi = proxy({
|
||||
findById: {
|
||||
data: null as TujuanEdukasiForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
stateTujuanEdukasi.findById.data = {
|
||||
id: '',
|
||||
judul: '',
|
||||
deskripsi: '',
|
||||
} as TujuanEdukasiForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
stateTujuanEdukasi.findById.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.edukasilingkungan.tujuanedukasilingkungan["find-by-id"].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
stateTujuanEdukasi.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal mengambil data tujuan edukasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data tujuan edukasi");
|
||||
} finally {
|
||||
stateTujuanEdukasi.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: TujuanEdukasiForm) {
|
||||
const cek = templateTujuanEdukasiForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stateTujuanEdukasi.update.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.edukasilingkungan.tujuanedukasilingkungan["update"].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Data tujuan edukasi berhasil diubah");
|
||||
await stateTujuanEdukasi.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data tujuan edukasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengubah data tujuan edukasi");
|
||||
} finally {
|
||||
stateTujuanEdukasi.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templateMateriEdukasiLingkunganForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type MateriEdukasiLingkunganForm = Prisma.MateriEdukasiLingkunganGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const stateMateriEdukasiLingkungan = proxy({
|
||||
findById: {
|
||||
data: null as MateriEdukasiLingkunganForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
stateMateriEdukasiLingkungan.findById.data = {
|
||||
id: '',
|
||||
judul: '',
|
||||
deskripsi: '',
|
||||
} as MateriEdukasiLingkunganForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
stateMateriEdukasiLingkungan.findById.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.edukasilingkungan.materiedukasilingkungan["find-by-id"].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
stateMateriEdukasiLingkungan.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal mengambil data materi edukasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data materi edukasi");
|
||||
} finally {
|
||||
stateMateriEdukasiLingkungan.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: MateriEdukasiLingkunganForm) {
|
||||
const cek = templateMateriEdukasiLingkunganForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stateMateriEdukasiLingkungan.update.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.edukasilingkungan.materiedukasilingkungan["update"].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Data materi edukasi berhasil diubah");
|
||||
await stateMateriEdukasiLingkungan.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data materi edukasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengubah data materi edukasi");
|
||||
} finally {
|
||||
stateMateriEdukasiLingkungan.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templateContohEdukasiLingkunganForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type ContohEdukasiLingkunganForm = Prisma.ContohEdukasiLingkunganGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const stateContohEdukasiLingkungan = proxy({
|
||||
findById: {
|
||||
data: null as ContohEdukasiLingkunganForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
stateContohEdukasiLingkungan.findById.data = {
|
||||
id: '',
|
||||
judul: '',
|
||||
deskripsi: '',
|
||||
} as ContohEdukasiLingkunganForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
stateContohEdukasiLingkungan.findById.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.edukasilingkungan.contohkegiatandesa["find-by-id"].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
stateContohEdukasiLingkungan.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal mengambil data contoh edukasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data contoh edukasi");
|
||||
} finally {
|
||||
stateContohEdukasiLingkungan.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: ContohEdukasiLingkunganForm) {
|
||||
const cek = templateContohEdukasiLingkunganForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stateContohEdukasiLingkungan.update.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.edukasilingkungan.contohkegiatandesa["update"].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Data contoh edukasi berhasil diubah");
|
||||
await stateContohEdukasiLingkungan.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data contoh edukasi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengubah data contoh edukasi");
|
||||
} finally {
|
||||
stateContohEdukasiLingkungan.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const stateEdukasiLingkungan = proxy({
|
||||
stateTujuanEdukasi,
|
||||
stateMateriEdukasiLingkungan,
|
||||
stateContohEdukasiLingkungan
|
||||
})
|
||||
|
||||
|
||||
export default stateEdukasiLingkungan;
|
||||
492
src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts
Normal file
492
src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts
Normal file
@@ -0,0 +1,492 @@
|
||||
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 templateKegiatanDesaForm = z.object({
|
||||
judul: z.string().min(1, "Judul minimal 1 karakter"),
|
||||
deskripsiSingkat: z.string().min(1, "Deskripsi singkat minimal 1 karakter"),
|
||||
deskripsiLengkap: z.string().min(1, "Deskripsi lengkap minimal 1 karakter"),
|
||||
tanggal: z.date(),
|
||||
lokasi: z.string().min(1, "Lokasi minimal 1 karakter"),
|
||||
partisipan: z.number().min(1, "Partisipan minimal 1"),
|
||||
imageId: z.string().min(1, "Gambar wajib dipilih"),
|
||||
kategoriKegiatanId: z.string().min(1, "Kategori kegiatan minimal 1"),
|
||||
});
|
||||
|
||||
const defaultKegiatanDesaForm = {
|
||||
judul: "",
|
||||
deskripsiSingkat: "",
|
||||
deskripsiLengkap: "",
|
||||
tanggal: new Date(),
|
||||
lokasi: "",
|
||||
partisipan: 0,
|
||||
imageId: "",
|
||||
kategoriKegiatanId: "",
|
||||
};
|
||||
|
||||
const kegiatanDesa = proxy({
|
||||
create: {
|
||||
form: { ...defaultKegiatanDesaForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateKegiatanDesaForm.safeParse(kegiatanDesa.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
kegiatanDesa.create.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.kegiatandesa["create"].post({
|
||||
...kegiatanDesa.create.form,
|
||||
tanggal: kegiatanDesa.create.form.tanggal.toISOString(), // ✅ convert Date -> string
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
kegiatanDesa.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
kegiatanDesa.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<
|
||||
Prisma.KegiatanDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategoriKegiatan: true;
|
||||
};
|
||||
}>
|
||||
> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.lingkungan.kegiatandesa["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
kegiatanDesa.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KegiatanDesaGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
kategoriKegiatan: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/lingkungan/kegiatandesa/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kegiatanDesa.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
kegiatanDesa.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
kegiatanDesa.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
kegiatanDesa.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/lingkungan/kegiatandesa/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "kegiatan desa berhasil dihapus");
|
||||
await kegiatanDesa.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus pasar desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus pasar desa");
|
||||
} finally {
|
||||
kegiatanDesa.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultKegiatanDesaForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
kegiatanDesa.edit.loading = true;
|
||||
|
||||
const response = await fetch(`/api/lingkungan/kegiatandesa/${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,
|
||||
deskripsiSingkat: data.deskripsiSingkat,
|
||||
deskripsiLengkap: data.deskripsiLengkap,
|
||||
tanggal: data.tanggal,
|
||||
lokasi: data.lokasi,
|
||||
partisipan: data.partisipan,
|
||||
imageId: data.imageId,
|
||||
kategoriKegiatanId: data.kategoriKegiatanId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kegiatan desa:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
} finally {
|
||||
kegiatanDesa.edit.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateKegiatanDesaForm.safeParse(kegiatanDesa.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
kegiatanDesa.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/kegiatandesa/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
judul: this.form.judul,
|
||||
deskripsiSingkat: this.form.deskripsiSingkat,
|
||||
deskripsiLengkap: this.form.deskripsiLengkap,
|
||||
tanggal:
|
||||
typeof this.form.tanggal === "string"
|
||||
? this.form.tanggal
|
||||
: this.form.tanggal.toISOString(),
|
||||
lokasi: this.form.lokasi,
|
||||
partisipan: this.form.partisipan,
|
||||
imageId: this.form.imageId,
|
||||
kategoriKegiatanId: this.form.kategoriKegiatanId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
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 kegiatan desa");
|
||||
await kegiatanDesa.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate kegiatan desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating kegiatan desa:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate kegiatan desa"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
kegiatanDesa.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
kegiatanDesa.edit.id = "";
|
||||
kegiatanDesa.edit.form = { ...defaultKegiatanDesaForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= KATEGORI kegiatan ========================================= //
|
||||
const kategoriKegiatanForm = z.object({
|
||||
nama: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const kategoriKegiatanDefaultForm = {
|
||||
nama: "",
|
||||
};
|
||||
|
||||
const kategoriKegiatan = proxy({
|
||||
create: {
|
||||
form: { ...kategoriKegiatanDefaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = kategoriKegiatanForm.safeParse(kategoriKegiatan.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
kategoriKegiatan.create.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.kategorikegiatan[
|
||||
"create"
|
||||
].post(kategoriKegiatan.create.form);
|
||||
if (res.status === 200) {
|
||||
kategoriKegiatan.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
kategoriKegiatan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Array<{
|
||||
id: string;
|
||||
nama: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.lingkungan.kategorikegiatan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
kategoriKegiatan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KategoriKegiatanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/lingkungan/kategorikegiatan/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
kategoriKegiatan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
kategoriKegiatan.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
kategoriKegiatan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
kategoriKegiatan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/kategorikegiatan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Kategori kegiatan berhasil dihapus");
|
||||
await kategoriKegiatan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus kategori kegiatan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus kategori kegiatan");
|
||||
} finally {
|
||||
kategoriKegiatan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...kategoriKegiatanDefaultForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/kategorikegiatan/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
nama: data.nama,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading kategori kegiatan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = kategoriKegiatanForm.safeParse(kategoriKegiatan.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
kategoriKegiatan.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/kategorikegiatan/${kategoriKegiatan.edit.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: kategoriKegiatan.edit.form.nama,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Clone the response to avoid 'body already read' error
|
||||
const responseClone = response.clone();
|
||||
|
||||
try {
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
"Update failed with status:",
|
||||
response.status,
|
||||
"Response:",
|
||||
result
|
||||
);
|
||||
throw new Error(
|
||||
result?.message ||
|
||||
`Gagal mengupdate kategori kegiatan (${response.status})`
|
||||
);
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
toast.success(
|
||||
result.message || "Berhasil memperbarui kategori kegiatan"
|
||||
);
|
||||
await kategoriKegiatan.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate kategori kegiatan"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// If JSON parsing fails, try to get the response text for better error messages
|
||||
try {
|
||||
const text = await responseClone.text();
|
||||
console.error("Error response text:", text);
|
||||
throw new Error(`Gagal memproses respons dari server: ${text}`);
|
||||
} catch (textError) {
|
||||
console.error("Error parsing response as text:", textError);
|
||||
console.error("Original error:", error);
|
||||
throw new Error("Gagal memproses respons dari server");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating kategori kegiatan:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate kategori kegiatan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
kategoriKegiatan.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
kategoriKegiatan.edit.id = "";
|
||||
kategoriKegiatan.edit.form = { ...kategoriKegiatanDefaultForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const gotongRoyongState = proxy({
|
||||
kegiatanDesa,
|
||||
kategoriKegiatan,
|
||||
});
|
||||
export default gotongRoyongState;
|
||||
@@ -0,0 +1,274 @@
|
||||
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 templateFilosofiTriHitaForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type FilosofiTriHitaForm = Prisma.FilosofiTriHitaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const stateFilosofiTriHita = proxy({
|
||||
findById: {
|
||||
data: null as FilosofiTriHitaForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
stateFilosofiTriHita.findById.data = {
|
||||
id: "",
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
} as FilosofiTriHitaForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
stateFilosofiTriHita.findById.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.konservasiadatbali.filosofitrihitakarana[
|
||||
"find-by-id"
|
||||
].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
stateFilosofiTriHita.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal mengambil data filosofi tri hita karana");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat mengambil data filosofi tri hita karana"
|
||||
);
|
||||
} finally {
|
||||
stateFilosofiTriHita.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: FilosofiTriHitaForm) {
|
||||
const cek = templateFilosofiTriHitaForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stateFilosofiTriHita.update.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.konservasiadatbali.filosofitrihitakarana[
|
||||
"update"
|
||||
].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Data filosofi tri hita karana berhasil diubah");
|
||||
await stateFilosofiTriHita.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data filosofi tri hita karana");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat mengubah data filosofi tri hita karana"
|
||||
);
|
||||
} finally {
|
||||
stateFilosofiTriHita.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templateNilaiKonservasiAdatForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type NilaiKonservasiAdatForm = Prisma.NilaiKonservasiAdatGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const stateNilaiKonservasiAdat = proxy({
|
||||
findById: {
|
||||
data: null as NilaiKonservasiAdatForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
stateNilaiKonservasiAdat.findById.data = {
|
||||
id: "",
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
} as NilaiKonservasiAdatForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
stateNilaiKonservasiAdat.findById.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.konservasiadatbali.nilaikonservasiadatbali[
|
||||
"find-by-id"
|
||||
].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
stateNilaiKonservasiAdat.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal mengambil data nilai konservasi adat");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat mengambil data nilai konservasi adat"
|
||||
);
|
||||
} finally {
|
||||
stateNilaiKonservasiAdat.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: NilaiKonservasiAdatForm) {
|
||||
const cek = templateNilaiKonservasiAdatForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stateNilaiKonservasiAdat.update.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.konservasiadatbali.nilaikonservasiadatbali[
|
||||
"update"
|
||||
].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Data nilai konservasi adat berhasil diubah");
|
||||
await stateNilaiKonservasiAdat.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data nilai konservasi adat");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat mengubah data nilai konservasi adat"
|
||||
);
|
||||
} finally {
|
||||
stateNilaiKonservasiAdat.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templateBentukKonservasiBerdasarkanAdatForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type BentukKonservasiBerdasarkanAdatForm =
|
||||
Prisma.BentukKonservasiBerdasarkanAdatGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const stateBentukKonservasiBerdasarkanAdat = proxy({
|
||||
findById: {
|
||||
data: null as BentukKonservasiBerdasarkanAdatForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
stateBentukKonservasiBerdasarkanAdat.findById.data = {
|
||||
id: "",
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
} as BentukKonservasiBerdasarkanAdatForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
stateBentukKonservasiBerdasarkanAdat.findById.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.konservasiadatbali.bentukkonservasiberdasarkanadat[
|
||||
"find-by-id"
|
||||
].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
stateBentukKonservasiBerdasarkanAdat.findById.data =
|
||||
res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error(
|
||||
"Gagal mengambil data bentuk konservasi berdasarkan adat"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat mengambil data bentuk konservasi berdasarkan adat"
|
||||
);
|
||||
} finally {
|
||||
stateBentukKonservasiBerdasarkanAdat.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: BentukKonservasiBerdasarkanAdatForm) {
|
||||
const cek = templateBentukKonservasiBerdasarkanAdatForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stateBentukKonservasiBerdasarkanAdat.update.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.konservasiadatbali.bentukkonservasiberdasarkanadat[
|
||||
"update"
|
||||
].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success(
|
||||
"Data bentuk konservasi berdasarkan adat berhasil diubah"
|
||||
);
|
||||
await stateBentukKonservasiBerdasarkanAdat.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data bentuk konservasi berdasarkan adat");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error(
|
||||
"Terjadi kesalahan saat mengubah data bentuk konservasi berdasarkan adat"
|
||||
);
|
||||
} finally {
|
||||
stateBentukKonservasiBerdasarkanAdat.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const stateKonservasiAdatBali = proxy({
|
||||
stateFilosofiTriHita,
|
||||
stateNilaiKonservasiAdat,
|
||||
stateBentukKonservasiBerdasarkanAdat,
|
||||
});
|
||||
|
||||
export default stateKonservasiAdatBali;
|
||||
@@ -0,0 +1,460 @@
|
||||
/* 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, "Nama minimal 1 karakter"),
|
||||
icon: z.string().min(1, "Icon minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
icon: "",
|
||||
};
|
||||
|
||||
const pengelolaanSampah = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(pengelolaanSampah.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
pengelolaanSampah.create.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.pengelolaansampah[
|
||||
"create"
|
||||
].post(pengelolaanSampah.create.form);
|
||||
if (res.status === 200) {
|
||||
pengelolaanSampah.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
pengelolaanSampah.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
// Change to arrow function
|
||||
pengelolaanSampah.findMany.loading = true; // Use the full path to access the property
|
||||
pengelolaanSampah.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.lingkungan.pengelolaansampah[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
pengelolaanSampah.findMany.data = res.data.data || [];
|
||||
pengelolaanSampah.findMany.total = res.data.total || 0;
|
||||
pengelolaanSampah.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load pengelolaan sampah:",
|
||||
res.data?.message
|
||||
);
|
||||
pengelolaanSampah.findMany.data = [];
|
||||
pengelolaanSampah.findMany.total = 0;
|
||||
pengelolaanSampah.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pengelolaan sampah:", error);
|
||||
pengelolaanSampah.findMany.data = [];
|
||||
pengelolaanSampah.findMany.total = 0;
|
||||
pengelolaanSampah.findMany.totalPages = 1;
|
||||
} finally {
|
||||
pengelolaanSampah.findMany.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/lingkungan/pengelolaansampah/${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,
|
||||
icon: data.icon,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal mengambil data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pengelolaan sampah:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/pengelolaansampah/${id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
}
|
||||
);
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await pengelolaanSampah.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data pengelolaan sampah");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.ProgramKreatifGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/lingkungan/pengelolaansampah/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
pengelolaanSampah.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
pengelolaanSampah.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pengelolaan sampah:", error);
|
||||
pengelolaanSampah.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
pengelolaanSampah.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/pengelolaansampah/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(
|
||||
result.message || "pengelolaan sampah berhasil dihapus"
|
||||
);
|
||||
await pengelolaanSampah.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus pengelolaan sampah");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus pengelolaan sampah");
|
||||
} finally {
|
||||
pengelolaanSampah.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const templateKeteranganSampahForm = z.object({
|
||||
name: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
alamat: z.string().min(1, "Alamat minimal 1 karakter"),
|
||||
namaTempatMaps: z.string().min(1, "Nama Tempat Maps minimal 1 karakter"),
|
||||
lat: z.number(),
|
||||
lng: z.number(),
|
||||
});
|
||||
|
||||
const defaultKeteranganSampahForm = {
|
||||
name: "",
|
||||
alamat: "",
|
||||
namaTempatMaps: "",
|
||||
lat: 0,
|
||||
lng: 0,
|
||||
};
|
||||
|
||||
|
||||
const keteranganSampah = proxy({
|
||||
create: {
|
||||
form: { ...defaultKeteranganSampahForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateKeteranganSampahForm.safeParse(
|
||||
keteranganSampah.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
keteranganSampah.create.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.pengelolaansampah.keteranganbankterdekat[
|
||||
"create"
|
||||
].post(keteranganSampah.create.form);
|
||||
if (res.status === 200) {
|
||||
keteranganSampah.findMany.load();
|
||||
return toast.success("Data berhasil ditambahkan");
|
||||
}
|
||||
return toast.error("Gagal menambahkan data");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Gagal menambahkan data");
|
||||
} finally {
|
||||
keteranganSampah.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.KeteranganBankSampahTerdekatGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.lingkungan.pengelolaansampah.keteranganbankterdekat[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
keteranganSampah.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KeteranganBankSampahTerdekatGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
keteranganSampah.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
keteranganSampah.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
keteranganSampah.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
keteranganSampah.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Keterangan sampah berhasil dihapus");
|
||||
await keteranganSampah.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus keterangan sampah");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus keterangan sampah");
|
||||
} finally {
|
||||
keteranganSampah.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultKeteranganSampahForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${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,
|
||||
alamat: data.alamat,
|
||||
namaTempatMaps: data.namaTempatMaps,
|
||||
lat: data.lat,
|
||||
lng: data.lng,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading keterangan sampah:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async update() {
|
||||
const cek = templateKeteranganSampahForm.safeParse(keteranganSampah.edit.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
keteranganSampah.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/lingkungan/pengelolaansampah/keteranganbankterdekat/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: this.form.name,
|
||||
alamat: this.form.alamat,
|
||||
namaTempatMaps: this.form.namaTempatMaps,
|
||||
lat: this.form.lat,
|
||||
lng: this.form.lng,
|
||||
}),
|
||||
}
|
||||
);
|
||||
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 keterangan sampah");
|
||||
await keteranganSampah.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal mengupdate keterangan sampah");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating keterangan sampah:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Gagal mengupdate keterangan sampah"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
keteranganSampah.edit.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
keteranganSampah.edit.id = "";
|
||||
keteranganSampah.edit.form = { ...defaultKeteranganSampahForm };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const pengelolaanSampahState = proxy({
|
||||
pengelolaanSampah,
|
||||
keteranganSampah,
|
||||
});
|
||||
|
||||
export default pengelolaanSampahState;
|
||||
@@ -0,0 +1,227 @@
|
||||
/* 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, "Nama minimal 1 karakter"),
|
||||
deskripsi: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
judul: z.string().min(1, "Judul minimal 1 karakter"),
|
||||
icon: z.string().min(1, "Icon minimal 1 karakter"),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
judul: "",
|
||||
icon: "",
|
||||
};
|
||||
|
||||
const programPenghijauanState = proxy({
|
||||
create: {
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateForm.safeParse(programPenghijauanState.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
programPenghijauanState.create.loading = true;
|
||||
const res = await ApiFetch.api.lingkungan.programpenghijauan["create"].post(
|
||||
programPenghijauanState.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
programPenghijauanState.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
console.log(res);
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
programPenghijauanState.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => {
|
||||
// Change to arrow function
|
||||
programPenghijauanState.findMany.loading = true; // Use the full path to access the property
|
||||
programPenghijauanState.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.lingkungan.programpenghijauan["find-many"].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
programPenghijauanState.findMany.data = res.data.data || [];
|
||||
programPenghijauanState.findMany.total = res.data.total || 0;
|
||||
programPenghijauanState.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to load grafik berdasarkan program penghijauan:",
|
||||
res.data?.message
|
||||
);
|
||||
programPenghijauanState.findMany.data = [];
|
||||
programPenghijauanState.findMany.total = 0;
|
||||
programPenghijauanState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading grafik berdasarkan program penghijauan:", error);
|
||||
programPenghijauanState.findMany.data = [];
|
||||
programPenghijauanState.findMany.total = 0;
|
||||
programPenghijauanState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
programPenghijauanState.findMany.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/lingkungan/programpenghijauan/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
judul: data.judul,
|
||||
icon: data.icon,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal mengambil data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading program penghijauan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateForm.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(`/api/lingkungan/programpenghijauan/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await programPenghijauanState.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data:", error);
|
||||
toast.error("Gagal update data program penghijauan");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.ProgramPenghijauanGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/lingkungan/programpenghijauan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
programPenghijauanState.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
programPenghijauanState.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading program penghijauan:", error);
|
||||
programPenghijauanState.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
programPenghijauanState.delete.loading = true;
|
||||
|
||||
const response = await fetch(`/api/lingkungan/programpenghijauan/del/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Program penghijauan berhasil dihapus");
|
||||
await programPenghijauanState.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus program penghijauan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus program penghijauan");
|
||||
} finally {
|
||||
programPenghijauanState.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default programPenghijauanState;
|
||||
282
src/app/admin/(dashboard)/_state/pendidikan/beasiswa-desa.ts
Normal file
282
src/app/admin/(dashboard)/_state/pendidikan/beasiswa-desa.ts
Normal file
@@ -0,0 +1,282 @@
|
||||
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 templateBeasiswaPendaftar = z.object({
|
||||
namaLengkap: z.string().min(1, "Nama harus diisi"),
|
||||
nik: z.string().min(1, "NIK harus diisi"),
|
||||
tempatLahir: z.string().min(1, "Tempat lahir harus diisi"),
|
||||
tanggalLahir: z.string().min(1, "Tanggal lahir harus diisi"),
|
||||
jenisKelamin: z.string().min(1, "Jenis kelamin harus diisi"),
|
||||
kewarganegaraan: z.string().min(1, "Kewarganegaraan harus diisi"),
|
||||
agama: z.string().min(1, "Agama harus diisi"),
|
||||
alamatKTP: z.string().min(1, "Alamat KTP harus diisi"),
|
||||
alamatDomisili: z.string().min(1, "Alamat domisili harus diisi"),
|
||||
noHp: z.string().min(1, "No HP harus diisi"),
|
||||
email: z.string().min(1, "Email harus diisi"),
|
||||
statusPernikahan: z.string().min(1, "Status pernikahan harus diisi"),
|
||||
ukuranBaju: z.string().min(1, "Ukuran baju harus diisi"),
|
||||
});
|
||||
|
||||
const defaultBeasiswaPendaftar = {
|
||||
namaLengkap: "",
|
||||
nik: "",
|
||||
tempatLahir: "",
|
||||
tanggalLahir: "",
|
||||
jenisKelamin: "",
|
||||
kewarganegaraan: "",
|
||||
agama: "",
|
||||
alamatKTP: "",
|
||||
alamatDomisili: "",
|
||||
noHp: "",
|
||||
email: "",
|
||||
statusPernikahan: "",
|
||||
ukuranBaju: "",
|
||||
};
|
||||
|
||||
const beasiswaPendaftar = proxy({
|
||||
create: {
|
||||
form: { ...defaultBeasiswaPendaftar },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateBeasiswaPendaftar.safeParse(
|
||||
beasiswaPendaftar.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
beasiswaPendaftar.create.loading = true;
|
||||
const res = await ApiFetch.api.pendidikan.beasiswa.beasiswapendaftar[
|
||||
"create"
|
||||
].post(beasiswaPendaftar.create.form);
|
||||
if (res.status === 200) {
|
||||
beasiswaPendaftar.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 {
|
||||
beasiswaPendaftar.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: [] as Prisma.BeasiswaPendaftarGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}>[],
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.pendidikan.beasiswa.beasiswapendaftar[
|
||||
"findMany"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
beasiswaPendaftar.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.BeasiswaPendaftarGetPayload<{
|
||||
omit: {
|
||||
isActive: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/pendidikan/beasiswa/beasiswapendaftar/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
beasiswaPendaftar.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
beasiswaPendaftar.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
beasiswaPendaftar.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async delete(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
beasiswaPendaftar.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/pendidikan/beasiswa/beasiswapendaftar/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Beasiswa berhasil dihapus");
|
||||
await beasiswaPendaftar.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus beasiswa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus beasiswa");
|
||||
} finally {
|
||||
beasiswaPendaftar.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultBeasiswaPendaftar },
|
||||
loading: false,
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/pendidikan/beasiswa/beasiswapendaftar/${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 = {
|
||||
namaLengkap: data.namaLengkap,
|
||||
nik: data.nik,
|
||||
tempatLahir: data.tempatLahir,
|
||||
tanggalLahir: data.tanggalLahir,
|
||||
jenisKelamin: data.jenisKelamin,
|
||||
kewarganegaraan: data.kewarganegaraan,
|
||||
agama: data.agama,
|
||||
alamatKTP: data.alamatKTP,
|
||||
alamatDomisili: data.alamatDomisili,
|
||||
noHp: data.noHp,
|
||||
email: data.email,
|
||||
statusPernikahan: data.statusPernikahan,
|
||||
ukuranBaju: data.ukuranBaju,
|
||||
};
|
||||
return data; // Return the loaded data
|
||||
} else {
|
||||
throw new Error(result?.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading beasiswa pendaftar:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templateBeasiswaPendaftar.safeParse(
|
||||
beasiswaPendaftar.update.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
beasiswaPendaftar.update.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/pendidikan/beasiswa/beasiswapendaftar/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
namaLengkap: this.form.namaLengkap,
|
||||
nik: this.form.nik,
|
||||
tanggalLahir: this.form.tanggalLahir,
|
||||
jenisKelamin: this.form.jenisKelamin,
|
||||
kewarganegaraan: this.form.kewarganegaraan,
|
||||
agama: this.form.agama,
|
||||
alamatKTP: this.form.alamatKTP,
|
||||
alamatDomisili: this.form.alamatDomisili,
|
||||
noHp: this.form.noHp,
|
||||
email: this.form.email,
|
||||
statusPernikahan: this.form.statusPernikahan,
|
||||
ukuranBaju: this.form.ukuranBaju,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
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 beasiswa pendaftar");
|
||||
await beasiswaPendaftar.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal update beasiswa pendaftar");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating beasiswa pendaftar:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update beasiswa pendaftar"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
beasiswaPendaftar.update.loading = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
beasiswaPendaftar.update.id = "";
|
||||
beasiswaPendaftar.update.form = { ...defaultBeasiswaPendaftar };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const beasiswaDesaState = proxy({
|
||||
beasiswaPendaftar,
|
||||
});
|
||||
|
||||
export default beasiswaDesaState;
|
||||
@@ -0,0 +1,260 @@
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
// ========================================= TUJUAN PROGRAM ========================================= //
|
||||
|
||||
const templateTujuanProgramForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type TujuanProgramForm = Prisma.TujuanBimbinganBelajarDesaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const stateTujuanProgram = proxy({
|
||||
findById: {
|
||||
data: null as TujuanProgramForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
stateTujuanProgram.findById.data = {
|
||||
id: "",
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
} as TujuanProgramForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
stateTujuanProgram.findById.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.bimbinganbelajardesa.tujuanprogram[
|
||||
"find-by-id"
|
||||
].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
stateTujuanProgram.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal mengambil data tujuan program");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data tujuan program");
|
||||
} finally {
|
||||
stateTujuanProgram.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: TujuanProgramForm) {
|
||||
const cek = templateTujuanProgramForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stateTujuanProgram.update.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.bimbinganbelajardesa.tujuanprogram[
|
||||
"update"
|
||||
].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Data tujuan program berhasil diubah");
|
||||
await stateTujuanProgram.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data tujuan program");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengubah data tujuan program");
|
||||
} finally {
|
||||
stateTujuanProgram.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= LOKASI DAN JADWAL ========================================= //
|
||||
|
||||
const templateLokasiDanJadwalForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type LokasiDanJadwalForm = Prisma.LokasiJadwalBimbinganBelajarDesaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const lokasiDanJadwalState = proxy({
|
||||
findById: {
|
||||
data: null as LokasiDanJadwalForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
lokasiDanJadwalState.findById.data = {
|
||||
id: "",
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
} as LokasiDanJadwalForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
lokasiDanJadwalState.findById.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.bimbinganbelajardesa.lokasidanjadwal[
|
||||
"find-by-id"
|
||||
].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
lokasiDanJadwalState.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal mengambil data lokasi dan jadwal");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data lokasi dan jadwal");
|
||||
} finally {
|
||||
lokasiDanJadwalState.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: LokasiDanJadwalForm) {
|
||||
const cek = templateLokasiDanJadwalForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
lokasiDanJadwalState.update.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.bimbinganbelajardesa.lokasidanjadwal[
|
||||
"update"
|
||||
].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Data lokasi dan jadwal berhasil diubah");
|
||||
await lokasiDanJadwalState.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data lokasi dan jadwal");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengubah data lokasi dan jadwal");
|
||||
} finally {
|
||||
lokasiDanJadwalState.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ========================================= FASILITAS YANG DISEDIAKAN ========================================= //
|
||||
|
||||
const templateFasilitasYangDisediakanForm = z.object({
|
||||
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
});
|
||||
|
||||
type FasilitasYangDisediakanForm = Prisma.FasilitasBimbinganBelajarDesaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
judul: true;
|
||||
deskripsi: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const fasilitasYangDisediakanState = proxy({
|
||||
findById: {
|
||||
data: null as FasilitasYangDisediakanForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
fasilitasYangDisediakanState.findById.data = {
|
||||
id: "",
|
||||
judul: "",
|
||||
deskripsi: "",
|
||||
} as FasilitasYangDisediakanForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
fasilitasYangDisediakanState.findById.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.bimbinganbelajardesa.fasilitasyangdisediakan[
|
||||
"find-by-id"
|
||||
].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
fasilitasYangDisediakanState.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
toast.error("Gagal mengambil data fasilitas yang disediakan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data fasilitas yang disediakan");
|
||||
} finally {
|
||||
fasilitasYangDisediakanState.findById.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: FasilitasYangDisediakanForm) {
|
||||
const cek = templateFasilitasYangDisediakanForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fasilitasYangDisediakanState.update.loading = true;
|
||||
const res =
|
||||
await ApiFetch.api.pendidikan.bimbinganbelajardesa.fasilitasyangdisediakan[
|
||||
"update"
|
||||
].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Data fasilitas yang disediakan berhasil diubah");
|
||||
await fasilitasYangDisediakanState.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal mengubah data fasilitas yang disediakan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengubah data fasilitas yang disediakan");
|
||||
} finally {
|
||||
fasilitasYangDisediakanState.update.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const stateBimbinganBelajarDesa = proxy({
|
||||
stateTujuanProgram,
|
||||
lokasiDanJadwalState,
|
||||
fasilitasYangDisediakanState,
|
||||
});
|
||||
|
||||
export default stateBimbinganBelajarDesa;
|
||||
178
src/app/admin/(dashboard)/_state/pendidikan/data-pendidikan.ts
Normal file
178
src/app/admin/(dashboard)/_state/pendidikan/data-pendidikan.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
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 templateDataPendidikan = z.object({
|
||||
name: z.string().min(1, "Data nama harus diisi"),
|
||||
jumlah: z.string().min(1, "Data jumlah harus diisi"),
|
||||
});
|
||||
|
||||
type DataPendidikan = Prisma.DataPendidikanGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
name: true;
|
||||
jumlah: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const defaultForm: Omit<DataPendidikan, "id"> & { id?: string } = {
|
||||
name: "",
|
||||
jumlah: "",
|
||||
};
|
||||
|
||||
const dataPendidikan = proxy({
|
||||
create: {
|
||||
form: defaultForm,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDataPendidikan.safeParse(dataPendidikan.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
dataPendidikan.create.loading = true;
|
||||
const res = await ApiFetch.api.pendidikan.datapendidikan["create"].post(
|
||||
dataPendidikan.create.form
|
||||
);
|
||||
if (res.status === 200) {
|
||||
const id = res.data?.data?.id;
|
||||
if (id) {
|
||||
toast.success("Success create");
|
||||
dataPendidikan.create.form = {
|
||||
name: "",
|
||||
jumlah: "",
|
||||
};
|
||||
dataPendidikan.findMany.load();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
dataPendidikan.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DataPendidikanGetPayload<{
|
||||
select: { id: true; name: true; jumlah: true };
|
||||
}>[]
|
||||
| null,
|
||||
loading: false,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.pendidikan.datapendidikan[
|
||||
"findMany"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
dataPendidikan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.DataPendidikanGetPayload<{
|
||||
select: { id: true; name: true; jumlah: true };
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(`/api/pendidikan/datapendidikan/${id}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
dataPendidikan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch data", res.status, res.statusText);
|
||||
dataPendidikan.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading data pendidikan:", error);
|
||||
dataPendidikan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
update: {
|
||||
id: "",
|
||||
form: { ...defaultForm },
|
||||
loading: false,
|
||||
async byId() {
|
||||
// Method implementation if needed
|
||||
},
|
||||
async submit() {
|
||||
const id = this.id;
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
const cek = templateDataPendidikan.safeParse(this.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => (v.path as string[]).join("."))
|
||||
.join("\n")}] required`;
|
||||
toast.error(err);
|
||||
return null;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(`/api/pendidikan/datapendidikan/${id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result?.success) {
|
||||
throw new Error(result?.message || "Gagal update data");
|
||||
}
|
||||
toast.success("Berhasil update data!");
|
||||
await dataPendidikan.findMany.load();
|
||||
return result.data;
|
||||
} catch (error) {
|
||||
console.error("Error update data data pendidikan:", error);
|
||||
toast.error("Gagal update data data pendidikan");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
|
||||
try {
|
||||
dataPendidikan.delete.loading = true;
|
||||
|
||||
const response = await fetch(
|
||||
`/api/pendidikan/datapendidikan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result?.success) {
|
||||
toast.success(result.message || "Data berhasil dihapus");
|
||||
await dataPendidikan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result?.message || "Gagal menghapus data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete data pendidikan:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus data pendidikan");
|
||||
} finally {
|
||||
dataPendidikan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
export default dataPendidikan;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user