Compare commits
6 Commits
nico/31-ju
...
nico/4-aug
| Author | SHA1 | Date | |
|---|---|---|---|
| a2b68ec78b | |||
| 0e55462adc | |||
| 73ae198158 | |||
| 9d14bb0c56 | |||
| 1cdff53c56 | |||
| 54312e9486 |
22
prisma/data/landing-page/apbdes/apbdes.json
Normal file
22
prisma/data/landing-page/apbdes/apbdes.json
Normal file
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"id": "cmdwq7qp60008vntw67s4j6sq",
|
||||
"name": "Pembiayaan",
|
||||
"jumlah": "295 M"
|
||||
},
|
||||
{
|
||||
"id": "cmdwpsprc0003vntw9o4d33dr",
|
||||
"name": "Pendapatan",
|
||||
"jumlah": "495 M"
|
||||
},
|
||||
{
|
||||
"id": "cmdwqe8xl000cvntwcuqpvdhp",
|
||||
"name": "Belanja",
|
||||
"jumlah": "395 M"
|
||||
},
|
||||
{
|
||||
"id": "cmdwqq4b6000gvntwm07rinx4",
|
||||
"name": "Pangan",
|
||||
"jumlah": "285 M"
|
||||
}
|
||||
]
|
||||
128
prisma/data/landing-page/desa-anti-korupsi/desaantiKorpusi.json
Normal file
128
prisma/data/landing-page/desa-anti-korupsi/desaantiKorpusi.json
Normal file
@@ -0,0 +1,128 @@
|
||||
[
|
||||
{
|
||||
"id": "cmds9h9ko000pvnberdjnx64b",
|
||||
"name": "1.1 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmds9sjmz000svnbesv2133of",
|
||||
"name": "1.2 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmds9tcpi000vvnbev3ebtlnt",
|
||||
"name": "1.3 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmds9twvj000yvnbep0pq8dzf",
|
||||
"name": "1.4 PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA",
|
||||
"deskripsi": "<p>PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmds9ugap0011vnbe118yv871",
|
||||
"name": "1.5 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA",
|
||||
"deskripsi": "<p>ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA</p>",
|
||||
"kategoriId": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsa35310014vnbe6qy6l1rz",
|
||||
"name": "2.1 ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA",
|
||||
"deskripsi": "<p>ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsa46590017vnbepp3noso1",
|
||||
"name": "2.2 ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH",
|
||||
"deskripsi": "<p>ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsa5m7z001avnbe4cvfrcz0",
|
||||
"name": "2.3 TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI",
|
||||
"deskripsi": "<p>TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsa8q5q001dvnbemch8j24x",
|
||||
"name": "3.1 ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT",
|
||||
"deskripsi": "<p>ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsa9lbi001gvnbequn2ba7m",
|
||||
"name": "3.2 ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA",
|
||||
"deskripsi": "<p>ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsaa7aq001jvnbeizh04e67",
|
||||
"name": "3.3 ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA",
|
||||
"deskripsi": "<p>ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsaaw8d001mvnbek3tfefrk",
|
||||
"name": "3.4 ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT",
|
||||
"deskripsi": "<p>ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsabhif001pvnbepm06hry6",
|
||||
"name": "3.5 ADANYA MAKLUMAT PELAYANAN",
|
||||
"deskripsi": "<p>ADANYA MAKLUMAT PELAYANAN</p>",
|
||||
"kategoriId": "cmds9fr73000kvnbe6w281dcl",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsag40b001svnbe7krq9khc",
|
||||
"name": "4.1 ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA",
|
||||
"deskripsi": "<p>ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsagkaf001vvnbejo26w8sa",
|
||||
"name": "4.2 ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
"deskripsi": "<p>ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsah4qe001yvnbeiy3mwrvb",
|
||||
"name": "4.3 ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA",
|
||||
"deskripsi": "<p>ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA</p>",
|
||||
"kategoriId": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsak5vn0021vnbemg86aab4",
|
||||
"name": "5.1 ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||
"deskripsi": "<p>ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
||||
"fileId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsalc800024vnbezgulhgrb",
|
||||
"name": "5.2 ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||
"deskripsi": "<p>ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI</p>",
|
||||
"kategoriId": "cmds9govb000mvnbesq8b4y99",
|
||||
"fileId": ""
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"id": "cmds9es2o000ivnbe1o0swrvh",
|
||||
"name": "PENGUATAN TATA LAKSANA"
|
||||
},
|
||||
{
|
||||
"id": "cmds9f2ua000jvnbeksu1sfwm",
|
||||
"name": "PENGUATAN PENGAWASAN"
|
||||
},
|
||||
{
|
||||
"id": "cmds9fr73000kvnbe6w281dcl",
|
||||
"name": "PENGUATAN KUALITAS PELAYANAN PUBLIK"
|
||||
},
|
||||
{
|
||||
"id": "cmds9g5ow000lvnbel3rkkwrv",
|
||||
"name": "PENGUATAN PARTISIPASI MASYARAKAT"
|
||||
},
|
||||
{
|
||||
"id": "cmds9govb000mvnbesq8b4y99",
|
||||
"name": "KEARIFAN LOKAL"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"id": "cmdwrolsl0000vnd3e24q5440",
|
||||
"name": "Olahraga dan Kepemudaan"
|
||||
},
|
||||
{
|
||||
"id": "cmdwrot900001vnd30b5kj96g",
|
||||
"name": "Hukum dan Kesadaran Masyarakat"
|
||||
},
|
||||
{
|
||||
"id": "cmdwrp0pr0002vnd35w6nkjh0",
|
||||
"name": "Tata Kelola dan Inovasi Desa"
|
||||
}
|
||||
]
|
||||
20
prisma/data/landing-page/prestasi-desa/prestasi-desa.json
Normal file
20
prisma/data/landing-page/prestasi-desa/prestasi-desa.json
Normal file
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"id": "cmdwrrxkh0005vnd3p5rxkiev",
|
||||
"name": "Tim Bola Voli Putri Dharma Temaja meraih juara 3 dalam Turnamen Bola Voli Mangupura Cup 2024 kategori Putri Se-Bali",
|
||||
"deskripsi": "<p>Tim Bola Voli Putri Dharma Temaja meraih juara 3 dalam Turnamen Bola Voli Mangupura Cup 2024 kategori Putri Se-Bali</p>",
|
||||
"kategoriId": "cmdwrolsl0000vnd3e24q5440"
|
||||
},
|
||||
{
|
||||
"id": "cmdwrzs740008vnd329ysez5x",
|
||||
"name": "Prestasi Juara 3 dalam Lomba Keluarga Sadar Hukum Kabupaten Badung Tahun 2024",
|
||||
"deskripsi": "<p>Prestasi Juara 3 dalam Lomba Keluarga Sadar Hukum Kabupaten Badung Tahun 2024</p>",
|
||||
"kategoriId": "cmdwrot900001vnd30b5kj96g"
|
||||
},
|
||||
{
|
||||
"id": "cmdws0sgq000bvnd32o7m94im",
|
||||
"name": "Peringkat 5 Dalam Ajang Bergengsi Mangupura Award",
|
||||
"deskripsi": "<p>Peringkat 5 Dalam Ajang Bergengsi Mangupura Award</p>",
|
||||
"kategoriId": "cmdwrp0pr0002vnd35w6nkjh0"
|
||||
}
|
||||
]
|
||||
@@ -1,8 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
||||
"position": "Perbekel Darmasaba periode 2021-2027"
|
||||
}
|
||||
]
|
||||
|
||||
32
prisma/data/landing-page/profile/mediaSosial.json
Normal file
32
prisma/data/landing-page/profile/mediaSosial.json
Normal file
@@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"id": "cmds8w2q60002vnbe6i8qhkuo",
|
||||
"name": "Telephone Desa Darmasaba",
|
||||
"iconUrl": "081239580000"
|
||||
},
|
||||
{
|
||||
"id": "cmds8z7u20005vnbegyyvnbk0",
|
||||
"name": "Email Desa Darmasaba",
|
||||
"iconUrl": "desadarmasaba@badungkab.go.id"
|
||||
},
|
||||
{
|
||||
"id": "cmds9023u0008vnbe3oxmhwyf",
|
||||
"name": "Desa Darmasaba",
|
||||
"iconUrl": "https://www.youtube.com/channel/UCtPw9WOQO7d2HIKzKgel4Xg"
|
||||
},
|
||||
{
|
||||
"id": "cmds90oul000bvnbe2bqkptoi",
|
||||
"name": "Pemerintah Desa Darmasaba",
|
||||
"iconUrl": "https://www.facebook.com/DarmasabaDesaku"
|
||||
},
|
||||
{
|
||||
"id": "cmds91i4e000evnbe8gtf1gub",
|
||||
"name": "ddarmasaba",
|
||||
"iconUrl": "https://www.instagram.com/ddarmasaba/"
|
||||
},
|
||||
{
|
||||
"id": "cmds92de5000hvnbemlu6sq5x",
|
||||
"name": "desa.darmasaba",
|
||||
"iconUrl": "https://www.tiktok.com/@desa.darmasaba?is_from_webapp=1&sender_device=pc"
|
||||
}
|
||||
]
|
||||
7
prisma/data/landing-page/profile/profile.json
Normal file
7
prisma/data/landing-page/profile/profile.json
Normal file
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "edit",
|
||||
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
||||
"position": "Perbekel Darmasaba periode 2021-2027"
|
||||
}
|
||||
]
|
||||
50
prisma/data/landing-page/profile/programInovasi.json
Normal file
50
prisma/data/landing-page/profile/programInovasi.json
Normal file
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"id": "cmdr7039z0002vn5rttctt9hn",
|
||||
"name": "Davest",
|
||||
"description": "Darmasaba Village Festval",
|
||||
"link": "https://darmasaba.desa.id/berita/55862-rakor-davest-2024"
|
||||
},
|
||||
{
|
||||
"id": "cmdr755pf0005vn5rp8tyuubw",
|
||||
"name": "Dmangan",
|
||||
"description": "Darmasaba Aman Pangan",
|
||||
"link": "https://darmasaba.desa.id/berita/61452-kader-d-mangan-berhasil-meraih-prestasi-dalam-ajang-lomba-banjar-bali-quis-bbq-tahun-2024"
|
||||
},
|
||||
{
|
||||
"id": "cmdr76nqk0008vn5rdddvcxnr",
|
||||
"name": "Bicara Darmasaba",
|
||||
"description": "Bicara Darmasaba",
|
||||
"link": "https://darmasaba.desa.id/berita/42506-bicara-darmasaba"
|
||||
},
|
||||
{
|
||||
"id": "cmdr77vbw000bvn5rvpmoq31s",
|
||||
"name": "Bares",
|
||||
"description": "Darmasaba Recycling Stock/Exchange",
|
||||
"link": "http://darmasaba.desa.id/berita/56722-bares"
|
||||
},
|
||||
{
|
||||
"id": "cmdr7bxtp000evn5rmy85wihx",
|
||||
"name": "Sajjana Dharma Raksaka",
|
||||
"description": "Sajjana Dharma Raksaka",
|
||||
"link": "https://ppid.badungkab.go.id/storage/dokumen/5RS9dldGkrgzMQq6bKdZsqsVRHI8gffWv4PGfb3r.pdf"
|
||||
},
|
||||
{
|
||||
"id": "cmdr7dlnk000hvn5r9lur3z35",
|
||||
"name": "PDKT",
|
||||
"description": "Perangkat Desa Kuat Teknologi",
|
||||
"link": "https://darmasaba.desa.id/berita/53752-p-d-k-t"
|
||||
},
|
||||
{
|
||||
"id": "cmdr7ftob000mvn5rfhgdtg8v",
|
||||
"name": "GM",
|
||||
"description": "Galah Melah",
|
||||
"link": "https://darmasaba.desa.id/berita/52880-galah-melah"
|
||||
},
|
||||
{
|
||||
"id": "cmdr7glue000pvn5r6onzslju",
|
||||
"name": "Inovasi Desa Darmasaba",
|
||||
"description": "Inovasi Desa Darmasaba",
|
||||
"link": "https://darmasaba.desa.id/produk-lokal-desa"
|
||||
}
|
||||
]
|
||||
114
prisma/data/landing-page/sdgs-desa/sdgs-desa.json
Normal file
114
prisma/data/landing-page/sdgs-desa/sdgs-desa.json
Normal file
@@ -0,0 +1,114 @@
|
||||
[
|
||||
{
|
||||
"id": "cmdsjzdl30002vneknuvo4irv",
|
||||
"name": "Desa Tanpa Kemiskinan",
|
||||
"jumlah": "52.62",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskargd0005vnek0mu2ofk9",
|
||||
"name": "Desa Tanpa Kelaparan",
|
||||
"jumlah": "35.75",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskbvl0008vnek5dmieatb",
|
||||
"name": "Desa Sehat Dan Sejahtera",
|
||||
"jumlah": "77.37",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskcx91000bvneko7tuaoqa",
|
||||
"name": "Pendidikan Desa Berkualitas",
|
||||
"jumlah": "34.11",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskjare000evnek1hglu0x8",
|
||||
"name": "Keterlibatan Perempuan Desa",
|
||||
"jumlah": "45.70",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskqcpc0002vnvnqjkqgm92",
|
||||
"name": "Desa Layak Air Bersih Dan Sanitasi",
|
||||
"jumlah": "48.54",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsktl3x0005vnvne15seefw",
|
||||
"name": "Desa Berenergi Bersih Dan Terbarukan",
|
||||
"jumlah": "99.64",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskuncw0008vnvcsdqoeog",
|
||||
"name": "Pertumbuhan Ekonomi Desa Merata",
|
||||
"jumlah": "40.92",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskw83j000bvvn9szqrea6",
|
||||
"name": "Infrastruktur Dan Inovasi Desa Sesuai Kebutuhan",
|
||||
"jumlah": "35.37",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskwrq7000envnvy0c5nbgf",
|
||||
"name": "Desa Tanpa Kesenjangan",
|
||||
"jumlah": "35.47",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskxivx000hnvnvsx520gv1",
|
||||
"name": "Kawasan Pemukiman Desa Aman Dan Nyaman",
|
||||
"jumlah": "40.35",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdskzg4c000kvnnkiv61gkt",
|
||||
"name": "Konsumsi Dan Produksi Desa Sadar Lingkungan",
|
||||
"jumlah": "16.67",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsl07lk000nvnnvnrepsdy5m",
|
||||
"name": "Desa Tanggap Perubahan Iklim",
|
||||
"jumlah": "0.00",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsl10rq000qvnvnlch9c1yv",
|
||||
"name": "Desa Peduli Lingkungan Laut",
|
||||
"jumlah": "50.00",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsl1mc2000tvnvn357n8usi",
|
||||
"name": "Desa Peduli Lingkungan Darat",
|
||||
"jumlah": "0.00",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsl2bx3000wvnvntshi4gnj",
|
||||
"name": "Desa Damai Berkeadilan",
|
||||
"jumlah": "78.65",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsl2yz3000zvnvnmf60ok7q",
|
||||
"name": "Kemitraan Untuk Pembangunan Desa",
|
||||
"jumlah": "20.00",
|
||||
"imageId": ""
|
||||
},
|
||||
{
|
||||
"id": "cmdsl492h0012vnvnmckm3n2x",
|
||||
"name": "Kelembagaan Desa Dinamis Dan Budaya Desa Adaptif",
|
||||
"jumlah": "47.22",
|
||||
"imageId": ""
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ model FileStorage {
|
||||
Posyandu Posyandu[]
|
||||
StrukturPPID StrukturPPID[]
|
||||
GalleryFoto GalleryFoto[]
|
||||
PelayananSuratKeterangan PelayananSuratKeterangan[]
|
||||
|
||||
Pelapor Pelapor[]
|
||||
Penghargaan Penghargaan[]
|
||||
ProfileDesaImage ProfileDesaImage[]
|
||||
ProfilePPID ProfilePPID[]
|
||||
@@ -78,7 +79,8 @@ model FileStorage {
|
||||
InfoWabahPenyakit InfoWabahPenyakit[]
|
||||
KeamananLingkungan KeamananLingkungan[]
|
||||
MenuTipsKeamanan MenuTipsKeamanan[]
|
||||
Pelapor Pelapor[]
|
||||
PelayananSuratKeteranganImage PelayananSuratKeterangan[] @relation("PelayananSuratKeteranganImage")
|
||||
PelayananSuratKeteranganImage2 PelayananSuratKeterangan[] @relation("PelayananSuratKeteranganImage2")
|
||||
PasarDesa PasarDesa[]
|
||||
KontakDaruratKeamanan KontakDaruratKeamanan[]
|
||||
KontakItem KontakItem[]
|
||||
@@ -100,6 +102,7 @@ model FileStorage {
|
||||
DataPerpustakaan DataPerpustakaan[]
|
||||
|
||||
PegawaiPPID PegawaiPPID[]
|
||||
|
||||
}
|
||||
|
||||
//========================================= MENU LANDING PAGE ========================================= //
|
||||
@@ -130,15 +133,15 @@ model ProgramInovasi {
|
||||
}
|
||||
|
||||
model MediaSosial {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
iconUrl String? @db.VarChar(255)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
iconUrl String? @db.VarChar(255)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
isActive Boolean @default(true)
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
//========================================= PROFILE ========================================= //
|
||||
@@ -148,8 +151,8 @@ model DesaAntiKorupsi {
|
||||
deskripsi String @db.Text
|
||||
kategori KategoriDesaAntiKorupsi @relation(fields: [kategoriId], references: [id])
|
||||
kategoriId String
|
||||
file FileStorage @relation(fields: [fileId], references: [id])
|
||||
fileId String
|
||||
file FileStorage? @relation(fields: [fileId], references: [id])
|
||||
fileId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
@@ -168,30 +171,30 @@ model KategoriDesaAntiKorupsi {
|
||||
|
||||
//========================================= SDGS Desa ========================================= //
|
||||
model SDGSDesa {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
jumlah String
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
//========================================= APBDes ========================================= //
|
||||
model APBDes {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
jumlah String
|
||||
image FileStorage @relation("APBDesImage", fields: [imageId], references: [id])
|
||||
imageId String
|
||||
file FileStorage @relation("APBDesFile", fields: [fileId], references: [id])
|
||||
fileId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
image FileStorage? @relation("APBDesImage", fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
file FileStorage? @relation("APBDesFile", fields: [fileId], references: [id])
|
||||
fileId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
//========================================= PRESTASI DESA ========================================= //
|
||||
@@ -313,14 +316,14 @@ model StrukturPPID {
|
||||
}
|
||||
|
||||
model PosisiOrganisasiPPID {
|
||||
id String @id @default(cuid())
|
||||
nama String @db.VarChar(100)
|
||||
deskripsi String? @db.Text
|
||||
id String @id @default(cuid())
|
||||
nama String @db.VarChar(100)
|
||||
deskripsi String? @db.Text
|
||||
hierarki Int
|
||||
pegawai PegawaiPPID[]
|
||||
strukturOrganisasi StrukturPPID[] // Relasi balik
|
||||
parentId String?
|
||||
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
||||
parentId String?
|
||||
parent PosisiOrganisasiPPID? @relation("Parent", fields: [parentId], references: [id])
|
||||
children PosisiOrganisasiPPID[] @relation("Parent")
|
||||
}
|
||||
|
||||
@@ -672,15 +675,17 @@ model GalleryVideo {
|
||||
|
||||
// ========================================= LAYANAN DESA ========================================= //
|
||||
model PelayananSuratKeterangan {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
deskripsi String @db.Text
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
deskripsi String @db.Text
|
||||
image FileStorage? @relation("PelayananSuratKeteranganImage", fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
image2 FileStorage? @relation("PelayananSuratKeteranganImage2", fields: [image2Id], references: [id])
|
||||
image2Id String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model PelayananTelunjukSaktiDesa {
|
||||
|
||||
186
prisma/seed.ts
186
prisma/seed.ts
@@ -1,4 +1,9 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import profilePejabatDesa from "./data/landing-page/profile/profile.json";
|
||||
import programInovasi from "./data/landing-page/profile/programInovasi.json";
|
||||
import mediaSosial from "./data/landing-page/profile/mediaSosial.json";
|
||||
import sdgsDesa from "./data/landing-page/sdgs-desa/sdgs-desa.json";
|
||||
import apbdes from "./data/landing-page/apbdes/apbdes.json";
|
||||
import categoryPengumuman from "./data/category-pengumuman.json";
|
||||
import kategoriBerita from "./data/kategori-berita.json";
|
||||
import caraMemperolehInformasi from "./data/list-caraMemperolehInformasi.json";
|
||||
@@ -20,27 +25,82 @@ 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';
|
||||
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 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";
|
||||
import posisiOrganisasiPPID from "./data/ppid/struktur-ppid/posisi-organisasi-PPID.json";
|
||||
import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
|
||||
|
||||
(async () => {
|
||||
// =========== LANDING PAGE ===========
|
||||
// =========== PROFILE ===========
|
||||
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)"
|
||||
);
|
||||
|
||||
// =========== PROGRAM INOVASI ===========
|
||||
for (const p of programInovasi) {
|
||||
await prisma.programInovasi.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
description: p.description,
|
||||
link: p.link,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
description: p.description,
|
||||
link: p.link,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("program inovasi success ...");
|
||||
|
||||
// =========== MEDIA SOSIAL ===========
|
||||
for (const p of mediaSosial) {
|
||||
await prisma.mediaSosial.upsert({
|
||||
where: { id: p.id },
|
||||
update: {
|
||||
name: p.name,
|
||||
iconUrl: p.iconUrl,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
iconUrl: p.iconUrl,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("media sosial success ...");
|
||||
|
||||
// =========== LAYANAN ===========
|
||||
for (const l of layanan) {
|
||||
await prisma.layanan.upsert({
|
||||
where: {
|
||||
@@ -57,6 +117,46 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
|
||||
console.log("layanan success ...");
|
||||
|
||||
// =========== SDGSDesa ===========
|
||||
for (const l of sdgsDesa) {
|
||||
await prisma.sDGSDesa.upsert({
|
||||
where: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
update: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
create: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("sdgs desa success ...");
|
||||
|
||||
// =========== APBDes ===========
|
||||
for (const l of apbdes) {
|
||||
await prisma.aPBDes.upsert({
|
||||
where: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
update: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
create: {
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("sdgs desa success ...");
|
||||
|
||||
for (const l of sejarahDesa) {
|
||||
await prisma.sejarahDesa.upsert({
|
||||
where: {
|
||||
@@ -134,7 +234,9 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ profilePerbekel seeded without imageId (editable later via UI)");
|
||||
console.log(
|
||||
"✅ profilePerbekel seeded without imageId (editable later via UI)"
|
||||
);
|
||||
|
||||
for (const l of visiMisiDesa) {
|
||||
await prisma.visiMisiDesa.upsert({
|
||||
@@ -157,7 +259,7 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
|
||||
// Flatten the nested array structure for posisiOrganisasiPPID
|
||||
const flattenedPosisiOrganisasiPPID = posisiOrganisasiPPID.flat();
|
||||
|
||||
|
||||
for (const p of flattenedPosisiOrganisasiPPID) {
|
||||
await prisma.posisiOrganisasiPPID.upsert({
|
||||
where: {
|
||||
@@ -182,7 +284,7 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
|
||||
// Flatten the nested array structure for pegawaiPPID
|
||||
const flattenedPegawaiPPID = pegawaiPPID.flat();
|
||||
|
||||
|
||||
for (const p of flattenedPegawaiPPID) {
|
||||
await prisma.pegawaiPPID.upsert({
|
||||
where: {
|
||||
@@ -252,7 +354,6 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
}
|
||||
console.log("pelayanan penduduk non permanen success ...");
|
||||
|
||||
|
||||
for (const p of potensi) {
|
||||
await prisma.potensi.upsert({
|
||||
where: {
|
||||
@@ -422,7 +523,6 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
}
|
||||
console.log("kategori produk success ...");
|
||||
|
||||
|
||||
for (const p of posisiOrganisasi) {
|
||||
await prisma.posisiOrganisasi.upsert({
|
||||
where: {
|
||||
@@ -611,7 +711,6 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
|
||||
console.log("bentuk konservasi berdasarkan adat success ...");
|
||||
|
||||
|
||||
for (const n of nilaiKonservasiAdat) {
|
||||
await prisma.nilaiKonservasiAdat.upsert({
|
||||
where: {
|
||||
@@ -631,22 +730,6 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
|
||||
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 },
|
||||
@@ -693,7 +776,9 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ tujuan bimbingan belajar desa seeded (editable later via UI)");
|
||||
console.log(
|
||||
"✅ tujuan bimbingan belajar desa seeded (editable later via UI)"
|
||||
);
|
||||
|
||||
for (const t of lokasiJadwalBimbinganBelajarDesa) {
|
||||
await prisma.lokasiJadwalBimbinganBelajarDesa.upsert({
|
||||
@@ -709,7 +794,9 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ lokasi jadwal bimbingan belajar desa seeded (editable later via UI)");
|
||||
console.log(
|
||||
"✅ lokasi jadwal bimbingan belajar desa seeded (editable later via UI)"
|
||||
);
|
||||
|
||||
for (const t of fasilitasBimbinganBelajarDesa) {
|
||||
await prisma.fasilitasBimbinganBelajarDesa.upsert({
|
||||
@@ -725,7 +812,9 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ fasilitas bimbingan belajar desa seeded (editable later via UI)");
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)"
|
||||
);
|
||||
|
||||
for (const t of tujuanProgram2) {
|
||||
await prisma.tujuanPendidikanNonFormal.upsert({
|
||||
@@ -741,7 +830,9 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ fasilitas bimbingan belajar desa seeded (editable later via UI)");
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)"
|
||||
);
|
||||
|
||||
for (const t of tempatKegiatan) {
|
||||
await prisma.tempatKegiatan.upsert({
|
||||
@@ -757,7 +848,9 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ fasilitas bimbingan belajar desa seeded (editable later via UI)");
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)"
|
||||
);
|
||||
|
||||
for (const t of jenisProgramYangDiselenggarakan) {
|
||||
await prisma.jenisProgramYangDiselenggarakan.upsert({
|
||||
@@ -773,8 +866,9 @@ import pegawaiPPID from "./data/ppid/struktur-ppid/pegawai-PPID.json";
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ fasilitas bimbingan belajar desa seeded (editable later via UI)");
|
||||
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)"
|
||||
);
|
||||
})()
|
||||
.then(() => prisma.$disconnect())
|
||||
.catch((e) => {
|
||||
|
||||
@@ -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";
|
||||
@@ -8,12 +9,14 @@ const templateSuratKeteranganForm = z.object({
|
||||
name: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||
imageId: z.string().nonempty(),
|
||||
image2Id: z.string().nonempty(),
|
||||
});
|
||||
|
||||
const suratKeteranganForm = {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
imageId: "",
|
||||
image2Id: "",
|
||||
};
|
||||
|
||||
const telunjukSaktiDesaForm = {
|
||||
@@ -105,15 +108,38 @@ const suratKeterangan = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: [] as Prisma.PelayananSuratKeteranganGetPayload<{
|
||||
include: { image: true };
|
||||
}>[],
|
||||
async load() {
|
||||
const res = await ApiFetch.api.desa.layanan.pelayanansuratketerangan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
suratKeterangan.findMany.data = res.data?.data ?? [];
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
suratKeterangan.findMany.loading = true; // Use the full path to access the property
|
||||
suratKeterangan.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.desa.layanan.pelayanansuratketerangan[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
suratKeterangan.findMany.data = res.data.data || [];
|
||||
suratKeterangan.findMany.total = res.data.total || 0;
|
||||
suratKeterangan.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load surat keterangan:", res.data?.message);
|
||||
suratKeterangan.findMany.data = [];
|
||||
suratKeterangan.findMany.total = 0;
|
||||
suratKeterangan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading surat keterangan:", error);
|
||||
suratKeterangan.findMany.data = [];
|
||||
suratKeterangan.findMany.total = 0;
|
||||
suratKeterangan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
suratKeterangan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -121,6 +147,7 @@ const suratKeterangan = proxy({
|
||||
data: null as Prisma.PelayananSuratKeteranganGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
image2: true;
|
||||
};
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
@@ -202,6 +229,7 @@ const suratKeterangan = proxy({
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
imageId: data.imageId || "",
|
||||
image2Id: data.image2Id || "",
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
@@ -238,6 +266,7 @@ const suratKeterangan = proxy({
|
||||
name: this.form.name,
|
||||
deskripsi: this.form.deskripsi,
|
||||
imageId: this.form.imageId,
|
||||
image2Id: this.form.image2Id,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -54,20 +55,38 @@ const desaAntikorupsi = proxy({
|
||||
},
|
||||
},
|
||||
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 ?? [];
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
desaAntikorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
desaAntikorupsi.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.landingpage.desaantikorupsi[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
desaAntikorupsi.findMany.data = res.data.data || [];
|
||||
desaAntikorupsi.findMany.total = res.data.total || 0;
|
||||
desaAntikorupsi.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load media sosial:", res.data?.message);
|
||||
desaAntikorupsi.findMany.data = [];
|
||||
desaAntikorupsi.findMany.total = 0;
|
||||
desaAntikorupsi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading media sosial:", error);
|
||||
desaAntikorupsi.findMany.data = [];
|
||||
desaAntikorupsi.findMany.total = 0;
|
||||
desaAntikorupsi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
desaAntikorupsi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -281,14 +300,38 @@ const kategoriDesaAntiKorupsi = proxy({
|
||||
},
|
||||
},
|
||||
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 ?? [];
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
kategoriDesaAntiKorupsi.findMany.loading = true; // Use the full path to access the property
|
||||
kategoriDesaAntiKorupsi.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.landingpage.kategoridak[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriDesaAntiKorupsi.findMany.data = res.data.data || [];
|
||||
kategoriDesaAntiKorupsi.findMany.total = res.data.total || 0;
|
||||
kategoriDesaAntiKorupsi.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load media sosial:", res.data?.message);
|
||||
kategoriDesaAntiKorupsi.findMany.data = [];
|
||||
kategoriDesaAntiKorupsi.findMany.total = 0;
|
||||
kategoriDesaAntiKorupsi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading media sosial:", error);
|
||||
kategoriDesaAntiKorupsi.findMany.data = [];
|
||||
kategoriDesaAntiKorupsi.findMany.total = 0;
|
||||
kategoriDesaAntiKorupsi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriDesaAntiKorupsi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -5,10 +6,10 @@ 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"),
|
||||
name: z.string().min(1, "Nama minimal 1 karakter"),
|
||||
description: z.string().min(1, "Deskripsi minimal 1 karakter"),
|
||||
imageId: z.string().min(1, "Gambar wajib dipilih"),
|
||||
link: z.string().min(3, "Link minimal 3 karakter"),
|
||||
link: z.string().min(1, "Link minimal 1 karakter"),
|
||||
});
|
||||
|
||||
type ProgramInovasiForm = Prisma.ProgramInovasiGetPayload<{
|
||||
@@ -59,15 +60,38 @@ const programInovasi = proxy({
|
||||
},
|
||||
},
|
||||
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 ?? [];
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
programInovasi.findMany.loading = true; // Use the full path to access the property
|
||||
programInovasi.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.landingpage.programinovasi[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
programInovasi.findMany.data = res.data.data || [];
|
||||
programInovasi.findMany.total = res.data.total || 0;
|
||||
programInovasi.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load pegawai:", res.data?.message);
|
||||
programInovasi.findMany.data = [];
|
||||
programInovasi.findMany.total = 0;
|
||||
programInovasi.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading pegawai:", error);
|
||||
programInovasi.findMany.data = [];
|
||||
programInovasi.findMany.total = 0;
|
||||
programInovasi.findMany.totalPages = 1;
|
||||
} finally {
|
||||
programInovasi.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -453,13 +477,38 @@ const mediaSosial = proxy({
|
||||
},
|
||||
},
|
||||
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 ?? [];
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
mediaSosial.findMany.loading = true; // Use the full path to access the property
|
||||
mediaSosial.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.landingpage.mediasosial[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
mediaSosial.findMany.data = res.data.data || [];
|
||||
mediaSosial.findMany.total = res.data.total || 0;
|
||||
mediaSosial.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load media sosial:", res.data?.message);
|
||||
mediaSosial.findMany.data = [];
|
||||
mediaSosial.findMany.total = 0;
|
||||
mediaSosial.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading media sosial:", error);
|
||||
mediaSosial.findMany.data = [];
|
||||
mediaSosial.findMany.total = 0;
|
||||
mediaSosial.findMany.totalPages = 1;
|
||||
} finally {
|
||||
mediaSosial.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -52,19 +53,38 @@ const sdgsDesa = proxy({
|
||||
},
|
||||
},
|
||||
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 ?? [];
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
sdgsDesa.findMany.loading = true; // Use the full path to access the property
|
||||
sdgsDesa.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.landingpage.sdgsdesa[
|
||||
"findMany"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
sdgsDesa.findMany.data = res.data.data || [];
|
||||
sdgsDesa.findMany.total = res.data.total || 0;
|
||||
sdgsDesa.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load media sosial:", res.data?.message);
|
||||
sdgsDesa.findMany.data = [];
|
||||
sdgsDesa.findMany.total = 0;
|
||||
sdgsDesa.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading media sosial:", error);
|
||||
sdgsDesa.findMany.data = [];
|
||||
sdgsDesa.findMany.total = 0;
|
||||
sdgsDesa.findMany.totalPages = 1;
|
||||
} finally {
|
||||
sdgsDesa.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -4,8 +4,9 @@ import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
||||
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
||||
import colors from '@/con/colors';
|
||||
import ApiFetch from '@/lib/api-fetch';
|
||||
import { Box, Button, Center, FileInput, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react';
|
||||
import { Box, Button, Group, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { Dropzone } from '@mantine/dropzone';
|
||||
import { IconArrowBack, IconPhoto, IconUpload, IconX } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
@@ -16,11 +17,14 @@ function EditSuratKeterangan() {
|
||||
const params = useParams()
|
||||
const stateSurat = useProxy(stateLayananDesa.suratKeterangan)
|
||||
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
||||
const [previewImage2, setPreviewImage2] = useState<string | null>(null);
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [file2, setFile2] = useState<File | null>(null);
|
||||
const [formData, setFormData] = useState({
|
||||
name: stateSurat.edit.form.name,
|
||||
deskripsi: stateSurat.edit.form.deskripsi,
|
||||
imageId: stateSurat.edit.form.imageId,
|
||||
image2Id: stateSurat.edit.form.image2Id,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
@@ -31,12 +35,22 @@ function EditSuratKeterangan() {
|
||||
const data = await stateSurat.edit.load(id);
|
||||
if (data) {
|
||||
setFormData({
|
||||
name: data.name,
|
||||
deskripsi: data.deskripsi,
|
||||
imageId: data.imageId,
|
||||
name: data.name || "",
|
||||
deskripsi: data.deskripsi || "",
|
||||
imageId: data.imageId || "",
|
||||
image2Id: data.image2Id || "",
|
||||
});
|
||||
if (data?.image?.link) {
|
||||
|
||||
if (data.image?.link) {
|
||||
setPreviewImage(data.image.link);
|
||||
} else {
|
||||
setPreviewImage(null);
|
||||
}
|
||||
|
||||
if (data.image2?.link) {
|
||||
setPreviewImage2(data.image2.link);
|
||||
} else {
|
||||
setPreviewImage2(null);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -54,6 +68,7 @@ function EditSuratKeterangan() {
|
||||
name: formData.name,
|
||||
deskripsi: formData.deskripsi,
|
||||
imageId: formData.imageId,
|
||||
image2Id: formData.image2Id,
|
||||
}
|
||||
if (file) {
|
||||
const res = await ApiFetch.api.fileStorage.create.post({ file, name: file.name });
|
||||
@@ -66,6 +81,17 @@ function EditSuratKeterangan() {
|
||||
stateSurat.edit.form.imageId = uploaded.id;
|
||||
}
|
||||
|
||||
if (file2) {
|
||||
const res = await ApiFetch.api.fileStorage.create.post({ file: file2, name: file2.name });
|
||||
const uploaded = res.data?.data;
|
||||
|
||||
if (!uploaded?.id) {
|
||||
return toast.error("Gagal upload gambar");
|
||||
}
|
||||
|
||||
stateSurat.edit.form.image2Id = uploaded.id;
|
||||
}
|
||||
|
||||
await stateSurat.edit.update()
|
||||
toast.success("Surat berhasil diperbarui!")
|
||||
router.push("/admin/desa/layanan/pelayanan_surat_keterangan")
|
||||
@@ -103,25 +129,106 @@ function EditSuratKeterangan() {
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<FileInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Upload Gambar Konten</Text>}
|
||||
value={file}
|
||||
onChange={async (e) => {
|
||||
if (!e) return;
|
||||
setFile(e);
|
||||
const base64 = await e.arrayBuffer().then((buf) =>
|
||||
"data:image/png;base64," + Buffer.from(buf).toString("base64")
|
||||
);
|
||||
setPreviewImage(base64);
|
||||
}}
|
||||
/>
|
||||
{previewImage ? (
|
||||
<Image alt="" src={previewImage} w={200} h={200} />
|
||||
) : (
|
||||
<Center w={200} h={200} bg={"gray"}>
|
||||
<IconImageInPicture />
|
||||
</Center>
|
||||
)}
|
||||
<Box>
|
||||
<Text fz={"md"} fw={"bold"}>Gambar</Text>
|
||||
<Box >
|
||||
<Dropzone
|
||||
onDrop={(files) => {
|
||||
const file = files[0]; // Hanya ambil file pertama
|
||||
if (file) {
|
||||
setFile(file);
|
||||
setPreviewImage(URL.createObjectURL(file)); // Buat preview
|
||||
}
|
||||
}}
|
||||
maxSize={5 * 1024 ** 2} // 5MB
|
||||
accept={{
|
||||
'image/*': ['.jpeg', '.jpg', '.png', '.webp']
|
||||
}}
|
||||
>
|
||||
<Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
|
||||
<Dropzone.Accept>
|
||||
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
|
||||
</Dropzone.Accept>
|
||||
<Dropzone.Reject>
|
||||
<IconX size={52} color="var(--mantine-color-red-6)" stroke={1.5} />
|
||||
</Dropzone.Reject>
|
||||
<Dropzone.Idle>
|
||||
<IconPhoto size={52} color="var(--mantine-color-dimmed)" stroke={1.5} />
|
||||
</Dropzone.Idle>
|
||||
|
||||
<div>
|
||||
<Text size="xl" inline>
|
||||
Drag images here or click to select files
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed" inline mt={7}>
|
||||
Attach as many files as you like, each file should not exceed 5mb
|
||||
</Text>
|
||||
</div>
|
||||
</Group>
|
||||
</Dropzone>
|
||||
{previewImage && (
|
||||
<Image
|
||||
src={previewImage}
|
||||
alt="Preview"
|
||||
width={280}
|
||||
height={180}
|
||||
fit="cover"
|
||||
radius="sm"
|
||||
mt="md"
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"md"} fw={"bold"}>Gambar</Text>
|
||||
<Box >
|
||||
<Dropzone
|
||||
onDrop={(files) => {
|
||||
const file = files[0]; // Hanya ambil file pertama
|
||||
if (file) {
|
||||
setFile2(file);
|
||||
setPreviewImage2(URL.createObjectURL(file)); // Buat preview
|
||||
}
|
||||
}}
|
||||
maxSize={5 * 1024 ** 2} // 5MB
|
||||
accept={{
|
||||
'image/*': ['.jpeg', '.jpg', '.png', '.webp']
|
||||
}}
|
||||
>
|
||||
<Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
|
||||
<Dropzone.Accept>
|
||||
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
|
||||
</Dropzone.Accept>
|
||||
<Dropzone.Reject>
|
||||
<IconX size={52} color="var(--mantine-color-red-6)" stroke={1.5} />
|
||||
</Dropzone.Reject>
|
||||
<Dropzone.Idle>
|
||||
<IconPhoto size={52} color="var(--mantine-color-dimmed)" stroke={1.5} />
|
||||
</Dropzone.Idle>
|
||||
|
||||
<div>
|
||||
<Text size="xl" inline>
|
||||
Drag images here or click to select files
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed" inline mt={7}>
|
||||
Attach as many files as you like, each file should not exceed 5mb
|
||||
</Text>
|
||||
</div>
|
||||
</Group>
|
||||
</Dropzone>
|
||||
{previewImage2 && (
|
||||
<Image
|
||||
src={previewImage2}
|
||||
alt="Preview"
|
||||
width={280}
|
||||
height={180}
|
||||
fit="cover"
|
||||
radius="sm"
|
||||
mt="md"
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Button bg={colors['blue-button']} onClick={handleSubmit}>Simpan</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
@@ -64,6 +64,10 @@ function DetailSuratKeterangan() {
|
||||
<Text fw={"bold"} fz={"lg"}>Gambar</Text>
|
||||
<Image w={{ base: 150, md: 150, lg: 150 }} src={suratKeteranganState.findUnique.data?.image?.link} alt="gambar" />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Gambar</Text>
|
||||
<Image w={{ base: 150, md: 150, lg: 150 }} src={suratKeteranganState.findUnique.data?.image2?.link} alt="gambar" />
|
||||
</Box>
|
||||
<Flex gap={"xs"} mt={10}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
||||
@@ -3,8 +3,9 @@ import CreateEditor from '@/app/admin/(dashboard)/_com/createEditor';
|
||||
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
||||
import colors from '@/con/colors';
|
||||
import ApiFetch from '@/lib/api-fetch';
|
||||
import { Box, Button, Center, FileInput, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react';
|
||||
import { Box, Button, Group, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { Dropzone } from '@mantine/dropzone';
|
||||
import { IconArrowBack, IconPhoto, IconUpload, IconX } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
@@ -12,8 +13,8 @@ import { useProxy } from 'valtio/utils';
|
||||
|
||||
function CreateSuratKeterangan() {
|
||||
const stateSurat = useProxy(stateLayananDesa.suratKeterangan)
|
||||
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [previewImage2, setPreviewImage2] = useState<{ preview: string; file: File } | null>(null);
|
||||
const [previewImage, setPreviewImage] = useState<{ preview: string; file: File } | null>(null);
|
||||
const router = useRouter()
|
||||
|
||||
const resetForm = () => {
|
||||
@@ -21,33 +22,57 @@ function CreateSuratKeterangan() {
|
||||
name: "",
|
||||
deskripsi: "",
|
||||
imageId: "",
|
||||
image2Id: ""
|
||||
}
|
||||
setPreviewImage(null)
|
||||
setFile(null)
|
||||
setPreviewImage2(null)
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!file) {
|
||||
return toast.error("Silahkan pilih file gambar terlebih dahulu")
|
||||
if (!previewImage) {
|
||||
return toast.warn("Pilih file gambar utama terlebih dahulu");
|
||||
}
|
||||
|
||||
const res = await ApiFetch.api.fileStorage.create.post({
|
||||
file: file,
|
||||
name: file.name
|
||||
})
|
||||
try {
|
||||
// Upload gambar utama
|
||||
const res1 = await ApiFetch.api.fileStorage.create.post({
|
||||
file: previewImage.file,
|
||||
name: `main_${previewImage.file.name}`,
|
||||
});
|
||||
|
||||
const uploaded = res.data?.data
|
||||
if (!uploaded?.id) {
|
||||
return toast.error("Gagal upload gambar")
|
||||
const uploadedImage1 = res1.data?.data;
|
||||
if (!uploadedImage1?.id) {
|
||||
return toast.error("Gagal upload gambar utama");
|
||||
}
|
||||
|
||||
let uploadedImage2 = null;
|
||||
// Upload gambar kedua jika ada
|
||||
if (previewImage2) {
|
||||
const res2 = await ApiFetch.api.fileStorage.create.post({
|
||||
file: previewImage2.file,
|
||||
name: `secondary_${previewImage2.file.name}`,
|
||||
});
|
||||
uploadedImage2 = res2.data?.data;
|
||||
}
|
||||
|
||||
// Set form data
|
||||
stateSurat.create.form.imageId = uploadedImage1.id;
|
||||
if (uploadedImage2?.id) {
|
||||
stateSurat.create.form.image2Id = uploadedImage2.id;
|
||||
}
|
||||
|
||||
// Create the record
|
||||
await stateSurat.create.create();
|
||||
|
||||
// Reset form dan redirect
|
||||
resetForm();
|
||||
toast.success("Data surat keterangan berhasil ditambahkan");
|
||||
router.push("/admin/desa/layanan/pelayanan_surat_keterangan");
|
||||
} catch (error) {
|
||||
console.error("Error creating surat keterangan:", error);
|
||||
toast.error("Terjadi kesalahan saat menambahkan surat keterangan");
|
||||
}
|
||||
|
||||
stateSurat.create.form.imageId = uploaded.id
|
||||
|
||||
await stateSurat.create.create()
|
||||
resetForm()
|
||||
router.push("/admin/desa/layanan/pelayanan_surat_keterangan")
|
||||
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
@@ -75,25 +100,105 @@ function CreateSuratKeterangan() {
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<FileInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Upload Gambar Konten</Text>}
|
||||
value={file}
|
||||
onChange={async (e) => {
|
||||
if (!e) return;
|
||||
setFile(e);
|
||||
const base64 = await e.arrayBuffer().then((buf) =>
|
||||
"data:image/png;base64," + Buffer.from(buf).toString("base64")
|
||||
);
|
||||
setPreviewImage(base64);
|
||||
}}
|
||||
/>
|
||||
{previewImage ? (
|
||||
<Image alt="" src={previewImage} w={200} h={200} />
|
||||
) : (
|
||||
<Center w={200} h={200} bg={"gray"}>
|
||||
<IconImageInPicture />
|
||||
</Center>
|
||||
)}
|
||||
<Box>
|
||||
<Text fz={"md"} fw={"bold"} mb="sm">Gambar Utama</Text>
|
||||
<Dropzone
|
||||
onDrop={(files) => {
|
||||
const file = files[0];
|
||||
if (file) {
|
||||
setPreviewImage({
|
||||
file,
|
||||
preview: URL.createObjectURL(file)
|
||||
});
|
||||
}
|
||||
}}
|
||||
maxSize={5 * 1024 ** 2}
|
||||
accept={{
|
||||
'image/*': ['.jpeg', '.jpg', '.png', '.webp']
|
||||
}}
|
||||
>
|
||||
<Group justify="center" gap="xl" mih={120} style={{ pointerEvents: 'none' }}>
|
||||
<Dropzone.Accept>
|
||||
<IconUpload size={32} color="var(--mantine-color-blue-6)" stroke={1.5} />
|
||||
</Dropzone.Accept>
|
||||
<Dropzone.Reject>
|
||||
<IconX size={32} color="var(--mantine-color-red-6)" stroke={1.5} />
|
||||
</Dropzone.Reject>
|
||||
<Dropzone.Idle>
|
||||
<IconPhoto size={32} color="var(--mantine-color-dimmed)" stroke={1.5} />
|
||||
</Dropzone.Idle>
|
||||
<div>
|
||||
<Text size="md" inline>Seret gambar ke sini atau klik untuk memilih</Text>
|
||||
<Text size="sm" c="dimmed" inline mt={7} display="block">
|
||||
Ukuran maksimal 5MB (JPEG, JPG, PNG, WebP)
|
||||
</Text>
|
||||
</div>
|
||||
</Group>
|
||||
</Dropzone>
|
||||
{previewImage && (
|
||||
<Image
|
||||
src={previewImage.preview}
|
||||
alt="Preview Gambar Utama"
|
||||
width={280}
|
||||
height={180}
|
||||
fit="cover"
|
||||
radius="sm"
|
||||
mt="md"
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box mt="lg">
|
||||
<Text fz={"md"} fw={"bold"} mb="sm">Gambar Tambahan (Opsional)</Text>
|
||||
<Dropzone
|
||||
onDrop={(files) => {
|
||||
const file = files[0];
|
||||
if (file) {
|
||||
setPreviewImage2({
|
||||
file,
|
||||
preview: URL.createObjectURL(file)
|
||||
});
|
||||
}
|
||||
}}
|
||||
maxSize={5 * 1024 ** 2}
|
||||
accept={{
|
||||
'image/*': ['.jpeg', '.jpg', '.png', '.webp']
|
||||
}}
|
||||
>
|
||||
<Group justify="center" gap="xl" mih={120} style={{ pointerEvents: 'none' }}>
|
||||
<Dropzone.Accept>
|
||||
<IconUpload size={32} color="var(--mantine-color-blue-6)" stroke={1.5} />
|
||||
</Dropzone.Accept>
|
||||
<Dropzone.Reject>
|
||||
<IconX size={32} color="var(--mantine-color-red-6)" stroke={1.5} />
|
||||
</Dropzone.Reject>
|
||||
<Dropzone.Idle>
|
||||
<IconPhoto size={32} color="var(--mantine-color-dimmed)" stroke={1.5} />
|
||||
</Dropzone.Idle>
|
||||
<div>
|
||||
<Text size="md" inline>Seret gambar ke sini atau klik untuk memilih</Text>
|
||||
<Text size="sm" c="dimmed" inline mt={7} display="block">
|
||||
Ukuran maksimal 5MB (JPEG, JPG, PNG, WebP)
|
||||
</Text>
|
||||
</div>
|
||||
</Group>
|
||||
</Dropzone>
|
||||
{previewImage2 ? (
|
||||
<Image
|
||||
src={previewImage2.preview}
|
||||
alt="Preview Gambar Tambahan"
|
||||
width={280}
|
||||
height={180}
|
||||
fit="cover"
|
||||
radius="sm"
|
||||
mt="md"
|
||||
/>
|
||||
) : (
|
||||
<Text size="sm" c="dimmed" mt="sm">
|
||||
Kosongkan jika tidak ada gambar tambahan
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
<Button bg={colors['blue-button']} onClick={handleSubmit}>Simpan</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import JudulListTab from '@/app/admin/(dashboard)/_com/judulListTab';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateLayananDesa from '../../../_state/desa/layananDesa';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
import stateLayananDesa from '../../../_state/desa/layananDesa';
|
||||
|
||||
function SuratKeterangan() {
|
||||
const [search, setSearch] = useState("");
|
||||
return (
|
||||
<Box>
|
||||
<HeaderSearch
|
||||
title='Posisi Organisasi'
|
||||
title='Pelayanan Surat Keterangan'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
@@ -30,54 +30,90 @@ function ListSuratKeterangan({ search }: { search: string }) {
|
||||
const suratKeteranganState = useProxy(stateLayananDesa.suratKeterangan)
|
||||
const router = useRouter()
|
||||
|
||||
useShallowEffect(() => {
|
||||
suratKeteranganState.findMany.load()
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = suratKeteranganState.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10)
|
||||
}, [])
|
||||
|
||||
const filteredData = (suratKeteranganState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
|
||||
if (!suratKeteranganState.findMany.data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.sort((a, b) => a.posisi?.hierarki - b.posisi?.hierarki);
|
||||
}, [data, search]);
|
||||
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton height={300} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Surat Keterangan'
|
||||
href='/admin/desa/layanan/pelayanan_surat_keterangan/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama</TableTh>
|
||||
<TableTh>Deskripsi</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulListTab
|
||||
<JudulList
|
||||
title='List Surat Keterangan'
|
||||
href='/admin/desa/layanan/pelayanan_surat_keterangan/create'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={16} />}
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama</TableTh>
|
||||
<TableTh>Deskripsi</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image?.link} alt="gambar" />
|
||||
<Box w={200}>
|
||||
<Text truncate="end" fz={"sm"}>{item.name}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={300}>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text>
|
||||
<Button onClick={() => router.push(`/admin/desa/layanan/pelayanan_surat_keterangan/${item.id}`)}>
|
||||
@@ -90,6 +126,18 @@ function ListSuratKeterangan({ search }: { search: string }) {
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -195,7 +195,6 @@ function CreateAPBDes() {
|
||||
placeholder='Masukkan judul'
|
||||
/>
|
||||
<TextInput
|
||||
type='number'
|
||||
value={stateAPBDes.create.form.jumlah}
|
||||
onChange={(val) => {
|
||||
stateAPBDes.create.form.jumlah = val.target.value;
|
||||
|
||||
@@ -77,7 +77,7 @@ function ListAPBDes({ search }: { search: string }) {
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"}>{item.jumlah}</Text>
|
||||
<Text truncate="end" fz={"sm"}>Rp. {item.jumlah}</Text>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
{item.file?.link ? (
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { IconEdit, IconSearch, IconX } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -34,6 +34,14 @@ function ListKategoriKegiatan({ search }: { search: string }) {
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
const router = useRouter()
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = stateKategori.findMany;
|
||||
|
||||
const handleHapus = () => {
|
||||
if (selectedId) {
|
||||
stateKategori.delete.byId(selectedId)
|
||||
@@ -42,23 +50,51 @@ function ListKategoriKegiatan({ search }: { search: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
useShallowEffect(() => {
|
||||
stateKategori.findMany.load()
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
load(page, 10)
|
||||
}, [page])
|
||||
|
||||
const filteredData = (stateKategori.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
|
||||
if (!stateKategori.findMany.data) {
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
<Skeleton height={550} />
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Kategori Kegiatan'
|
||||
href='/admin/landing-page/desa-anti-korupsi/kategori-desa-anti-korupsi/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama</TableTh>
|
||||
<TableTh>Edit</TableTh>
|
||||
<TableTh>Delete</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -68,38 +104,50 @@ function ListKategoriKegiatan({ search }: { search: string }) {
|
||||
title='List Kategori Kegiatan'
|
||||
href='/admin/landing-page/desa-anti-korupsi/kategori-desa-anti-korupsi/create'
|
||||
/>
|
||||
<Box style={{overflowY: "auto"}}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Kategori</TableTh>
|
||||
<TableTh>Edit</TableTh>
|
||||
<TableTh>Delete</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
<Button color="green" onClick={() => router.push(`/admin/landing-page/desa-anti-korupsi/kategori-desa-anti-korupsi/${item.id}`)}>
|
||||
<IconEdit size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button color="red" onClick={() => {
|
||||
setSelectedId(item.id)
|
||||
setModalHapus(true)
|
||||
}}>
|
||||
<IconX size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<Box style={{ overflowY: "auto" }}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Kategori</TableTh>
|
||||
<TableTh>Edit</TableTh>
|
||||
<TableTh>Delete</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
<Button color="green" onClick={() => router.push(`/admin/landing-page/desa-anti-korupsi/kategori-desa-anti-korupsi/${item.id}`)}>
|
||||
<IconEdit size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button color="red" onClick={() => {
|
||||
setSelectedId(item.id)
|
||||
setModalHapus(true)
|
||||
}}>
|
||||
<IconX size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
{/* Modal Konfirmasi Hapus */}
|
||||
<ModalKonfirmasiHapus
|
||||
opened={modalHapus}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -29,27 +29,65 @@ function DesaAntiKorupsi() {
|
||||
function ListDesaAntiKorupsi({ search }: { search: string }) {
|
||||
const listState = useProxy(korupsiState.desaAntikorupsi)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = listState.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
listState.findMany.load()
|
||||
}, [])
|
||||
load(page, 10);
|
||||
}, [page]);
|
||||
|
||||
const filteredData = (listState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword) ||
|
||||
item.kategori?.name?.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi?.toLowerCase().includes(keyword) ||
|
||||
item.kategori?.name?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.sort((a, b) => b.createdAt - a.createdAt);
|
||||
}, [data, search]);
|
||||
|
||||
if (!listState.findMany.data) {
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
<Skeleton height={550} />
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Desa Anti Korupsi'
|
||||
href='/admin/landing-page/desa-anti-korupsi/list-desa-anti-korupsi/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama</TableTh>
|
||||
<TableTh>Deskripsi</TableTh>
|
||||
<TableTh>Kategori</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
@@ -77,7 +115,9 @@ function ListDesaAntiKorupsi({ search }: { search: string }) {
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
<Box w={200}>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>{item.kategori?.name}</TableTd>
|
||||
<TableTd>
|
||||
@@ -92,6 +132,18 @@ function ListDesaAntiKorupsi({ search }: { search: string }) {
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -77,8 +77,10 @@ function ListPrestasi({ search }: { search: string }) {
|
||||
<Text truncate="end" fz={"sm"}>{item.name}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
<TableTd >
|
||||
<Box w={150}>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>{item.kategori?.name}</TableTd>
|
||||
<TableTd>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { Box, Button, Center, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -30,24 +30,61 @@ function ListMediaSosial({ search }: { search: string }) {
|
||||
const stateMediaSosial = useProxy(profileLandingPageState.mediaSosial)
|
||||
const router = useRouter();
|
||||
|
||||
useShallowEffect(() => {
|
||||
stateMediaSosial.findMany.load()
|
||||
}, [])
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = stateMediaSosial.findMany;
|
||||
|
||||
const filteredData = (stateMediaSosial.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.iconUrl?.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
useEffect(() => {
|
||||
load(page, 10)
|
||||
}, [page])
|
||||
|
||||
if (!stateMediaSosial.findMany.data) {
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.iconUrl?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
<Skeleton height={550} />
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Media Sosial'
|
||||
href='/admin/landing-page/profile/media-sosial/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Media Sosial / Nama Kontak</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Icon URL / No Telephone</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -57,37 +94,55 @@ function ListMediaSosial({ search }: { search: string }) {
|
||||
title='List Media Sosial'
|
||||
href='/admin/landing-page/profile/media-sosial/create'
|
||||
/>
|
||||
<Box style={{overflowY: "auto"}}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Media Sosial / Nama Kontak</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Icon URL / No Telephone</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
<Box w={50} h={50}>
|
||||
<Image src={item.image?.link} alt={item.name} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>{item.iconUrl}</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/landing-page/profile/media-sosial/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
<Box style={{ overflowY: "auto" }}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Media Sosial / Nama Kontak</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Icon URL / No Telephone</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
<Box w={50} h={50}>
|
||||
<Image src={item.image?.link} alt={item.name} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={250}>
|
||||
<a style={{color: "black"}} href={item.iconUrl} target="_blank" rel="noopener noreferrer">
|
||||
<Text truncate fz={'sm'}>{item.iconUrl}</Text>
|
||||
</a>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/landing-page/profile/media-sosial/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,13 @@ function DetailProgramInovasi() {
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Link</Text>
|
||||
<Text fz={"lg"}>{stateProgramInovasi.findUnique.data?.link}</Text>
|
||||
<a
|
||||
href={stateProgramInovasi.findUnique.data?.link || "#"}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{stateProgramInovasi.findUnique.data?.link || "Tidak ada link"}
|
||||
</a>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Gambar</Text>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import JudulList from '../../../_com/judulList';
|
||||
@@ -30,27 +30,62 @@ function ListProgramInovasi({ search }: { search: string }) {
|
||||
const stateProgramInovasi = useProxy(profileLandingPageState.programInovasi)
|
||||
const router = useRouter();
|
||||
|
||||
useShallowEffect(() => {
|
||||
stateProgramInovasi.findMany.load()
|
||||
}, [])
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = stateProgramInovasi.findMany;
|
||||
|
||||
const filteredData = (stateProgramInovasi.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.description?.toLowerCase().includes(keyword) ||
|
||||
item.link?.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
useEffect(() => {
|
||||
load(page, 10);
|
||||
}, [page]);
|
||||
|
||||
if (!stateProgramInovasi.findMany.data) {
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.description?.toLowerCase().includes(keyword) ||
|
||||
item.link?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
<Skeleton height={550} />
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Program Inovasi'
|
||||
href='/admin/landing-page/profile/program-inovasi/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama Program</TableTh>
|
||||
<TableTh>Deskripsi</TableTh>
|
||||
<TableTh>Link</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
@@ -72,8 +107,14 @@ function ListProgramInovasi({ search }: { search: string }) {
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>{item.description}</TableTd>
|
||||
<TableTd>{item.link}</TableTd>
|
||||
<TableTd w={200}>{item.description}</TableTd>
|
||||
<TableTd>
|
||||
<Box w={250}>
|
||||
<a style={{ color: "black" }} href={item.link} target="_blank" rel="noopener noreferrer">
|
||||
<Text truncate fz={'sm'}>{item.link}</Text>
|
||||
</a>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Button onClick={() => router.push(`/admin/landing-page/profile/program-inovasi/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
@@ -85,6 +126,18 @@ function ListProgramInovasi({ search }: { search: string }) {
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ function EditKolaborasiInovasi() {
|
||||
<iframe
|
||||
src={previewImage}
|
||||
width="100%"
|
||||
height="500px"
|
||||
height="250px"
|
||||
style={{ border: "1px solid #ccc", borderRadius: "8px" }}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -110,7 +110,7 @@ function CreateSDGsDesa() {
|
||||
<iframe
|
||||
src={previewImage}
|
||||
width="100%"
|
||||
height="500px"
|
||||
height="250px"
|
||||
style={{ border: "1px solid #ccc", borderRadius: "8px" }}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import sdgsDesa from '../../_state/landing-page/sdgs-desa';
|
||||
@@ -30,24 +30,61 @@ function SdgsDesa() {
|
||||
function ListSdgsDesa({ search }: { search: string }) {
|
||||
const listState = useProxy(sdgsDesa)
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = listState.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
listState.findMany.load()
|
||||
load(page, 10)
|
||||
}, [])
|
||||
|
||||
const filteredData = (listState.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.jumlah.toLowerCase().includes(keyword)
|
||||
)
|
||||
});
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.jumlah?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
|
||||
if (!listState.findMany.data) {
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
<Skeleton height={550} />
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Desa Anti Korupsi'
|
||||
href='/admin/landing-page/desa-anti-korupsi/list-desa-anti-korupsi/create'
|
||||
/>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama SDGs Desa</TableTh>
|
||||
<TableTh>Jumlah SDGs Desa</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -90,6 +127,18 @@ function ListSdgsDesa({ search }: { search: string }) {
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ type FormCreate = Prisma.PelayananSuratKeteranganGetPayload<{
|
||||
name: true;
|
||||
deskripsi: true;
|
||||
imageId: true;
|
||||
image2Id: true;
|
||||
};
|
||||
}>;
|
||||
async function createPelayananSuratKeterangan(context: Context) {
|
||||
@@ -17,6 +18,7 @@ async function createPelayananSuratKeterangan(context: Context) {
|
||||
name: body.name,
|
||||
deskripsi: body.deskripsi,
|
||||
imageId: body.imageId,
|
||||
image2Id: body.image2Id,
|
||||
},
|
||||
});
|
||||
return {
|
||||
|
||||
@@ -17,6 +17,7 @@ const pelayananSuratKeteranganDelete = async (context: Context) => {
|
||||
where: { id },
|
||||
include: {
|
||||
image: true,
|
||||
image2: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -40,6 +41,18 @@ const pelayananSuratKeteranganDelete = async (context: Context) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (pelayananSuratKeterangan.image2) {
|
||||
try {
|
||||
const filePath = path.join(pelayananSuratKeterangan.image2.path, pelayananSuratKeterangan.image2.name);
|
||||
await fs.unlink(filePath);
|
||||
await prisma.fileStorage.delete({
|
||||
where: { id: pelayananSuratKeterangan.image2.id },
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Gagal hapus gambar lama:", err);
|
||||
}
|
||||
}
|
||||
|
||||
const deleted = await prisma.pelayananSuratKeterangan.delete({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
@@ -1,24 +1,47 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function pelayananSuratKeteranganFindMany() {
|
||||
try {
|
||||
const data = await prisma.pelayananSuratKeterangan.findMany({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
});
|
||||
export default async function pelayananSuratKeteranganFindMany(context: Context) {
|
||||
const page = Number(context.query.page) || 1;
|
||||
const limit = Number(context.query.limit) || 10;
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Success fetch pelayanan surat keterangan",
|
||||
data,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("Find many error:", e);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed fetch pelayanan surat keterangan",
|
||||
};
|
||||
}
|
||||
try {
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.pelayananSuratKeterangan.findMany({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
image: true,
|
||||
image2: true,
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma.pelayananSuratKeterangan.count({
|
||||
where: { isActive: true }
|
||||
})
|
||||
]);
|
||||
|
||||
const totalPages = Math.ceil(total / limit);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Success fetch pelayanan surat keterangan with pagination",
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
total,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("Find many paginated error:", e);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed fetch pelayanan surat keterangan with pagination",
|
||||
data: [],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ export default async function pelayananSuratKeteranganFindUnique(request: Reques
|
||||
where: { id },
|
||||
include: {
|
||||
image: true,
|
||||
image2: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ const PelayananSuratKeterangan = new Elysia({ prefix: "/pelayanansuratketerangan
|
||||
name: t.String(),
|
||||
deskripsi: t.String(),
|
||||
imageId: t.String(),
|
||||
image2Id: t.String(),
|
||||
}),
|
||||
})
|
||||
.delete("/del/:id", pelayananSuratKeteranganDelete)
|
||||
@@ -30,6 +31,7 @@ const PelayananSuratKeterangan = new Elysia({ prefix: "/pelayanansuratketerangan
|
||||
name: t.String(),
|
||||
deskripsi: t.String(),
|
||||
imageId: t.String(),
|
||||
image2Id: t.String(),
|
||||
}),
|
||||
})
|
||||
export default PelayananSuratKeterangan;
|
||||
@@ -9,6 +9,7 @@ type FormUpdate = Prisma.PelayananSuratKeteranganGetPayload<{
|
||||
name: true;
|
||||
deskripsi: true;
|
||||
imageId: true;
|
||||
image2Id: true;
|
||||
};
|
||||
}>;
|
||||
export default async function updatePelayananSuratKeterangan(context: Context) {
|
||||
@@ -16,7 +17,7 @@ export default async function updatePelayananSuratKeterangan(context: Context) {
|
||||
const id = context.params?.id;
|
||||
const body = (await context.body) as Omit<FormUpdate, "id">;
|
||||
|
||||
const { name, deskripsi, imageId } = body;
|
||||
const { name, deskripsi, imageId, image2Id } = body;
|
||||
|
||||
if (!id) {
|
||||
return new Response(JSON.stringify({
|
||||
@@ -63,12 +64,28 @@ export default async function updatePelayananSuratKeterangan(context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
if (existing.image2Id && existing.image2Id !== image2Id) {
|
||||
const oldImage = existing.image;
|
||||
if (oldImage) {
|
||||
try {
|
||||
const filePath = path.join(oldImage.path, oldImage.name);
|
||||
await fs.unlink(filePath);
|
||||
await prisma.fileStorage.delete({
|
||||
where: { id: oldImage.id },
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Gagal hapus gambar lama:", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const updated = await prisma.pelayananSuratKeterangan.update({
|
||||
where: { id },
|
||||
data: {
|
||||
name,
|
||||
deskripsi,
|
||||
imageId,
|
||||
image2Id,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ async function apbdesFindMany(context: Context) {
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||
orderBy: { name: "asc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||
}),
|
||||
prisma.aPBDes.count({
|
||||
where: { isActive: true },
|
||||
|
||||
@@ -17,7 +17,7 @@ async function desaAntiKorupsiFindMany(context: Context) {
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' }, // opsional, kalau mau urut berdasarkan waktu
|
||||
orderBy: { name: 'asc' }, // opsional, kalau mau urut berdasarkan waktu
|
||||
}),
|
||||
prisma.desaAntiKorupsi.count({
|
||||
where: { isActive: true }
|
||||
|
||||
@@ -11,7 +11,7 @@ const DesaAntiKorupsi = new Elysia({
|
||||
})
|
||||
|
||||
// ✅ Find all
|
||||
.get("/find-many", desaAntiKorupsiFindMany)
|
||||
.get("/findMany", desaAntiKorupsiFindMany)
|
||||
|
||||
// ✅ Find by ID
|
||||
.get("/:id", desaAntiKorupsiFindUnique)
|
||||
|
||||
@@ -1,15 +1,40 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// /api/berita/findManyPaginated.ts
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function kategoriDesaAntiKorupsiFindMany() {
|
||||
const data = await prisma.kategoriDesaAntiKorupsi.findMany();
|
||||
return {
|
||||
success: true,
|
||||
data: data.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
}
|
||||
}),
|
||||
async function kategoriDesaAntiKorupsiFindMany(context: Context) {
|
||||
const page = Number(context.query.page) || 1;
|
||||
const limit = Number(context.query.limit) || 10;
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
try {
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.kategoriDesaAntiKorupsi.findMany({
|
||||
where: { isActive: true },
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { name: 'asc' }, // opsional, kalau mau urut berdasarkan waktu
|
||||
}),
|
||||
prisma.kategoriDesaAntiKorupsi.count({
|
||||
where: { isActive: true }
|
||||
})
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Success fetch kategori desa anti korupsi with pagination",
|
||||
data,
|
||||
page,
|
||||
totalPages: Math.ceil(total / limit),
|
||||
total,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Find many paginated error:", e);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed fetch kategori desa anti korupsi with pagination",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default kategoriDesaAntiKorupsiFindMany;
|
||||
|
||||
@@ -9,7 +9,7 @@ const KategoriDesaAntiKorupsi = new Elysia({
|
||||
prefix: "/kategoridak",
|
||||
tags: ["Landing Page/Desa Anti Korupsi"],
|
||||
})
|
||||
.get("/find-many", kategoriDesaAntiKorupsiFindMany)
|
||||
.get("/findMany", kategoriDesaAntiKorupsiFindMany)
|
||||
.get("/:id", async (context) => {
|
||||
const response = await kategoriDesaAntiKorupsiFindUnique(context);
|
||||
return response;
|
||||
|
||||
@@ -16,7 +16,7 @@ async function mediaSosialFindMany(context: Context) {
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||
orderBy: { name: "asc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||
}),
|
||||
prisma.mediaSosial.count({
|
||||
where: { isActive: true },
|
||||
|
||||
@@ -11,7 +11,7 @@ const MediaSosial = new Elysia({
|
||||
})
|
||||
|
||||
// ✅ Find all
|
||||
.get("/find-many", MediaSosialFindMany)
|
||||
.get("/findMany", MediaSosialFindMany)
|
||||
|
||||
// ✅ Find by ID
|
||||
.get("/:id", MediaSosialFindUnique)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// /api/berita/findManyPaginated.ts
|
||||
// // /api/berita/findManyPaginated.ts
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
@@ -16,7 +16,7 @@ async function programInovasiFindMany(context: Context) {
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||
orderBy: { name: "asc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||
}),
|
||||
prisma.programInovasi.count({
|
||||
where: { isActive: true },
|
||||
@@ -41,3 +41,4 @@ async function programInovasiFindMany(context: Context) {
|
||||
}
|
||||
|
||||
export default programInovasiFindMany;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ const ProgramInovasi = new Elysia({
|
||||
})
|
||||
|
||||
// ✅ Find all
|
||||
.get("/find-many", ProgramInovasiFindMany)
|
||||
.get("/findMany", ProgramInovasiFindMany)
|
||||
|
||||
// ✅ Find by ID
|
||||
.get("/:id", ProgramInovasiFindUnique)
|
||||
|
||||
@@ -16,7 +16,7 @@ async function sdgsDesaFindMany(context: Context) {
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||
orderBy: { jumlah: "desc" }, // opsional, kalau mau urut berdasarkan waktu
|
||||
}),
|
||||
prisma.sDGSDesa.count({
|
||||
where: { isActive: true },
|
||||
|
||||
@@ -11,7 +11,7 @@ const SDGSDesa = new Elysia({
|
||||
})
|
||||
|
||||
// ✅ Find all
|
||||
.get("/find-many", sdgsDesaFindMany)
|
||||
.get("/findMany", sdgsDesaFindMany)
|
||||
|
||||
// ✅ Find by ID
|
||||
.get("/:id", sdgsDesaFindUnique)
|
||||
|
||||
@@ -1,47 +1,33 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { ActionIcon, BackgroundImage, Box, Container, Flex, Group, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { ActionIcon, BackgroundImage, Box, Center, Container, Flex, Group, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { IconDownload } from '@tabler/icons-react';
|
||||
import BackButton from '../../(pages)/desa/layanan/_com/BackButto';
|
||||
import apbdes from '@/app/admin/(dashboard)/_state/landing-page/apbdes';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'next-view-transitions';
|
||||
|
||||
const data = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Pendapatan",
|
||||
image: "/api/img/pendapatan.jpeg",
|
||||
value: "Rp 495M"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Belanja",
|
||||
image: "/api/img/belanja.jpeg",
|
||||
value: "Rp 395M"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Pembiayaan",
|
||||
image: "/api/img/pembiayaan.jpeg",
|
||||
value: "Rp 295M"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "APBDesa 2025",
|
||||
image: "/api/img/apb-des.jpg",
|
||||
value: "Rp 500M"
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "APBDesa 2024",
|
||||
image: "/api/img/apb-des.jpg",
|
||||
value: "Rp 450M"
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "APBDesa 2023",
|
||||
image: "/api/img/apb-des.jpg",
|
||||
value: "Rp 400M"
|
||||
},
|
||||
]
|
||||
function Page() {
|
||||
const state = useProxy(apbdes);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await state.findMany.load();
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
loadData();
|
||||
}, [])
|
||||
|
||||
const data = state.findMany.data || [];
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
@@ -65,53 +51,59 @@ function Page() {
|
||||
sm: 3,
|
||||
}}
|
||||
>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<BackgroundImage
|
||||
key={k}
|
||||
src={v.image}
|
||||
h={350}
|
||||
radius={16}
|
||||
pos={"relative"}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 16,
|
||||
zIndex: 0
|
||||
}}
|
||||
pos={"absolute"}
|
||||
w={"100%"}
|
||||
h={"100%"}
|
||||
bg={colors.trans.dark[2]}
|
||||
/>
|
||||
<Stack justify='space-between' h={"100%"} gap={0} p={"lg"} pos={"relative"}>
|
||||
<Box p={"lg"}>
|
||||
{loading ? (
|
||||
<Center>
|
||||
<Text fz={"2.4rem"}>Memuat Data...</Text>
|
||||
</Center>
|
||||
) : (
|
||||
data.map((v, k) => {
|
||||
return (
|
||||
<BackgroundImage
|
||||
key={k}
|
||||
src={v.image?.link || ''}
|
||||
h={350}
|
||||
radius={16}
|
||||
pos={"relative"}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 16,
|
||||
zIndex: 0
|
||||
}}
|
||||
pos={"absolute"}
|
||||
w={"100%"}
|
||||
h={"100%"}
|
||||
bg={colors.trans.dark[2]}
|
||||
/>
|
||||
<Stack justify='space-between' h={"100%"} gap={0} p={"lg"} pos={"relative"}>
|
||||
<Box p={"lg"}>
|
||||
<Text
|
||||
c={"white"}
|
||||
size={"1.5rem"}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}>{v.name}</Text>
|
||||
</Box>
|
||||
<Text
|
||||
fw={"bold"}
|
||||
c={"white"}
|
||||
size={"1.5rem"}
|
||||
size={"3.5rem"}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}>{v.title}</Text>
|
||||
</Box>
|
||||
<Text
|
||||
fw={"bold"}
|
||||
c={"white"}
|
||||
size={"3.5rem"}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}>{v.value}</Text>
|
||||
<Group justify="center">
|
||||
<ActionIcon px={70} py={20} radius={"xl"} size="md" bg={colors["blue-button"]}>
|
||||
<Flex gap={"md"}>
|
||||
<IconDownload size={20} />
|
||||
<Text fz={"sm"} c={"white"}>Download</Text>
|
||||
</Flex>
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Stack>
|
||||
</BackgroundImage>
|
||||
)
|
||||
})}
|
||||
}}>{v.jumlah}</Text>
|
||||
<Group justify="center">
|
||||
<ActionIcon px={70} py={20} radius={"xl"} size="md" bg={colors["blue-button"]} component={Link} href={v.file?.link || ''}>
|
||||
<Flex gap={"md"}>
|
||||
<IconDownload size={20} />
|
||||
<Text fz={"sm"} c={"white"}>Download</Text>
|
||||
</Flex>
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Stack>
|
||||
</BackgroundImage>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Container, Flex, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { IconClipboardText } from '@tabler/icons-react';
|
||||
|
||||
const data = [
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "5.1 ADANYA BUDAYA LOKAL/HUKUM ADAT YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "5.2 ADANYA TOKOH MASYARAKAT, TOKOH AGAMA, TOKOH ADAT, TOKOH PEMUDA, DAN KAUM PEREMPUAN YANG MENDORONG UPAYA PENCEGAHAN TINDAK PIDANA KORUPSI",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
function Lokal() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"} ta={"center"}>
|
||||
Kearifan Lokal
|
||||
</Text>
|
||||
<Text
|
||||
py={10}
|
||||
ta={"justify"}
|
||||
>
|
||||
Sebagai bagian dari Program Desa Anti Korupsi, Desa Darmasaba menerapkan kearifan lokal sebagai strategi dalam menciptakan pemerintahan desa yang bersih, transparan, dan berintegritas. Kearifan lokal ini menjadi landasan moral dan budaya yang memperkuat nilai-nilai kejujuran, gotong royong, serta kepedulian sosial dalam kehidupan masyarakat. Adapun beberapa Kearifan Lokal :
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
<SimpleGrid
|
||||
px={{ base: "md", md: 100 }}
|
||||
cols={{
|
||||
base: 1,
|
||||
sm: 2,
|
||||
}}>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<Box
|
||||
key={k}
|
||||
>
|
||||
<Paper p={"lg"} >
|
||||
<Stack h="100%">
|
||||
<Text fz={"lg"} ta={"center"} c={colors["blue-button"]}>{v.judul}</Text>
|
||||
<Flex direction={{ base: "column", md: "row" }} align="center" justify="center" style={{ flex: 1 }}>
|
||||
<Box mb={{ base: 10, md: 0 }}>
|
||||
{v.icon}
|
||||
</Box>
|
||||
<Stack px={{ base: 0, md: 20 }} gap={10} style={{ flex: 1 }}>
|
||||
<Text fz={"sm"} ta={"justify"}>{v.deskripsi}</Text>
|
||||
<Button bg={colors["blue-button"]} radius={"lg"} w="fit-content">Download</Button>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid >
|
||||
</Stack >
|
||||
);
|
||||
}
|
||||
|
||||
export default Lokal;
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Container, Flex, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { IconClipboardText } from '@tabler/icons-react';
|
||||
|
||||
const data = [
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "3.1 ADANYA LAYANAN PENGADUAN BAGI MASYARAKAT",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "3.2 ADANYA SURVEY KEPUASAN MASYARAKAT (SKM) TERHADAP LAYANAN PEMERINTAH DESA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "3.3 ADANYA KETERBUKAAN AKSES MASYARAKAT TERHADAP INFORMASI LAYANAN PEMERINTAH DESA (KESEHATAN, PENDIDIKAN, SOSIAL, LINGKUNGAN, TRANTIBUMLINMAS, PEKERJAAN UMUM) PEMBANGUNAN, KEPENDUDUKAN, KEUANGAN, DAN PELAYANAN LAINNYA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "3.4 ADANYA MEDIA INFORMASI TENTANG APBDES DI BALAI DESA DAN/ATAU TEMPAT LAIN YANG MUDAH DIAKSES OLEH MASYARAKAT",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "3.5 ADANYA MAKLUMAT PELAYANAN",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
||||
function Pelayanan() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"} ta={"center"}>
|
||||
Penguatan Kualitas Pelayanan Publik
|
||||
</Text>
|
||||
<Text
|
||||
py={10}
|
||||
ta={"justify"}
|
||||
>
|
||||
Sebagai bagian dari Program Desa Anti Korupsi, Desa Darmasaba berkomitmen untuk meningkatkan kualitas pelayanan publik agar lebih transparan, cepat, dan bebas dari pungutan liar. Penguatan ini bertujuan untuk memastikan masyarakat mendapatkan pelayanan yang profesional, akuntabel, dan sesuai dengan standar yang telah ditetapkan. Adapun beberapa Penguatan Kualitas Pelayanan Publik :
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
<SimpleGrid
|
||||
px={{ base: "md", md: 100 }}
|
||||
cols={{
|
||||
base: 1,
|
||||
sm: 2,
|
||||
}}>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<Box
|
||||
key={k}
|
||||
>
|
||||
<Paper p={"lg"} h="100%">
|
||||
<Stack h="100%">
|
||||
<Text fz={"lg"} ta={"center"} c={colors["blue-button"]}>{v.judul}</Text>
|
||||
<Flex direction={{ base: "column", md: "row" }} align="center" justify="center" style={{ flex: 1 }}>
|
||||
<Box mb={{ base: 10, md: 0 }}>
|
||||
{v.icon}
|
||||
</Box>
|
||||
<Stack px={{ base: 0, md: 20 }} gap={10} style={{ flex: 1 }}>
|
||||
<Text fz={"sm"} ta={"justify"}>{v.deskripsi}</Text>
|
||||
<Button bg={colors["blue-button"]} radius={"lg"} w="fit-content">Download</Button>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid >
|
||||
</Stack >
|
||||
);
|
||||
}
|
||||
|
||||
export default Pelayanan;
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Container, Flex, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { IconClipboardText } from '@tabler/icons-react';
|
||||
|
||||
const data = [
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "4.1 ADANYA PARTISIPASI DAN KETERLIBATAN MASYARAKAT DALAM PENYUSUNAN RKP DESA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "4.2 ADANYA KESADARAN MASYARAKAT DALAM MENCEGAH TERJADINYA PRAKTIK GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "4.3 ADANYA KETERLIBATAN LEMBAGA KEMASYARAKATAN DALAM PELAKSANAAN PEMBANGUNAN DESA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
]
|
||||
function Partisipasi() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"} ta={"center"}>
|
||||
Penguatan Tata Laksana
|
||||
</Text>
|
||||
<Text
|
||||
py={10}
|
||||
ta={"justify"}
|
||||
>
|
||||
Sebagai bagian dari Program Desa Anti Korupsi, Desa Darmasaba menekankan penguatan partisipasi masyarakat agar warga dapat ikut serta dalam pengawasan, pengambilan keputusan, dan pelaksanaan pembangunan desa yang transparan dan akuntabel. Adapun beberapa Penguatan Partisipasi Masyarakat :
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
<SimpleGrid
|
||||
px={{ base: "md", md: 100 }}
|
||||
cols={{
|
||||
base: 1,
|
||||
sm: 2,
|
||||
}}>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<Box
|
||||
key={k}
|
||||
>
|
||||
<Paper p={"lg"} >
|
||||
<Stack h="100%">
|
||||
<Text fz={"lg"} ta={"center"} c={colors["blue-button"]}>{v.judul}</Text>
|
||||
<Flex direction={{ base: "column", md: "row" }} align="center" justify="center" style={{ flex: 1 }}>
|
||||
<Box mb={{ base: 10, md: 0 }}>
|
||||
{v.icon}
|
||||
</Box>
|
||||
<Stack px={{ base: 0, md: 20 }} gap={10} style={{ flex: 1 }}>
|
||||
<Text fz={"sm"} ta={"justify"}>{v.deskripsi}</Text>
|
||||
<Button bg={colors["blue-button"]} radius={"lg"} w="fit-content">Download</Button>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid >
|
||||
</Stack >
|
||||
);
|
||||
}
|
||||
|
||||
export default Partisipasi;
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Container, Flex, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { IconClipboardText } from '@tabler/icons-react';
|
||||
|
||||
const data = [
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "2.1 ADANYA KEGIATAN PENGAWASAN DAN EVALUASI KINERJA PERANGKAT DESA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "2.2 ADANYA TINDAK LANJUT HASIL PEMBINAAN, PETUNJUK, ARAH, PENGAWASAN, DAN PEMERIKSAAN DARI PEMERINTAH PUSAT/DAERAH",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN PENGAWASAN",
|
||||
deskripsi: "2.3 TIDAK ADANYA APARATUR DESA DALAM 3(TIGA) TAHUN TERAKHIR YANG TERJERAT TINDAKAN PIDANA KORUPSI",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
||||
function Pengawasan() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"} ta={"center"}>
|
||||
Penguatan Pengawasan
|
||||
</Text>
|
||||
<Text
|
||||
py={10}
|
||||
ta={"justify"}
|
||||
>
|
||||
Sebagai bagian dari Program Desa Anti Korupsi, Desa Darmasaba menerapkan penguatan pengawasan untuk memastikan transparansi dan akuntabilitas dalam pengelolaan pemerintahan desa. Sistem pengawasan ini melibatkan berbagai pihak, termasuk aparat desa, masyarakat, dan lembaga terkait, agar tidak ada celah bagi praktik korupsi. Adapun beberapa Penguatan Pengawasan :
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
<SimpleGrid
|
||||
px={{ base: "md", md: 100 }}
|
||||
cols={{
|
||||
base: 1,
|
||||
sm: 2,
|
||||
}}>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<Box
|
||||
key={k}
|
||||
>
|
||||
<Paper p={"lg"} >
|
||||
<Stack h="100%">
|
||||
<Text fz={"lg"} ta={"center"} c={colors["blue-button"]}>{v.judul}</Text>
|
||||
<Flex direction={{ base: "column", md: "row" }} align="center" justify="center" style={{ flex: 1 }}>
|
||||
<Box mb={{ base: 10, md: 0 }}>
|
||||
{v.icon}
|
||||
</Box>
|
||||
<Stack px={{ base: 0, md: 20 }} gap={10} style={{ flex: 1 }}>
|
||||
<Text fz={"sm"} ta={"justify"}>{v.deskripsi}</Text>
|
||||
<Button bg={colors["blue-button"]} radius={"lg"} w="fit-content">Download</Button>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid >
|
||||
</Stack >
|
||||
);
|
||||
}
|
||||
|
||||
export default Pengawasan;
|
||||
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Container, Flex, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { IconClipboardText } from '@tabler/icons-react';
|
||||
|
||||
const data = [
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.1 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.2 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.3 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.4 PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.5 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.6 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
]
|
||||
function Tatalaksana() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"} ta={"center"}>
|
||||
Penguatan Tata Laksana
|
||||
</Text>
|
||||
<Text
|
||||
py={10}
|
||||
ta={"justify"}
|
||||
>
|
||||
Sebagai bagian dari Program Desa Anti Korupsi, Desa Darmasaba menerapkan penguatan tata laksana untuk memastikan transparansi, akuntabilitas, dan efisiensi dalam pemerintahan desa. Adapun beberapa Penguatan Tata Laksana :
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
<SimpleGrid
|
||||
px={{ base: "md", md: 100 }}
|
||||
cols={{
|
||||
base: 1,
|
||||
sm: 2,
|
||||
}}>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<Box
|
||||
key={k}
|
||||
>
|
||||
<Paper p={"lg"} >
|
||||
<Stack h="100%">
|
||||
<Text fz={"lg"} ta={"center"} c={colors["blue-button"]}>{v.judul}</Text>
|
||||
<Flex direction={{ base: "column", md: "row" }} align="center" justify="center" style={{ flex: 1 }}>
|
||||
<Box mb={{ base: 10, md: 0 }}>
|
||||
{v.icon}
|
||||
</Box>
|
||||
<Stack px={{ base: 0, md: 20 }} gap={10} style={{ flex: 1 }}>
|
||||
<Text fz={"sm"} ta={"justify"}>{v.deskripsi}</Text>
|
||||
<Button bg={colors["blue-button"]} radius={"lg"} w="fit-content">Download</Button>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid >
|
||||
</Stack >
|
||||
);
|
||||
}
|
||||
|
||||
export default Tatalaksana;
|
||||
|
||||
|
||||
149
src/app/darmasaba/(tambahan)/desa-anti-korupsi/detail/page.tsx
Normal file
149
src/app/darmasaba/(tambahan)/desa-anti-korupsi/detail/page.tsx
Normal file
@@ -0,0 +1,149 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client';
|
||||
import korupsiState from '@/app/admin/(dashboard)/_state/landing-page/desa-anti-korupsi';
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Box, Button, Container, Flex, Paper, SimpleGrid, Stack, Text, ActionIcon } from '@mantine/core';
|
||||
import { IconFile } from '@tabler/icons-react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
|
||||
function Lokal() {
|
||||
const [selectedKategori, setSelectedKategori] = useState<string>('PENGUATAN TATA LAKSANA');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const state = useProxy(korupsiState);
|
||||
|
||||
// Load data on component mount
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await state.desaAntikorupsi.findMany.load(1, 100); // Load first 100 items
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
// Get data from state
|
||||
const data = state.desaAntikorupsi.findMany.data || [];
|
||||
|
||||
// Debug: Log the complete data structure
|
||||
console.log('Complete data:', JSON.parse(JSON.stringify(data)));
|
||||
|
||||
// Get unique categories
|
||||
const categories = [...new Set(
|
||||
data
|
||||
.filter(item => item.kategori?.name) // Only include items with a category name
|
||||
.map(item => item.kategori.name)
|
||||
)];
|
||||
|
||||
// Filter data based on selected category
|
||||
const filteredData = selectedKategori === 'PENGUATAN TATA LAKSANA'
|
||||
? data
|
||||
: data.filter(item => item.kategori?.name === selectedKategori);
|
||||
|
||||
// Debug: Log filtered data
|
||||
console.log('Filtered data:', JSON.parse(JSON.stringify(filteredData)));
|
||||
return (
|
||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Container w={{ base: "100%", md: "80%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"}>
|
||||
Desa Anti Korupsi
|
||||
</Text>
|
||||
<Text
|
||||
py={10}
|
||||
ta={"justify"}
|
||||
>
|
||||
Desa antikorupsi mendorong pemerintahan jujur dan transparan. Keuangan desa dikelola terbuka dengan melibatkan warga mengawasi anggaran, sehingga digunakan tepat sasaran sesuai kebutuhan. Adapun beberapa jenis tata penguatan :
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
<Container size="lg" px={{ base: "md", md: "xl" }}>
|
||||
{/* Category Filter Buttons */}
|
||||
<Flex gap="md" justify="center" mb="xl" wrap="wrap">
|
||||
{categories.map((kategori) => (
|
||||
<Button
|
||||
color={selectedKategori === kategori ? colors['blue-button'] : 'gray'}
|
||||
key={kategori}
|
||||
variant={selectedKategori === kategori ? 'filled' : 'outline'}
|
||||
onClick={() => setSelectedKategori(kategori)}
|
||||
size="sm"
|
||||
>
|
||||
{kategori}
|
||||
</Button>
|
||||
))}
|
||||
</Flex>
|
||||
|
||||
{/* Loading State */}
|
||||
{loading ? (
|
||||
<Text ta="center">Memuat data...</Text>
|
||||
) : (
|
||||
<SimpleGrid
|
||||
cols={{ base: 1, sm: 2, lg: 3 }}
|
||||
spacing="xl"
|
||||
verticalSpacing="xl"
|
||||
>
|
||||
{filteredData.map((item) => {
|
||||
console.log('Item data:', item);
|
||||
console.log('All item properties:', Object.keys(item).map(key => `${key}: ${item[key]}`).join(', '));
|
||||
|
||||
const handleDownload = async (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
if (!item?.file?.link) return;
|
||||
|
||||
try {
|
||||
const fileUrl = item.file.link.startsWith('http')
|
||||
? item.file.link
|
||||
: `${window.location.origin}${item.file.link.startsWith('/') ? '' : '/'}${item.file.link}`;
|
||||
|
||||
window.open(fileUrl, '_blank');
|
||||
} catch (error) {
|
||||
console.error('Error opening file:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper key={item.id} p="lg" shadow="sm" radius="md" withBorder>
|
||||
<Stack h="100%" justify="space-between">
|
||||
<div>
|
||||
<Text fz="lg" fw={600} mb="sm" c={colors["blue-button"]}>
|
||||
{item.name}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
{item?.file && (
|
||||
<ActionIcon
|
||||
variant="filled"
|
||||
color={colors["blue-button"]}
|
||||
size="lg"
|
||||
onClick={handleDownload}
|
||||
style={{ marginTop: 10 }}
|
||||
title="Unduh File"
|
||||
>
|
||||
<IconFile size={20} />
|
||||
</ActionIcon>
|
||||
)}
|
||||
</Stack>
|
||||
</Paper>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid>
|
||||
)}
|
||||
</Container>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
export default Lokal;
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ function Page() {
|
||||
<Box>
|
||||
{v.icon}
|
||||
</Box>
|
||||
<Button fz={"h4"} color={colors["blue-button"]} onClick={() => router.push(v.link)}>Detail</Button>
|
||||
<Button fz={"h4"} color={colors["blue-button"]} onClick={() => router.push("/darmasaba/desa-anti-korupsi/detail")}>Detail</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Container, Box, Text, Image, ActionIcon, Divider, Flex } from '@mantine/core';
|
||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"} px={{ base: "md", md: 0 }}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }} >
|
||||
<Box pb={20}>
|
||||
<Text ta={"center"} fz={{base: "2rem", md: "2.5rem", lg: "3rem", xl: "3.4rem"}} c={colors["blue-button"]} fw={"bold"}>
|
||||
Peringkat 5 Dalam Ajang Bergengsi Mangupura Award
|
||||
</Text>
|
||||
<Text
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
fz={"1.5rem"}
|
||||
>
|
||||
Tata Kelola dan Inovasi Desa
|
||||
</Text>
|
||||
</Box>
|
||||
<Image src="/api/img/prestasi-peringkat-5.jpeg" alt='' w={"100%"} />
|
||||
</Container>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Text py={20} fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Pada hari Senin, 18 November 2024, Desa Darmasaba kembali mencetak prestasi gemilang dengan meraih peringkat V dalam ajang bergengsi Mangupura Award. Penganugerahan ini berlangsung dalam rangkaian acara HUT Kota Mangupura ke-15 yang dihadiri oleh Drs. I Ketut Suiasa, S.H., Plt Bupati Badung, serta para tokoh penting lainnya.
|
||||
</Text>
|
||||
<Text fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Penghargaan ini bukan hanya sebuah pengakuan, tetapi juga menjadi motivasi bagi Desa Darmasaba untuk terus meningkatkan inovasi, pelayanan, pembangunan serta transformasi digital.
|
||||
Mari bersama kita lanjutkan semangat kolaborasi dan inovasi untuk menjadikan Darmasaba sebagai desa yang semakin unggul dan inspiratif!
|
||||
</Text>
|
||||
<Text py={20} fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Bersama, kita terus wujudkan Desa Darmasaba yang sadar hukum dan berprestasi!
|
||||
</Text>
|
||||
<Divider color={colors["blue-button"]} />
|
||||
<Flex justify={"space-between"} py={20}>
|
||||
<Text fz={'md'}>25 May 2021 . Darmasaba</Text>
|
||||
<Box>
|
||||
<Flex gap={"lg"}>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandFacebook color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandInstagram color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandTwitter color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandWhatsapp color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider color={colors["blue-button"]} pb={50} />
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -1,64 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Container, Box, Text, Image, ActionIcon, Divider, Flex } from '@mantine/core';
|
||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"} px={{ base: "md", md: 0 }}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }} >
|
||||
<Box pb={20}>
|
||||
<Text ta={"center"} fz={{ base: "2rem", md: "2.5rem", lg: "3rem", xl: "3.4rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
Juara 3 dalam Lomba Keluarga Sadar Hukum Kabupaten Badung Tahun 2024
|
||||
</Text>
|
||||
<Text
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
fz={"1.5rem"}
|
||||
>
|
||||
Hukum dan Kesadaran Masyarakat
|
||||
</Text>
|
||||
</Box>
|
||||
<Image src="/api/img/prestasilombahukum.png" alt='' w={"100%"} />
|
||||
</Container>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Text py={20} fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Dengan bangga, KADARKUM Desa Darmasaba berhasil meraih Juara 3 dalam Lomba Keluarga Sadar Hukum Kabupaten Badung Tahun 2024.
|
||||
Prestasi ini tidak lepas dari dukungan penuh dan semangat tinggi dari Ida Bagus Surya Prabhawa Manuaba, S.H., M.H., NL.P. selaku Perbekel Darmasaba yang selalu mendampingi dari proses pelatihan hingga perlombaan, serta turut hadir perwakilan Kecamatan Abiansemal, Ketua BPD Desa Darmasaba, Ketua TP PKK Desa Darmasaba, Perangkat & Staf Desa Darmasaba, Karang Taruna Paramartha Dharma Desa Darmasaba dan seluruh Tim Sukses KADARKUM Desa Darmasaba.
|
||||
</Text>
|
||||
<Text fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Acara yang berlangsung pada 14 November 2024 di Kertha Gosana Lt. 3 Pusat Pemerintahan Kabupaten Badung ini menjadi bukti nyata bahwa kerja keras dan kolaborasi adalah kunci keberhasilan.
|
||||
</Text>
|
||||
<Text py={20} fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Bersama, kita terus wujudkan Desa Darmasaba yang sadar hukum dan berprestasi!
|
||||
</Text>
|
||||
<Divider color={colors["blue-button"]} />
|
||||
<Flex justify={"space-between"} py={20}>
|
||||
<Text fz={'md'}>25 May 2021 . Darmasaba</Text>
|
||||
<Box>
|
||||
<Flex gap={"lg"}>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandFacebook color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandInstagram color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandTwitter color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandWhatsapp color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider color={colors["blue-button"]} pb={50} />
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -1,62 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Container, Box, Text, Image, ActionIcon, Divider, Flex } from '@mantine/core';
|
||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
function Page() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"} px={{ base: "md", md: 0 }}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }} >
|
||||
<Box pb={20}>
|
||||
<Text ta={"center"} fz={{base: "2rem", md: "2.5rem", lg: "3rem", xl: "3.4rem"}} c={colors["blue-button"]} fw={"bold"}>
|
||||
Juara 3 Turnamen Bola Voli Mangupura Cup 2024
|
||||
</Text>
|
||||
<Text
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
fz={"1.5rem"}
|
||||
>
|
||||
Olahraga dan Kepemudaan
|
||||
</Text>
|
||||
</Box>
|
||||
<Image src="/api/img/prestasi-voli.jpeg" alt='' w={"100%"} />
|
||||
</Container>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Text py={20} fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Selamat kepada Tim Bola Voli Putri Dharma Temaja yang berhasil meraih juara 3 dalam Turnamen Bola Voli Mangupura Cup 2024 kategori Putri Se-Bali.
|
||||
Perjuangan luar biasa yang ditunjukkan oleh tim ini merupakan bukti nyata kerja keras, kekompakan, dan semangat pantang menyerah. Dalam kompetisi yang diikuti oleh tim-tim terbaik dari seluruh Bali, Tim Dharma Temaja berhasil menunjukkan performa yang menginspirasi dan mengharumkan nama desa.
|
||||
</Text>
|
||||
<Text fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Terima kasih kepada seluruh pemain, pelatih, serta pendukung yang selalu memberikan dukungan penuh di setiap pertandingan. Kemenangan ini adalah awal dari perjalanan yang lebih besar, dan semoga prestasi ini dapat terus memotivasi kita untuk mencapai hasil yang lebih gemilang di masa depan.
|
||||
</Text>
|
||||
<Text py={20} fz={{ base: "sm", md: "lg" }} ta={"justify"}>
|
||||
Mari kita terus dukung Tim Bola Voli Putri Dharma Temaja agar semakin bersinar di ajang-ajang berikutnya
|
||||
</Text>
|
||||
<Divider color={colors["blue-button"]} />
|
||||
<Flex justify={"space-between"} py={20}>
|
||||
<Text fz={'md'}>25 May 2021 . Darmasaba</Text>
|
||||
<Box>
|
||||
<Flex gap={"lg"}>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandFacebook color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandInstagram color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandTwitter color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandWhatsapp color={colors["blue-button"]} size={"30"} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider color={colors["blue-button"]} pb={50} />
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
147
src/app/darmasaba/(tambahan)/prestasi-desa/[id]/page.tsx
Normal file
147
src/app/darmasaba/(tambahan)/prestasi-desa/[id]/page.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import prestasiState from '@/app/admin/(dashboard)/_state/landing-page/prestasi-desa';
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { ActionIcon, Box, Container, Divider, Flex, Image, Skeleton, Stack, Text } from '@mantine/core';
|
||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||
import { useParams, usePathname } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
|
||||
function Page() {
|
||||
const params = useParams();
|
||||
const pathname = usePathname();
|
||||
const [baseUrl, setBaseUrl] = useState('');
|
||||
const state = useProxy(prestasiState.prestasiDesa);
|
||||
|
||||
// Get base URL for sharing
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
setBaseUrl(window.location.origin);
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
prestasiState.kategoriPrestasi.findMany.load()
|
||||
const loadData = async () => {
|
||||
try {
|
||||
await state.findMany.load();
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
}
|
||||
}
|
||||
loadData();
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
state.findUnique.load(params?.id as string);
|
||||
}, [params?.id]);
|
||||
|
||||
if (!state.findUnique.data) {
|
||||
return (
|
||||
<Stack py={10} px={{ base: "md", md: 100 }}>
|
||||
<Skeleton h={40} />
|
||||
<Skeleton h={300} mt="md" />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"} px={{ base: "md", md: 0 }}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
{state.findUnique.data && (
|
||||
<>
|
||||
<Box pb={20} key={state.findUnique.data.id}>
|
||||
<Text
|
||||
ta={"center"}
|
||||
fz={{base: "2rem", md: "2.5rem", lg: "3rem", xl: "3.4rem"}}
|
||||
c={colors["blue-button"]}
|
||||
fw={"bold"}
|
||||
>
|
||||
{state.findUnique.data.name}
|
||||
</Text>
|
||||
<Text ta={"center"} fw={"bold"} fz={"1.5rem"}>
|
||||
{state.findUnique.data.kategori?.name}
|
||||
</Text>
|
||||
</Box>
|
||||
{state.findUnique.data.image?.link && (
|
||||
<Image
|
||||
src={state.findUnique.data.image.link}
|
||||
alt={state.findUnique.data.name || 'Prestasi'}
|
||||
w={"100%"}
|
||||
style={{ maxHeight: '500px', objectFit: 'cover' }}
|
||||
/>
|
||||
)}
|
||||
<Box mt="md">
|
||||
<Text dangerouslySetInnerHTML={{ __html: state.findUnique.data.deskripsi || '' }} />
|
||||
<Text mt="md" c="dimmed" size="sm">
|
||||
Dibuat pada: {new Date(state.findUnique.data.createdAt).toLocaleDateString('id-ID')}
|
||||
</Text>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Container>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Divider color={colors["blue-button"]} />
|
||||
<Flex justify={"space-between"} py={20}>
|
||||
<Text fz="md">
|
||||
Dibuat pada: {state.findUnique.data?.createdAt ? new Date(state.findUnique.data.createdAt).toLocaleDateString('id-ID', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
}) : '-'}
|
||||
</Text>
|
||||
<Box>
|
||||
<Flex gap={"lg"}>
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
component="a"
|
||||
href={`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(`${baseUrl}${pathname}`)}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Share on Facebook"
|
||||
>
|
||||
<IconBrandFacebook color={colors["blue-button"]} size={30} />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
component="a"
|
||||
href={`https://www.instagram.com/?url=${encodeURIComponent(`${baseUrl}${pathname}`)}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Share on Instagram"
|
||||
>
|
||||
<IconBrandInstagram color={colors["blue-button"]} size={30} />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
component="a"
|
||||
href={`https://twitter.com/intent/tweet?url=${encodeURIComponent(`${baseUrl}${pathname}`)}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Share on Twitter"
|
||||
>
|
||||
<IconBrandTwitter color={colors["blue-button"]} size={30} />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
component="a"
|
||||
href={`https://wa.me/?text=${encodeURIComponent(`${baseUrl}${pathname}`)}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Share on WhatsApp"
|
||||
>
|
||||
<IconBrandWhatsapp color={colors["blue-button"]} size={30} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider color={colors["blue-button"]} pb={50} />
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -1,34 +1,36 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { BackgroundImage, Box, Button, Container, Group, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { BackgroundImage, Box, Button, Center, Container, Group, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import BackButton from '../../(pages)/desa/layanan/_com/BackButto';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import prestasiState from '@/app/admin/(dashboard)/_state/landing-page/prestasi-desa';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const data = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Olahraga dan Kepemudaan",
|
||||
description: "Tim Bola Voli Putri Dharma Temaja meraih juara 3 dalam Turnamen Bola Voli Mangupura Cup 2024 kategori Putri Se-Bali ",
|
||||
image: "/api/img/prestasi-voli.jpeg",
|
||||
link: "/darmasaba/prestasi-desa/tim-bola-voli-putri-dharma-temaja-meraih-juara-3-dalam-turnamen-bola-voli-mangupura-cup-2024-kategori-putri-se-bali"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Hukum dan Kesadaran Masyarakat",
|
||||
description: "Prestasi Juara 3 dalam Lomba Keluarga Sadar Hukum Kabupaten Badung Tahun 2024",
|
||||
image: "/api/img/prestasilombahukum.png",
|
||||
link: "/darmasaba/prestasi-desa/prestasi-juara-3-dalam-lomba-keluarga-sadar-hukum-kabupaten-badung-tahun-2024"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Tata Kelola dan Inovasi Desa",
|
||||
description: "Peringkat 5 Dalam Ajang Bergengsi Mangupura Award",
|
||||
image: "/api/img/prestasi-peringkat-5.jpeg",
|
||||
link: "/darmasaba/prestasi-desa/peringkat-5-dalam-ajang-bergengsi-mangupura-award"
|
||||
}
|
||||
]
|
||||
function Page() {
|
||||
const state = useProxy(prestasiState.prestasiDesa);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [prestasiData, setPrestasiData] = useState<any[]>([]);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await prestasiState.kategoriPrestasi.findMany.load();
|
||||
await state.findMany.load();
|
||||
setPrestasiData(state.findMany.data || []);
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadData();
|
||||
}, []);
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"} >
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
@@ -48,12 +50,17 @@ function Page() {
|
||||
md: 3,
|
||||
}}
|
||||
>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<BackgroundImage
|
||||
key={k}
|
||||
src={v.image}
|
||||
h={350}
|
||||
{loading ? (
|
||||
<Center>
|
||||
<Text fz={"2.4rem"}>Memuat Data...</Text>
|
||||
</Center>
|
||||
) : (
|
||||
prestasiData.map((v, k) => {
|
||||
return (
|
||||
<BackgroundImage
|
||||
key={k}
|
||||
src={v.image?.link}
|
||||
|
||||
radius={16}
|
||||
pos={"relative"}
|
||||
>
|
||||
@@ -70,7 +77,7 @@ function Page() {
|
||||
<Stack justify='space-between' h={"100%"} gap={0} p={"lg"} pos={"relative"}>
|
||||
<Group>
|
||||
<Paper radius={"lg"} py={7} px={10}>
|
||||
<Text>{v.title}</Text>
|
||||
<Text>{v.kategori?.name}</Text>
|
||||
</Paper>
|
||||
</Group>
|
||||
<Box p={"lg"}>
|
||||
@@ -80,18 +87,27 @@ function Page() {
|
||||
size={"1.8rem"}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}>{v.description}</Text>
|
||||
lineHeight: 1.4,
|
||||
minHeight: '5.4rem',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
lineClamp={3}
|
||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||
/>
|
||||
</Box>
|
||||
<Group justify="center">
|
||||
<Button px={20} radius={"100"} size="md" bg={colors["blue-button"]}
|
||||
onClick={() => router.push(v.link)}>
|
||||
onClick={() => router.push(`/darmasaba/prestasi-desa/${v.id}`)}>
|
||||
Detail
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</BackgroundImage>
|
||||
)
|
||||
})}
|
||||
})
|
||||
)}
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -1,11 +1,43 @@
|
||||
import { Box, Center, Container, Image, Stack, Text } from '@mantine/core';
|
||||
'use client'
|
||||
import { Box, Center, Container, Image, LoadingOverlay, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { useEffect, useState } from 'react';
|
||||
import BackButton from '../../(pages)/desa/layanan/_com/BackButto';
|
||||
|
||||
|
||||
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
const [sdgsDesa, setSdgsDesa] = useState<Prisma.SDGSDesaGetPayload<{ include: { image: true } }>[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
useEffect(() => {
|
||||
const fetchSdgsDesa = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/landingpage/sdgsdesa/findMany');
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
// Ensure the data is an array before setting it
|
||||
let data = [];
|
||||
if (Array.isArray(result.data)) {
|
||||
data = result.data;
|
||||
} else if (Array.isArray(result)) {
|
||||
// In case the API returns the array directly
|
||||
data = result;
|
||||
} else {
|
||||
console.error('Invalid data format:', result);
|
||||
}
|
||||
setSdgsDesa(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching sdgs desa:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchSdgsDesa();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Stack pos={"relative"} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}><BackButton /></Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
@@ -28,12 +60,70 @@ function Page() {
|
||||
>
|
||||
SDGs Desa sebagaimana dijabarkan dalam Permendesa Nomor 21 tahun 2020 terdiri dari 18 tujuan yang harus dicapai pada tahun 2030. Tujuan-tujuan tersebut mencakup berbagai aspek kehidupan masyarakat desa, mulai dari pengentasan kemiskinan, peningkatan kesehatan dan pendidikan, kesetaraan gender, pertumbuhan ekonomi, infrastruktur, hingga kelestarian lingkungan. Adapun SDGs Desa terdiri dari tujuan-tujuan sebagai berikut:
|
||||
</Text>
|
||||
<Center>
|
||||
<Image src={"/api/img/sdgsdesa-18-removebg.png"} alt='' w={800} />
|
||||
</Center>
|
||||
</Box >
|
||||
<Box py={20}>
|
||||
|
||||
<Box py={20} px={{ base: "md", md: 100 }}>
|
||||
<Box pos="relative" style={{ minHeight: 200 }}>
|
||||
<LoadingOverlay visible={loading} overlayProps={{ blur: 2 }} />
|
||||
{!loading && sdgsDesa.length > 0 ? (
|
||||
<SimpleGrid
|
||||
cols={{ base: 1, sm: 2, md: 3, lg: 4 }}
|
||||
spacing="xl"
|
||||
verticalSpacing="xl"
|
||||
>
|
||||
{sdgsDesa.map((item) => (
|
||||
<Paper
|
||||
key={item.id}
|
||||
p="md"
|
||||
radius="md"
|
||||
shadow="sm"
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
transition: 'transform 0.2s',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-5px)',
|
||||
boxShadow: '0 8px 16px rgba(0,0,0,0.1)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
p="md"
|
||||
style={{
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRadius: '8px',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
marginBottom: '1rem',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={item.image?.link || '/placeholder-sdgs.png'}
|
||||
alt={item.name}
|
||||
width={120}
|
||||
height={120}
|
||||
fit="contain"
|
||||
/>
|
||||
</Box>
|
||||
<Stack gap="xs" style={{ width: '100%' }}>
|
||||
<Title order={4} ta="center" c={"dimmed"} fw={600} lineClamp={2} style={{ minHeight: '3rem' }}>
|
||||
{item.name}
|
||||
</Title>
|
||||
<Text ta="center" fw={"bold"} c={colors['blue-button']} fz={"h2"} lineClamp={3} style={{ minHeight: '4.5rem' }}>
|
||||
{item.jumlah}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Paper>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
) : !loading ? (
|
||||
<Center style={{ minHeight: 200 }}>
|
||||
<Text>Tidak ada data SDGs Desa yang tersedia</Text>
|
||||
</Center>
|
||||
) : null}
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack >
|
||||
);
|
||||
|
||||
@@ -112,7 +112,7 @@ function Footer() {
|
||||
</Box>
|
||||
</Paper>
|
||||
</Center>
|
||||
<Box py={20}>
|
||||
<Box py={20} >
|
||||
<SimpleGrid
|
||||
p={20}
|
||||
cols={{
|
||||
@@ -123,10 +123,10 @@ function Footer() {
|
||||
color: "white"
|
||||
}}
|
||||
>
|
||||
<Box p={mobile ? 30 : 30}>
|
||||
<Box p={mobile ? 30 : 30} style={{color: "white"}}>
|
||||
<Stack justify='space-between'>
|
||||
<Text fz={"md"} fw={"bold"}>Tentang Darmasaba</Text>
|
||||
<Text fz={"xs"} >Desa Darmasaba adalah desa
|
||||
<Text fz={"md"} fw={"bold"} c={"white"}>Tentang Darmasaba</Text>
|
||||
<Text fz={"xs"} c={"white"}>Desa Darmasaba adalah desa
|
||||
budaya yang kaya akan tradisi dan
|
||||
nilai-nilai luhur masyarakat Bali.</Text>
|
||||
<Box>
|
||||
@@ -149,42 +149,42 @@ function Footer() {
|
||||
</Box>
|
||||
<Box p={mobile ? 30 : 30}>
|
||||
<Stack justify='space-between' gap={"xs"}>
|
||||
<Text fz={"md"} fw={"bold"}>Layanan</Text>
|
||||
<Text fz={"md"} fw={"bold"} c={"white"}>Layanan</Text>
|
||||
<Anchor c={"white"} variant='transparent'>
|
||||
<Text fz={"xs"} >Administrasi Kependudukan</Text>
|
||||
<Text fz={"xs"} c={"white"}>Administrasi Kependudukan</Text>
|
||||
</Anchor>
|
||||
<Anchor c={"white"} variant='transparent'>
|
||||
<Text fz={"xs"} >Pelayanan Sosial</Text>
|
||||
<Text fz={"xs"} c={"white"}>Pelayanan Sosial</Text>
|
||||
</Anchor>
|
||||
<Anchor c={"white"} variant='transparent'>
|
||||
<Text fz={"xs"} >Pengaduan Masyarakat</Text>
|
||||
<Text fz={"xs"} c={"white"}>Pengaduan Masyarakat</Text>
|
||||
</Anchor>
|
||||
<Anchor c={"white"} variant='transparent'>
|
||||
<Text fz={"xs"} >Informasi Publik</Text>
|
||||
<Text fz={"xs"} c={"white"}>Informasi Publik</Text>
|
||||
</Anchor>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Box p={mobile ? 30 : 30}>
|
||||
<Stack justify='space-between' gap={"xs"}>
|
||||
<Text fz={"md"} fw={"bold"}>Tautan Penting</Text>
|
||||
<Text fz={"md"} fw={"bold"} c={"white"}>Tautan Penting</Text>
|
||||
<Anchor c={"white"} variant='transparent'>
|
||||
<Text fz={"xs"} >Portal Badung</Text>
|
||||
<Text fz={"xs"} c={"white"}>Portal Badung</Text>
|
||||
</Anchor>
|
||||
<Anchor c={"white"} variant='transparent'>
|
||||
<Text fz={"xs"} >E-Government</Text>
|
||||
<Text fz={"xs"} c={"white"}>E-Government</Text>
|
||||
</Anchor>
|
||||
<Anchor c={"white"} variant='transparent'>
|
||||
<Text fz={"xs"} >Transparansi</Text>
|
||||
<Text fz={"xs"} c={"white"}>Transparansi</Text>
|
||||
</Anchor>
|
||||
<Anchor c={"white"} variant='transparent'>
|
||||
<Text fz={"xs"} >Unduhan</Text>
|
||||
<Text fz={"xs"} c={"white"}>Unduhan</Text>
|
||||
</Anchor>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Box p={mobile ? 30 : 30}>
|
||||
<Stack justify='space-between'>
|
||||
<Text fz={"md"} fw={"bold"}>Newsletter</Text>
|
||||
<Text fz={"xs"} >Dapatkan informasi terbaru
|
||||
<Text fz={"md"} fw={"bold"} c={"white"}>Newsletter</Text>
|
||||
<Text fz={"xs"} c={"white"}>Dapatkan informasi terbaru
|
||||
tentang kegiatan dan program
|
||||
desa</Text>
|
||||
<TextInput
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import apbdes from '@/app/admin/(dashboard)/_state/landing-page/apbdes';
|
||||
import colors from '@/con/colors';
|
||||
import { ActionIcon, BackgroundImage, Box, Button, Flex, Group, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { ActionIcon, BackgroundImage, Box, Button, Center, Flex, Group, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { IconDownload } from '@tabler/icons-react';
|
||||
import Link from 'next/link';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
const data = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Pendapatan",
|
||||
image: "/api/img/pendapatan.jpeg",
|
||||
value: "Rp 495M"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Belanja",
|
||||
image: "/api/img/belanja.jpeg",
|
||||
value: "Rp 395M"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Pembiayaan",
|
||||
image: "/api/img/pembiayaan.jpeg",
|
||||
value: "Rp 295M"
|
||||
},
|
||||
|
||||
]
|
||||
function Apbdes() {
|
||||
const state = useProxy(apbdes);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const textHeading = {
|
||||
title: "APBDes",
|
||||
des: "Transparansi APBDes Darmasaba adalah langkah nyata menuju tata kelola pemerintahan desa yang bersih dan bertanggung jawab"
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await state.findMany.load();
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
loadData();
|
||||
}, [])
|
||||
|
||||
const data = (state.findMany.data || []).slice(0, 3);
|
||||
return (
|
||||
<>
|
||||
<Stack p={"sm"} gap={"4rem"} bg={colors.Bg}>
|
||||
@@ -53,53 +56,59 @@ function Apbdes() {
|
||||
sm: 3,
|
||||
}}
|
||||
>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<BackgroundImage
|
||||
key={k}
|
||||
src={v.image}
|
||||
h={350}
|
||||
radius={16}
|
||||
pos={"relative"}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 16,
|
||||
zIndex: 0
|
||||
}}
|
||||
pos={"absolute"}
|
||||
w={"100%"}
|
||||
h={"100%"}
|
||||
bg={colors.trans.dark[2]}
|
||||
/>
|
||||
<Stack justify='space-between' h={"100%"} gap={0} p={"lg"} pos={"relative"}>
|
||||
<Box p={"lg"}>
|
||||
{loading ? (
|
||||
<Center>
|
||||
<Text fz={"2.4rem"}>Memuat Data...</Text>
|
||||
</Center>
|
||||
) : (
|
||||
data.map((v, k) => {
|
||||
return (
|
||||
<BackgroundImage
|
||||
key={k}
|
||||
src={v.image?.link || ''}
|
||||
h={350}
|
||||
radius={16}
|
||||
pos={"relative"}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 16,
|
||||
zIndex: 0
|
||||
}}
|
||||
pos={"absolute"}
|
||||
w={"100%"}
|
||||
h={"100%"}
|
||||
bg={colors.trans.dark[2]}
|
||||
/>
|
||||
<Stack justify='space-between' h={"100%"} gap={0} p={"lg"} pos={"relative"}>
|
||||
<Box p={"lg"}>
|
||||
<Text
|
||||
c={"white"}
|
||||
size={"1.5rem"}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}>{v.name}</Text>
|
||||
</Box>
|
||||
<Text
|
||||
fw={"bold"}
|
||||
c={"white"}
|
||||
size={"1.5rem"}
|
||||
size={"3.5rem"}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}>{v.title}</Text>
|
||||
</Box>
|
||||
<Text
|
||||
fw={"bold"}
|
||||
c={"white"}
|
||||
size={"3.5rem"}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}>{v.value}</Text>
|
||||
<Group justify="center">
|
||||
<ActionIcon px={70} py={20} radius={"xl"} size="md" bg={colors["blue-button"]}>
|
||||
<Flex gap={"md"}>
|
||||
<IconDownload size={20} />
|
||||
<Text fz={"sm"} c={"white"}>Download</Text>
|
||||
</Flex>
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Stack>
|
||||
</BackgroundImage>
|
||||
)
|
||||
})}
|
||||
}}>{v.jumlah}</Text>
|
||||
<Group justify="center">
|
||||
<ActionIcon px={70} py={20} radius={"xl"} size="md" bg={colors["blue-button"]} component={Link} href={v.file?.link || ''}>
|
||||
<Flex gap={"md"}>
|
||||
<IconDownload size={20} />
|
||||
<Text fz={"sm"} c={"white"}>Download</Text>
|
||||
</Flex>
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Stack>
|
||||
</BackgroundImage>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</SimpleGrid>
|
||||
<Group pb={80} justify='center'>
|
||||
<Button component={Link} href="/darmasaba/apbdes" radius={"lg"} bg={colors["blue-button"]} fz={"h4"}>Lihat Semua</Button>
|
||||
|
||||
@@ -1,54 +1,44 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from "@/con/colors";
|
||||
import { Box, Button, Center, Container, Flex, Paper, SimpleGrid, Stack, Text, useMantineTheme } from "@mantine/core";
|
||||
import { useMediaQuery } from "@mantine/hooks";
|
||||
import { IconClipboardText } from "@tabler/icons-react";
|
||||
import Link from "next/link";
|
||||
import korupsiState from "@/app/admin/(dashboard)/_state/landing-page/desa-anti-korupsi";
|
||||
import { useProxy } from "valtio/utils";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function DesaAntiKorupsi() {
|
||||
const data = [
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.1 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.2 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP MENGENAI MEKANISME EVALUASI KINERJA PERANGKAT DESA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.3 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PENGENDALIAN GRATIFIKASI, SUAP DAN KONFLIK KEPENTINGAN",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.4 PERJANJIAN KERJA SAMA ANTARA PELAKSANA KEGIATAN ANGGARAN DENGAN PIHAK PENYEDIA, DAN TELAH MELALUI PROSES PENGADAAN BARANG/JASA DI DESA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.5 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PAKTA INTEGRITAS DAN SEJENISNYA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
{
|
||||
judul: "PENGUATAN TATA LAKSANA",
|
||||
deskripsi: "1.6 ADANYA PERDES/KEPUTUSAN KEPALA DESA/SOP TENTANG PERENCANAAN, PELAKSANAAN, PENATAUSAHAAN DAN PERTANGGUNG JAWABAN APBDES BESERTA IMPLEMENTASINYA",
|
||||
icon: <IconClipboardText size={100} color={colors["blue-button"]} />,
|
||||
},
|
||||
]
|
||||
const state = useProxy(korupsiState);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const theme = useMantineTheme();
|
||||
const mobile = useMediaQuery(`(max-width: ${theme.breakpoints.sm})`);
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await state.desaAntikorupsi.findMany.load();
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
loadData();
|
||||
}, [])
|
||||
|
||||
const data = (state.desaAntikorupsi.findMany.data || []).slice(0, 6);
|
||||
return (
|
||||
<Stack gap={"0"} bg={colors.Bg} p={"sm"} h={mobile ? 2000 : 1150}>
|
||||
<Stack gap={"0"} bg={colors.Bg} p={"sm"} h={mobile ? 2000 : 1050}>
|
||||
<Container w={{ base: "100%", md: "80%" }} p={"xl"} >
|
||||
<Center>
|
||||
<Text fz={{base: "2.4rem", md: "3.4rem"}}>Desa Anti Korupsi</Text>
|
||||
<Text fz={{ base: "2.4rem", md: "3.4rem" }}>Desa Anti Korupsi</Text>
|
||||
</Center>
|
||||
<Text ta={"center"} fz={{base: "1.2rem", md: "1.4rem"}}>Desa antikorupsi mendorong pemerintahan jujur dan transparan. Keuangan desa dikelola terbuka dengan melibatkan warga mengawasi anggaran, sehingga digunakan tepat sasaran sesuai kebutuhan.</Text>
|
||||
<Text ta={"center"} fz={{ base: "1.2rem", md: "1.4rem" }}>Desa antikorupsi mendorong pemerintahan jujur dan transparan. Keuangan desa dikelola terbuka dengan melibatkan warga mengawasi anggaran, sehingga digunakan tepat sasaran sesuai kebutuhan.</Text>
|
||||
<Center py={20}>
|
||||
<Button radius={"lg"} fz={"h4"} bg={colors["blue-button"]} component={Link} href={"/darmasaba/desaantikorupsi"}>Selengkapnya</Button>
|
||||
<Button radius={"lg"} fz={"h4"} bg={colors["blue-button"]} component={Link} href={"/darmasaba/desa-anti-korupsi/detail"}>Selengkapnya</Button>
|
||||
</Center>
|
||||
</Container>
|
||||
<SimpleGrid
|
||||
@@ -57,29 +47,44 @@ function DesaAntiKorupsi() {
|
||||
sm: 2,
|
||||
|
||||
}}>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<Box
|
||||
key={k}
|
||||
>
|
||||
<Paper p={"lg"} >
|
||||
<Flex gap={"lg"} justify={"center"} align={"center"}>
|
||||
<Box >
|
||||
<Text fz={{base: "1.2rem", md: "lg"}} ta={"center"} c={colors["blue-button"]}>{v.judul}</Text>
|
||||
<Flex justify={"center"} align={"center"}>
|
||||
<Box>
|
||||
{v.icon}
|
||||
</Box>
|
||||
<Box px={20}>
|
||||
<Text fz={"sm"} ta={{base: "left", md: "justify"}}>{v.deskripsi}</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
{loading ? (
|
||||
<Center>
|
||||
<Text fz={"2.4rem"}>Memuat Data...</Text>
|
||||
</Center>
|
||||
) : (
|
||||
data.map((v, k) => {
|
||||
return (
|
||||
<Box
|
||||
key={k}
|
||||
>
|
||||
<Paper
|
||||
p={"lg"}
|
||||
withBorder
|
||||
shadow="sm"
|
||||
h={{ base: 250, md: 210 }}
|
||||
>
|
||||
<Flex gap={"lg"} align={"center"}>
|
||||
<Box>
|
||||
<Flex justify={"center"} align={"center"}>
|
||||
<Box>
|
||||
<IconClipboardText color={colors["blue-button"]} size={50} />
|
||||
</Box>
|
||||
<Box px={20} >
|
||||
<Stack gap={"xs"}>
|
||||
<Text fz={{ base: "1.2rem", md: "lg" }} ta={"center"} c={colors["blue-button"]} fw={500}>
|
||||
{v.kategori?.name || v.name || 'Kategori'}
|
||||
</Text>
|
||||
<Text dangerouslySetInnerHTML={{ __html: v.name || 'Name' }} fz={{ base: "1rem", md: "lg" }} ta={"center"} c={colors["blue-button"]} fw={500} />
|
||||
</Stack>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import images from "@/con/images";
|
||||
import profileLandingPageState from "@/app/admin/(dashboard)/_state/landing-page/profile";
|
||||
import { Center, Image, Paper, SimpleGrid } from "@mantine/core";
|
||||
import { useShallowEffect } from "@mantine/hooks";
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTransitionRouter } from 'next-view-transitions';
|
||||
import { useProxy } from "valtio/utils";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
|
||||
const listImageModule = Object.values(images.module);
|
||||
type ProgramInovasiItem = Prisma.ProgramInovasiGetPayload<{ include: { image: true } }>;
|
||||
|
||||
function ModuleItem({ item }: { item: string }) {
|
||||
function ModuleItem({ data }: { data: ProgramInovasiItem }) {
|
||||
const router = useTransitionRouter();
|
||||
return (
|
||||
<Paper
|
||||
onClick={() => {
|
||||
router.push(`/module/c`);
|
||||
router.push(`/${data.name}`);
|
||||
}}
|
||||
p={"md"}
|
||||
bg={"white"}
|
||||
@@ -22,7 +25,7 @@ function ModuleItem({ item }: { item: string }) {
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
>
|
||||
<Image src={item} alt="icon"
|
||||
<Image src={data.image?.link || ""} alt="icon"
|
||||
fit="contain"
|
||||
sizes="100%"
|
||||
loading="lazy"
|
||||
@@ -38,6 +41,11 @@ function ModuleItem({ item }: { item: string }) {
|
||||
}
|
||||
|
||||
function ModuleView() {
|
||||
const listImageState = useProxy(profileLandingPageState.programInovasi)
|
||||
|
||||
useShallowEffect(() => {
|
||||
listImageState.findMany.load()
|
||||
}, [])
|
||||
return (
|
||||
<SimpleGrid
|
||||
cols={{
|
||||
@@ -45,9 +53,9 @@ function ModuleView() {
|
||||
md: 3,
|
||||
}}
|
||||
>
|
||||
{listImageModule.map((item, k) => {
|
||||
return <ModuleItem key={k} item={item} />;
|
||||
})}
|
||||
{listImageState.findMany.data?.map((item) => (
|
||||
<ModuleItem key={item.id} data={item} />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import images from "@/con/images";
|
||||
import { ActionIcon, Flex, Image } from "@mantine/core";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { useTransitionRouter } from "next-view-transitions";
|
||||
|
||||
function SosmedView() {
|
||||
const listSosmed = Object.values(images.sosmed);
|
||||
|
||||
|
||||
function SosmedView({data} : {data : Prisma.MediaSosialGetPayload<{ include: { image: true } }>[]}) {
|
||||
const router = useTransitionRouter();
|
||||
return (
|
||||
<Flex gap={"md"} justify={"center"} align={"center"}>
|
||||
{listSosmed.map((item, k) => {
|
||||
{data?.map((item, k) => {
|
||||
return (
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
@@ -13,8 +16,11 @@ function SosmedView() {
|
||||
w={32}
|
||||
h={32}
|
||||
pos={"relative"}
|
||||
onClick={() => {
|
||||
router.push(item.iconUrl || "");
|
||||
}}
|
||||
>
|
||||
<Image src={item} alt="icon" loading="lazy" />
|
||||
<Image src={item.image?.link || ""} alt="icon" loading="lazy" />
|
||||
</ActionIcon>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
import colors from "@/con/colors";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
Skeleton,
|
||||
Flex,
|
||||
Grid,
|
||||
GridCol,
|
||||
@@ -11,9 +13,9 @@ import {
|
||||
Stack,
|
||||
Text
|
||||
} from "@mantine/core";
|
||||
import { useEffect, useState } from "react";
|
||||
import ModuleView from "./ModuleView";
|
||||
import SosmedView from "./SosmedView";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const getDayOfWeek = () => {
|
||||
const days = ['Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu'];
|
||||
@@ -56,6 +58,38 @@ const getWorkStatus = (day: string, currentTime: string): { status: string; mess
|
||||
|
||||
|
||||
function LandingPage() {
|
||||
const [socialMedia, setSocialMedia] = useState<Prisma.MediaSosialGetPayload<{ include: { image: true } }>[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSocialMedia = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/landingpage/mediasosial/findMany');
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
// Ensure the data is an array before setting it
|
||||
if (Array.isArray(result.data)) {
|
||||
setSocialMedia(result.data);
|
||||
} else if (Array.isArray(result)) {
|
||||
// In case the API returns the array directly
|
||||
setSocialMedia(result);
|
||||
} else {
|
||||
console.error('Unexpected API response format:', result);
|
||||
setSocialMedia([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching social media:', error);
|
||||
setSocialMedia([]); // Ensure we always have an array
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchSocialMedia();
|
||||
}, []);
|
||||
|
||||
const [workStatus, setWorkStatus] = useState<{ status: string; message: string }>
|
||||
({ status: '', message: '' });
|
||||
|
||||
@@ -248,7 +282,13 @@ function LandingPage() {
|
||||
|
||||
</Flex>
|
||||
<ModuleView />
|
||||
<SosmedView />
|
||||
{isLoading ? (
|
||||
<Skeleton height={32} width="100%" />
|
||||
) : socialMedia.length > 0 ? (
|
||||
<SosmedView data={socialMedia} />
|
||||
) : (
|
||||
<div>No social media links available</div>
|
||||
)}
|
||||
<Text c={colors.trans.dark[2]} style={{
|
||||
textAlign: "center"
|
||||
}} >Sampaikan saran dan masukan guna kemajuan dalam pembangunan. Semua lebih mudah melalui fitur interaktif</Text>
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import prestasiState from "@/app/admin/(dashboard)/_state/landing-page/prestasi-desa";
|
||||
import colors from "@/con/colors";
|
||||
import { BackgroundImage, Box, Button, Center, Container, Group, SimpleGrid, Stack, Text } from "@mantine/core";
|
||||
import { useProxy } from "valtio/utils";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
|
||||
const data = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Olahraga dan Kepemudaan",
|
||||
deskripsi: "Tim Bola Voli Putri Dharma Temaja meraih juara 3 dalam Turnamen Bola Voli Mangupura Cup 2024 kategori Putri Se-Bali ",
|
||||
image: "/api/img/prestasi-voli.jpeg",
|
||||
link: "/darmasaba/prestasi-desa/tim-bola-voli-putri-dharma-temaja-meraih-juara-3-dalam-turnamen-bola-voli-mangupura-cup-2024-kategori-putri-se-bali"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Hukum dan Kesadaran Masyarakat",
|
||||
deskripsi: "Prestasi Juara 3 dalam Lomba Keluarga Sadar Hukum Kabupaten Badung Tahun 2024",
|
||||
image: "/api/img/prestasilombahukum.png",
|
||||
link: "/darmasaba/prestasi-desa/prestasi-juara-3-dalam-lomba-keluarga-sadar-hukum-kabupaten-badung-tahun-2024"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Tata Kelola dan Inovasi Desa",
|
||||
deskripsi: "Peringkat 5 Dalam Ajang Bergengsi Mangupura Award",
|
||||
image: "/api/img/prestasi-peringkat-5.jpeg",
|
||||
link: "/darmasaba/prestasi-desa/peringkat-5-dalam-ajang-bergengsi-mangupura-award"
|
||||
}
|
||||
]
|
||||
function Prestasi() {
|
||||
const state = useProxy(prestasiState.prestasiDesa);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
prestasiState.kategoriPrestasi.findMany.load()
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await state.findMany.load();
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
loadData();
|
||||
}, [])
|
||||
|
||||
const data = (state.findMany.data || []).slice(0, 3);
|
||||
return (
|
||||
<>
|
||||
<Stack p={"sm"}>
|
||||
@@ -43,52 +46,56 @@ function Prestasi() {
|
||||
sm: 3
|
||||
}}
|
||||
>
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<BackgroundImage
|
||||
key={k}
|
||||
src={v.image}
|
||||
h={720}
|
||||
radius={16}
|
||||
pos={"relative"}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 16,
|
||||
zIndex: 0
|
||||
}}
|
||||
pos={"absolute"}
|
||||
w={"100%"}
|
||||
h={"100%"}
|
||||
bg={colors.trans.dark[2]}
|
||||
/>
|
||||
<Stack justify="space-between" h={"100%"} gap={0} p={"lg"} pos={"relative"}>
|
||||
<Box p={"lg"}>
|
||||
{loading ? (
|
||||
<Center>
|
||||
<Text fz={"2.4rem"}>Memuat Data...</Text>
|
||||
</Center>
|
||||
) : (
|
||||
data.map((v, k) => {
|
||||
return (
|
||||
<BackgroundImage
|
||||
key={k}
|
||||
src={v.image?.link || ''}
|
||||
radius={16}
|
||||
pos={"relative"}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 16,
|
||||
zIndex: 0
|
||||
}}
|
||||
pos={"absolute"}
|
||||
w={"100%"}
|
||||
h={"100%"}
|
||||
bg={colors.trans.dark[2]}
|
||||
/>
|
||||
<Stack justify="space-between" h={"100%"} gap={0} p={"lg"} pos={"relative"}>
|
||||
<Box p={"lg"}>
|
||||
<Text
|
||||
c={"white"}
|
||||
fz={{ base: "1rem", md: "1.125rem", lg: "1.25rem", xl: "1.5rem" }}
|
||||
ta={"center"}
|
||||
>
|
||||
{v.kategori.name}
|
||||
</Text>
|
||||
</Box>
|
||||
<Text
|
||||
fw={"bold"}
|
||||
c={"white"}
|
||||
fz={{ base: "1rem", md: "1.125rem", lg: "1.25rem", xl: "1.5rem"}}
|
||||
fz={{ base: "2rem", md: "2.5rem", lg: "2.7rem", xl: "3rem" }}
|
||||
ta={"center"}
|
||||
>
|
||||
{v.title}
|
||||
</Text>
|
||||
</Box>
|
||||
<Text
|
||||
fw={"bold"}
|
||||
c={"white"}
|
||||
fz={{base: "2rem", md: "2.5rem", lg: "2.7rem", xl: "3rem"}}
|
||||
ta={"center"}
|
||||
>
|
||||
{v.deskripsi}
|
||||
</Text>
|
||||
<Group justify="center">
|
||||
<Button component={Link} href={v.link} px={46} radius={"100"} size="md" bg={colors["blue-button"]}>
|
||||
Lihat Detail
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</BackgroundImage>
|
||||
)
|
||||
})}
|
||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||
/>
|
||||
<Group justify="center">
|
||||
<Button onClick={() => router.push(`/darmasaba/prestasi-desa/${v.id}`)} px={46} radius={"100"} size="md" bg={colors["blue-button"]}>
|
||||
Lihat Detail
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</BackgroundImage>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
@@ -1,12 +1,51 @@
|
||||
'use client'
|
||||
import colors from "@/con/colors";
|
||||
import { Box, Button, Center, Container, Image, Paper, SimpleGrid, Stack, Text, useMantineTheme } from "@mantine/core";
|
||||
import { Box, Button, Center, Container, Image, Paper, SimpleGrid, Stack, Text, Title, useMantineTheme } from "@mantine/core";
|
||||
import { useMediaQuery } from "@mantine/hooks";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function SDGS() {
|
||||
const theme = useMantineTheme();
|
||||
const mobile = useMediaQuery(`(max-width: ${theme.breakpoints.sm})`);
|
||||
const [sdgsDesa, setSdgsDesa] = useState<Prisma.SDGSDesaGetPayload<{ include: { image: true } }>[] | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSdgsDesa = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/landingpage/sdgsdesa/findMany');
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
// Ensure the data is an array before setting it
|
||||
let data = [];
|
||||
if (Array.isArray(result.data)) {
|
||||
data = result.data;
|
||||
} else if (Array.isArray(result)) {
|
||||
// In case the API returns the array directly
|
||||
data = result;
|
||||
} else {
|
||||
console.error('Unexpected API response format:', result);
|
||||
setSdgsDesa([]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort by jumlah in descending order and take top 3
|
||||
const top3Sdgs = [...data]
|
||||
.sort((a, b) => parseInt(b.jumlah) - parseInt(a.jumlah))
|
||||
.slice(0, 3);
|
||||
|
||||
setSdgsDesa(top3Sdgs);
|
||||
} catch (error) {
|
||||
console.error('Error fetching sdgs desa:', error);
|
||||
setSdgsDesa([]);
|
||||
}
|
||||
};
|
||||
|
||||
fetchSdgsDesa();
|
||||
}, []);
|
||||
return (
|
||||
<Stack p={"sm"}>
|
||||
<Container w={{ base: "100%", md: "80%" }} p={"xl"}>
|
||||
@@ -16,22 +55,82 @@ export default function SDGS() {
|
||||
<Text fz={"1.4rem"} ta={"center"}>SDGs Desa adalah upaya menerapkan 17 Tujuan Pembangunan Berkelanjutan di tingkat desa.
|
||||
Dengan fokus pada pengentasan kemiskinan, pendidikan, kesehatan, kesetaraan gender, dan pelestarian lingkungan, kami berkomitmen untuk menciptakan desa yang lebih baik bagi semua</Text>
|
||||
<Box py={50}>
|
||||
<Paper p={"lg"} bg={colors.Bg}>
|
||||
<SimpleGrid
|
||||
cols={{
|
||||
base: 1,
|
||||
sm: 3,
|
||||
}}>
|
||||
<Center>
|
||||
<Image src={"/api/img/sgdesa-1.png"} alt="" w={mobile ? 250 : 200} />
|
||||
</Center>
|
||||
<Center>
|
||||
<Image src={"/api/img/sgdesa-2.png"} alt="" w={mobile ? 250 : 220} />
|
||||
</Center>
|
||||
<Center>
|
||||
<Image src={"/api/img/sgdesa-3.png"} alt="" w={mobile ? 250 : 190} />
|
||||
</Center>
|
||||
</SimpleGrid>
|
||||
<Paper p={{ base: 'md', md: 'xl' }} bg={colors.Bg} radius="lg" shadow="sm">
|
||||
{sdgsDesa && sdgsDesa.length > 0 ? (
|
||||
<SimpleGrid
|
||||
cols={{ base: 1, sm: 3 }}
|
||||
spacing="xl"
|
||||
verticalSpacing="xl"
|
||||
>
|
||||
{sdgsDesa.map((item) => (
|
||||
<Box
|
||||
key={item.id}
|
||||
p="md"
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
transition: 'transform 0.2s',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-5px)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
p="md"
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
width: mobile ? 150 : 180,
|
||||
height: mobile ? 150 : 180,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: '1.5rem',
|
||||
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)'
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={item.image?.link ? item.image.link : '/placeholder-sdgs.png'}
|
||||
alt={item.name}
|
||||
width={mobile ? 100 : 120}
|
||||
height={mobile ? 100 : 120}
|
||||
style={{
|
||||
objectFit: 'contain',
|
||||
maxWidth: '100%',
|
||||
maxHeight: '100%'
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Text
|
||||
ta="center"
|
||||
fz={{ base: 'lg', md: 'xl' }}
|
||||
fw={700}
|
||||
mb="xs"
|
||||
style={{ lineHeight: 1.2 }}
|
||||
>
|
||||
{item.name}
|
||||
</Text>
|
||||
<Title
|
||||
order={2}
|
||||
ta="center"
|
||||
c={colors['blue-button']}
|
||||
style={{
|
||||
fontSize: mobile ? '2.5rem' : '3rem',
|
||||
lineHeight: 1,
|
||||
margin: '0.5rem 0',
|
||||
fontWeight: 800
|
||||
}}
|
||||
>
|
||||
{item.jumlah}
|
||||
</Title>
|
||||
</Box>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
) : (
|
||||
<Text>Tidak ada data SDGs Desa</Text>
|
||||
)}
|
||||
</Paper>
|
||||
<Center>
|
||||
<Button component={Link} href={"/darmasaba/sdgs-desa"} radius={"lg"} fz={"1.2rem"} mt={20} bg={colors["blue-button"]}>Selengkapnya</Button>
|
||||
|
||||
Reference in New Issue
Block a user