Compare commits
4 Commits
nico/17-ju
...
nico/18-ju
| Author | SHA1 | Date | |
|---|---|---|---|
| d2f53ff69b | |||
| 40f0294595 | |||
| 6ed0246cea | |||
| af726043bd |
@@ -23,7 +23,7 @@
|
|||||||
"@mantine/charts": "^7.17.1",
|
"@mantine/charts": "^7.17.1",
|
||||||
"@mantine/core": "^7.17.4",
|
"@mantine/core": "^7.17.4",
|
||||||
"@mantine/dates": "^8.1.0",
|
"@mantine/dates": "^8.1.0",
|
||||||
"@mantine/dropzone": "^7.17.0",
|
"@mantine/dropzone": "^8.1.1",
|
||||||
"@mantine/form": "^8.1.0",
|
"@mantine/form": "^8.1.0",
|
||||||
"@mantine/hooks": "^7.17.4",
|
"@mantine/hooks": "^7.17.4",
|
||||||
"@mantine/tiptap": "^7.17.4",
|
"@mantine/tiptap": "^7.17.4",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "edit",
|
||||||
"judul": "Lambang Desa",
|
"judul": "Lambang Desa",
|
||||||
"deskripsi" : "<ul><li>Memperkokoh kerukunan hidup masyarakat dalam jalinan adat, budaya, olahraga, dan agama.</li><li>Meningkatkan kualitas pelayanan publik dengan menerapkan teknologi informasi dan komunikasi terintegrasi.</li><li>Meningkatkan tata kelola pemerintah desa dengan menerapkan prinsip good governance dan good clean government.</li><li>Meningkatkan kualitas pendidikan, kesehatan, Keluarga Berencana serta pengelolaan kependudukan.</li><li>Memperkuat usaha mikro kecil dan menengah (UMKM) dan BUMDesa sebagai pilar ekonomi masyarakat.</li><li>Mewujudkan tatanan kehidupan bermasyarakat yang menjunjung tinggi penegakan hukum dan HAM.</li><li>Meningkatkan perlindungan dan pengelolaan terhadap sumber daya alam dan lingkungan hidup.</li><li>Memperkuat daya saing desa melalui peningkatan mutu sumber daya manusia dan infrastruktur desa berbasis potensi desa.</li><li>Meningkatkan sinergisitas potensi budaya, pertanian dalam arti luas dan pariwisata.</li><li>Memperkuat daya saing desa melalui peningkatan mutu sumber daya manusia dan infrastruktur desa berbasis potensi desa.</li><li>Meningkatkan sinergisitas potensi budaya, pertanian dalam arti luas dan pariwisata.</li></ul>"
|
"deskripsi" : "<ul><li>Memperkokoh kerukunan hidup masyarakat dalam jalinan adat, budaya, olahraga, dan agama.</li><li>Meningkatkan kualitas pelayanan publik dengan menerapkan teknologi informasi dan komunikasi terintegrasi.</li><li>Meningkatkan tata kelola pemerintah desa dengan menerapkan prinsip good governance dan good clean government.</li><li>Meningkatkan kualitas pendidikan, kesehatan, Keluarga Berencana serta pengelolaan kependudukan.</li><li>Memperkuat usaha mikro kecil dan menengah (UMKM) dan BUMDesa sebagai pilar ekonomi masyarakat.</li><li>Mewujudkan tatanan kehidupan bermasyarakat yang menjunjung tinggi penegakan hukum dan HAM.</li><li>Meningkatkan perlindungan dan pengelolaan terhadap sumber daya alam dan lingkungan hidup.</li><li>Memperkuat daya saing desa melalui peningkatan mutu sumber daya manusia dan infrastruktur desa berbasis potensi desa.</li><li>Meningkatkan sinergisitas potensi budaya, pertanian dalam arti luas dan pariwisata.</li><li>Memperkuat daya saing desa melalui peningkatan mutu sumber daya manusia dan infrastruktur desa berbasis potensi desa.</li><li>Meningkatkan sinergisitas potensi budaya, pertanian dalam arti luas dan pariwisata.</li></ul>"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "edit",
|
||||||
"judul": "Maskot Desa",
|
"judul": "Maskot Desa",
|
||||||
"deskripsi" : "<p>Pudak adalah bunga dari tanaman sejenis pandan (Pandanaceae). Bentuk bunga ini tersusun dalam beberapa lapisan, terbungkus oleh kelopak warna putih (semacam daun lonjong) yang ujungnya meruncing.</p><p>Bunga Pudak berwarna kuning dan akan terlihat jika kelopak atau pelepahnya telah mekar. Kekhasan dari bunga pudak, yaitu mempunyai aroma wangi yang semerbak nan lembut (tidak menyengat), dan dapat menebar keharuman sepanjang pagi atau pun sore hari. Tanaman ini dapat tumbuh di sepanjang pantai, aliran sungai, di atas batu-batu karang, dan juga di tanah ladang.</p><p>Dalam Kamus Jawa Kuna- Indonesia kata “Pudak” berarti bunga pandan atau Pandanus Moschatus (Mardiwarsito: 1981: 442). Selain itu bunga pudak juga dapat disebut ketaka atau ketaki (Mardiwarsito, 1981: 276). Sedangkan kata “Sategal” berasal dari kata dasar “Tegal” yang berarti ladang (Mardiwarsito, 1981: 593). Jadi Pudak Sategal dapat diartikan sebagai satu ladang luas yang dipenuhi bunga pudak dan menabar keharuman.</p><p>Pada sebuah kesempatan, Ida Pedanda Putu Pemaron menjelaskan mengenai makna dari istilah Pudak Sategal dengan sebuah analogi bahwa, sekuntum bunga pudak memiliki aroma wangi atau keharuman yang sangat kuat, apalagi jika satu ladang penuh bunga pudak, maka dapat dipastikan aroma keharumannya akan membumbung menyebar ke segala penjuru (Wawancara, 18 Mei 2019 di Geria Putra Mandara Kenderan, Tegallalang). “Pudak” ialah sebuah bunga yang memiliki aroma wangi atau keharuman yang semerbak, lembut, dan khas.</p><p>Garapan Tari Maskot Desa Darmasaba Sekar Pudak diwujudkan ke dalam bentuk tari kreasi yang ditarikan secara berkelompok dengan jumlah lima orang penari perempuan (putri).</p><p>Pemilihan penari perempuan dimaksudkan untuk mempresentasikan keindahan, keluwesan, dan keharuman dari bunga pudak. Sedangkan penetapan jumlah penari lima orang didasarkan atas pertimbangan kebutuhan koreografi agar dapat membentuk desain-desain komposisi lantai yang menarik dan dinamis, baik ketika ditarikan di area panggung yang luas atau pun area panggung yang kecil. Penyajian tari maskot ini dirancang dengan durasi waktu 9 menit.</p>"
|
"deskripsi" : "<p>Pudak adalah bunga dari tanaman sejenis pandan (Pandanaceae). Bentuk bunga ini tersusun dalam beberapa lapisan, terbungkus oleh kelopak warna putih (semacam daun lonjong) yang ujungnya meruncing.</p><p>Bunga Pudak berwarna kuning dan akan terlihat jika kelopak atau pelepahnya telah mekar. Kekhasan dari bunga pudak, yaitu mempunyai aroma wangi yang semerbak nan lembut (tidak menyengat), dan dapat menebar keharuman sepanjang pagi atau pun sore hari. Tanaman ini dapat tumbuh di sepanjang pantai, aliran sungai, di atas batu-batu karang, dan juga di tanah ladang.</p><p>Dalam Kamus Jawa Kuna- Indonesia kata “Pudak” berarti bunga pandan atau Pandanus Moschatus (Mardiwarsito: 1981: 442). Selain itu bunga pudak juga dapat disebut ketaka atau ketaki (Mardiwarsito, 1981: 276). Sedangkan kata “Sategal” berasal dari kata dasar “Tegal” yang berarti ladang (Mardiwarsito, 1981: 593). Jadi Pudak Sategal dapat diartikan sebagai satu ladang luas yang dipenuhi bunga pudak dan menabar keharuman.</p><p>Pada sebuah kesempatan, Ida Pedanda Putu Pemaron menjelaskan mengenai makna dari istilah Pudak Sategal dengan sebuah analogi bahwa, sekuntum bunga pudak memiliki aroma wangi atau keharuman yang sangat kuat, apalagi jika satu ladang penuh bunga pudak, maka dapat dipastikan aroma keharumannya akan membumbung menyebar ke segala penjuru (Wawancara, 18 Mei 2019 di Geria Putra Mandara Kenderan, Tegallalang). “Pudak” ialah sebuah bunga yang memiliki aroma wangi atau keharuman yang semerbak, lembut, dan khas.</p><p>Garapan Tari Maskot Desa Darmasaba Sekar Pudak diwujudkan ke dalam bentuk tari kreasi yang ditarikan secara berkelompok dengan jumlah lima orang penari perempuan (putri).</p><p>Pemilihan penari perempuan dimaksudkan untuk mempresentasikan keindahan, keluwesan, dan keharuman dari bunga pudak. Sedangkan penetapan jumlah penari lima orang didasarkan atas pertimbangan kebutuhan koreografi agar dapat membentuk desain-desain komposisi lantai yang menarik dan dinamis, baik ketika ditarikan di area panggung yang luas atau pun area panggung yang kecil. Penyajian tari maskot ini dirancang dengan durasi waktu 9 menit.</p>"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "edit",
|
||||||
"biodata": "<p>I.B Surya Prabhawa Manuaba, S.H., M.H., adalah Perbekel Darmasaba periode 2021-2027, seorang advokat, pendiri Mantra Legal Consultants & Advocates, serta aktif di bidang musik dan akademis. Dia menempuh pendidikan hukum di Universitas Udayana dan Universitas Mahasaraswati Denpasar serta memiliki pengalaman luas di berbagai organisasi dan kepemimpinan.</p>",
|
"biodata": "<p>I.B Surya Prabhawa Manuaba, S.H., M.H., adalah Perbekel Darmasaba periode 2021-2027, seorang advokat, pendiri Mantra Legal Consultants & Advocates, serta aktif di bidang musik dan akademis. Dia menempuh pendidikan hukum di Universitas Udayana dan Universitas Mahasaraswati Denpasar serta memiliki pengalaman luas di berbagai organisasi dan kepemimpinan.</p>",
|
||||||
"pengalaman": "<ul><li>2021 - 2027: Perbekel Desa Darmasaba</li><li>2015 - Sekarang: Founder & Managing Director Mantra Legal Consultants & Advocates</li><li>2020 - Sekarang: Founder Ugawa Record Music Studio</li><li>2010 - 2016: Dosen Fakultas Hukum Universitas Mahasaraswati Denpasar</li></ul>",
|
"pengalaman": "<ul><li>2021 - 2027: Perbekel Desa Darmasaba</li><li>2015 - Sekarang: Founder & Managing Director Mantra Legal Consultants & Advocates</li><li>2020 - Sekarang: Founder Ugawa Record Music Studio</li><li>2010 - 2016: Dosen Fakultas Hukum Universitas Mahasaraswati Denpasar</li></ul>",
|
||||||
"pengalamanOrganisasi": "<ul> <li>1996 – 1997: Ketua OSIS SMP Negeri 1 Abiansemal</li><li>1999 – 2000: Ketua OSIS SMA Negeri 1 Mengwi</li> <li>2008 – 2009: Ketua BEM Universitas Mahasaraswati Denpasar</li> <li>2008 – 2010: Ketua Sekaa Taruna Sila Dharma, Banjar Tengah, Desa Adat Tegal, Darmasaba</li> <li>2020 – Sekarang: Pengurus Young Lawyer Committee Peradi Denpasar</li> <li>2021 – Sekarang: Dewan Kehormatan Himpunan Pengusaha Muda Indonesia (HIPMI) Badung</li> <li>2023 – 2028: Komite Tetap Advokasi – Bidang Hukum dan Regulasi Kamar Dagang dan Industri Badung</li> </ul>",
|
"pengalamanOrganisasi": "<ul> <li>1996 – 1997: Ketua OSIS SMP Negeri 1 Abiansemal</li><li>1999 – 2000: Ketua OSIS SMA Negeri 1 Mengwi</li> <li>2008 – 2009: Ketua BEM Universitas Mahasaraswati Denpasar</li> <li>2008 – 2010: Ketua Sekaa Taruna Sila Dharma, Banjar Tengah, Desa Adat Tegal, Darmasaba</li> <li>2020 – Sekarang: Pengurus Young Lawyer Committee Peradi Denpasar</li> <li>2021 – Sekarang: Dewan Kehormatan Himpunan Pengusaha Muda Indonesia (HIPMI) Badung</li> <li>2023 – 2028: Komite Tetap Advokasi – Bidang Hukum dan Regulasi Kamar Dagang dan Industri Badung</li> </ul>",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "edit",
|
||||||
"judul": "Sejarah Desa",
|
"judul": "Sejarah Desa",
|
||||||
"deskripsi": "<p>Asal – usul nama Darmasaba tertuang dalam lontar Usada Bali. Seperti di tulis dalam monografi Desa Darmasaba tahun 1980 silam, nama Darmasaba berkaitan dengan keturunan Danghyang Nirarta diceritakan, Sang kawi-wiku asal Daha (Jawa Timur) itu memiliki cucu bernama Ida Pedanda Sakti Manuaba yang tigggal di Desa Kendran Tegalalang Gianyar. Merasa tidak disenangi sang ayah, Ida Pedanda Sakti Manuaba pergi mengembara bersama dua orang pengiringnya. Pengembaraan sang pendeta sampai di pura Sarin Buana di Jimbaran. Saat mengadakan semedi di tempat ini sang pendeta melihat sinar api. Yang sangat jauh di utara. Timbul keinginan Ida Pedanda Manuaba untuk mengunjungi tempat itu. Sampailah sang Pedanda di pura Batan Bila Peguyangan. Disini Ida Pedanda Manuaba singgah menghadap Ida Pedanda Budha yang tinggal disana. Selanjutnya, kedua pendeta bersama-sama menuju arah utara dan singgah di Taman Cang Ana, sebuah taman milik Arya Lanang Blusung. Di tempat ini kedua pendeta bersama-sama melaksanakan semedi dan menetap untuk sementara waktu.</p>"
|
"deskripsi": "<p>Asal – usul nama Darmasaba tertuang dalam lontar Usada Bali. Seperti di tulis dalam monografi Desa Darmasaba tahun 1980 silam, nama Darmasaba berkaitan dengan keturunan Danghyang Nirarta diceritakan, Sang kawi-wiku asal Daha (Jawa Timur) itu memiliki cucu bernama Ida Pedanda Sakti Manuaba yang tigggal di Desa Kendran Tegalalang Gianyar. Merasa tidak disenangi sang ayah, Ida Pedanda Sakti Manuaba pergi mengembara bersama dua orang pengiringnya. Pengembaraan sang pendeta sampai di pura Sarin Buana di Jimbaran. Saat mengadakan semedi di tempat ini sang pendeta melihat sinar api. Yang sangat jauh di utara. Timbul keinginan Ida Pedanda Manuaba untuk mengunjungi tempat itu. Sampailah sang Pedanda di pura Batan Bila Peguyangan. Disini Ida Pedanda Manuaba singgah menghadap Ida Pedanda Budha yang tinggal disana. Selanjutnya, kedua pendeta bersama-sama menuju arah utara dan singgah di Taman Cang Ana, sebuah taman milik Arya Lanang Blusung. Di tempat ini kedua pendeta bersama-sama melaksanakan semedi dan menetap untuk sementara waktu.</p>"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id" : "1",
|
"id" : "edit",
|
||||||
"visi" : "<p>Mewujudkan Desa Darmasaba yang sejahtera, unggul, religius, berbudaya, dan aman dengan berlandaskan Tri Hita Karana</p>",
|
"visi" : "<p>Mewujudkan Desa Darmasaba yang sejahtera, unggul, religius, berbudaya, dan aman dengan berlandaskan Tri Hita Karana</p>",
|
||||||
"misi" : "<ul><li>Memperkokoh kerukunan hidup masyarakat dalam jalinan adat, budaya, olahraga, dan agama.</li><li>Meningkatkan kualitas pelayanan publik dengan menerapkan teknologi informasi dan komunikasi terintegrasi.</li><li>Meningkatkan tata kelola pemerintah desa dengan menerapkan prinsip good governance dan good clean government.</li><li>Meningkatkan kualitas pendidikan, kesehatan, Keluarga Berencana serta pengelolaan kependudukan.</li><li>Memperkuat usaha mikro kecil dan menengah (UMKM) dan BUMDesa sebagai pilar ekonomi masyarakat.</li><li>Mewujudkan tatanan kehidupan bermasyarakat yang menjunjung tinggi penegakan hukum dan HAM.</li><li>Meningkatkan perlindungan dan pengelolaan terhadap sumber daya alam dan lingkungan hidup.</li><li>Memperkuat daya saing desa melalui peningkatan mutu sumber daya manusia dan infrastruktur desa berbasis potensi desa.</li><li>Meningkatkan sinergisitas potensi budaya, pertanian dalam arti luas dan pariwisata.</li></ul>"
|
"misi" : "<ul><li>Memperkokoh kerukunan hidup masyarakat dalam jalinan adat, budaya, olahraga, dan agama.</li><li>Meningkatkan kualitas pelayanan publik dengan menerapkan teknologi informasi dan komunikasi terintegrasi.</li><li>Meningkatkan tata kelola pemerintah desa dengan menerapkan prinsip good governance dan good clean government.</li><li>Meningkatkan kualitas pendidikan, kesehatan, Keluarga Berencana serta pengelolaan kependudukan.</li><li>Memperkuat usaha mikro kecil dan menengah (UMKM) dan BUMDesa sebagai pilar ekonomi masyarakat.</li><li>Mewujudkan tatanan kehidupan bermasyarakat yang menjunjung tinggi penegakan hukum dan HAM.</li><li>Meningkatkan perlindungan dan pengelolaan terhadap sumber daya alam dan lingkungan hidup.</li><li>Memperkuat daya saing desa melalui peningkatan mutu sumber daya manusia dan infrastruktur desa berbasis potensi desa.</li><li>Meningkatkan sinergisitas potensi budaya, pertanian dalam arti luas dan pariwisata.</li></ul>"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "edit",
|
||||||
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
"name": "I.B Surya Prabhawa Manuaba, S.H., M.H.",
|
||||||
"biodata": "<p>I.B Surya Prabhawa Manuaba, S.H., M.H., adalah Perbekel Darmasaba periode 2021-2027, seorang advokat, pendiri Mantra Legal Consultants & Advocates, serta aktif di bidang musik dan akademis. Dia menempuh pendidikan hukum di Universitas Udayana dan Universitas Mahasaraswati Denpasar, serta memiliki pengalaman luas di berbagai organisasi dan kepemimpinan.</p>",
|
"biodata": "<p>I.B Surya Prabhawa Manuaba, S.H., M.H., adalah Perbekel Darmasaba periode 2021-2027, seorang advokat, pendiri Mantra Legal Consultants & Advocates, serta aktif di bidang musik dan akademis. Dia menempuh pendidikan hukum di Universitas Udayana dan Universitas Mahasaraswati Denpasar, serta memiliki pengalaman luas di berbagai organisasi dan kepemimpinan.</p>",
|
||||||
"riwayat": "<ul> <li>2021 - 2027: Perbekel Desa Darmasaba</li> <li>2015 - Sekarang: Founder & Managing Director Mantra Legal Consultants & Advocates</li> <li>2020 - Sekarang: Founder Ugawa Record Music Studio</li> <li>2010 - 2016: Dosen Fakultas Hukum Universitas Mahasaraswati Denpasar</li> </ul>",
|
"riwayat": "<ul> <li>2021 - 2027: Perbekel Desa Darmasaba</li> <li>2015 - Sekarang: Founder & Managing Director Mantra Legal Consultants & Advocates</li> <li>2020 - Sekarang: Founder Ugawa Record Music Studio</li> <li>2010 - 2016: Dosen Fakultas Hukum Universitas Mahasaraswati Denpasar</li> </ul>",
|
||||||
|
|||||||
@@ -50,26 +50,26 @@ model AppMenuChild {
|
|||||||
// ========================================= FILE STORAGE ========================================= //
|
// ========================================= FILE STORAGE ========================================= //
|
||||||
|
|
||||||
model FileStorage {
|
model FileStorage {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique
|
name String @unique
|
||||||
realName String
|
realName String
|
||||||
path String
|
path String
|
||||||
mimeType String
|
mimeType String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime?
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
link String
|
link String
|
||||||
Berita Berita[]
|
Berita Berita[]
|
||||||
PotensiDesa PotensiDesa[]
|
PotensiDesa PotensiDesa[]
|
||||||
Posyandu Posyandu[]
|
Posyandu Posyandu[]
|
||||||
StrukturPPID StrukturPPID[]
|
StrukturPPID StrukturPPID[]
|
||||||
GalleryFoto GalleryFoto[]
|
GalleryFoto GalleryFoto[]
|
||||||
PelayananSuratKeterangan PelayananSuratKeterangan[]
|
PelayananSuratKeterangan PelayananSuratKeterangan[]
|
||||||
Penghargaan Penghargaan[]
|
Penghargaan Penghargaan[]
|
||||||
ProfileDesaImage ProfileDesaImage[]
|
ProfileDesaImage ProfileDesaImage[]
|
||||||
ProfilePPID ProfilePPID[]
|
ProfilePPID ProfilePPID[]
|
||||||
ProfilPerbekel ProfilPerbekel[]
|
ProfilPerbekel ProfilPerbekel[]
|
||||||
}
|
}
|
||||||
|
|
||||||
//========================================= MENU PPID ========================================= //
|
//========================================= MENU PPID ========================================= //
|
||||||
@@ -116,6 +116,7 @@ model ProfilePPID {
|
|||||||
riwayat String @db.Text
|
riwayat String @db.Text
|
||||||
pengalaman String @db.Text
|
pengalaman String @db.Text
|
||||||
unggulan String @db.Text
|
unggulan String @db.Text
|
||||||
|
imageUrl String?
|
||||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||||
imageId String?
|
imageId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
@@ -278,37 +279,37 @@ model LambangDesa {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model MaskotDesa {
|
model MaskotDesa {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
judul String
|
judul String
|
||||||
deskripsi String @db.Text
|
deskripsi String @db.Text
|
||||||
images ProfileDesaImage[]
|
images ProfileDesaImage[]
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime @default(now())
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
model ProfileDesaImage {
|
model ProfileDesaImage {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
label String
|
label String
|
||||||
image FileStorage @relation(fields: [imageId], references: [id])
|
image FileStorage @relation(fields: [imageId], references: [id])
|
||||||
imageId String
|
imageId String
|
||||||
MaskotDesa MaskotDesa @relation(fields: [maskotDesaId], references: [id])
|
MaskotDesa MaskotDesa @relation(fields: [maskotDesaId], references: [id])
|
||||||
maskotDesaId String
|
maskotDesaId String
|
||||||
}
|
}
|
||||||
|
|
||||||
model ProfilPerbekel {
|
model ProfilPerbekel {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
biodata String @db.Text
|
biodata String @db.Text
|
||||||
pengalaman String @db.Text
|
pengalaman String @db.Text
|
||||||
pengalamanOrganisasi String @db.Text
|
pengalamanOrganisasi String @db.Text
|
||||||
programUnggulan String @db.Text
|
programUnggulan String @db.Text
|
||||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||||
imageId String?
|
imageId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime @default(now())
|
deletedAt DateTime @default(now())
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================= BERITA ========================================= //
|
// ========================================= BERITA ========================================= //
|
||||||
|
|||||||
BIN
public/bungapudak.png
Normal file
BIN
public/bungapudak.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 221 KiB |
BIN
public/klimakstari.png
Normal file
BIN
public/klimakstari.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 217 KiB |
BIN
public/pohonpudak.png
Normal file
BIN
public/pohonpudak.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 253 KiB |
|
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 195 KiB |
BIN
public/tarisekar.png
Normal file
BIN
public/tarisekar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 208 KiB |
@@ -6,7 +6,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
const templateForm = z.object({
|
const templateForm = z.object({
|
||||||
name: z.string().min(1).max(50),
|
name: z.string().min(1).max(50),
|
||||||
deskripsi: z.string().min(1).max(50),
|
deskripsi: z.string().min(1).max(5000),
|
||||||
kategori: z.string().min(1).max(50),
|
kategori: z.string().min(1).max(50),
|
||||||
imageId: z.string().min(1).max(50),
|
imageId: z.string().min(1).max(50),
|
||||||
content: z.string().min(1).max(5000),
|
content: z.string().min(1).max(5000),
|
||||||
|
|||||||
@@ -38,13 +38,13 @@ const sejarahDesa = proxy({
|
|||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/desa/profile/sejarah-desa/${id}`);
|
const response = await fetch(`/api/desa/profile/sejarah/${id}`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.data = result.data;
|
this.data = result.data;
|
||||||
return result.data;
|
return result.data;
|
||||||
@@ -91,64 +91,69 @@ const sejarahDesa = proxy({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
// Validate form
|
// Validate form
|
||||||
const validation = sejarahDesaForm.safeParse(this.form);
|
const validation = sejarahDesaForm.safeParse(this.form);
|
||||||
|
|
||||||
if (!validation.success) {
|
if (!validation.success) {
|
||||||
const errors = validation.error.issues
|
const errors = validation.error.issues
|
||||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||||
.join(", ");
|
.join(", ");
|
||||||
toast.error(`Form tidak valid: ${errors}`);
|
toast.error(`Form tidak valid: ${errors}`);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
this.error = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/desa/profile/sejarah/${this.id}`,
|
||||||
|
{
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(this.form),
|
||||||
}
|
}
|
||||||
|
);
|
||||||
this.loading = true;
|
|
||||||
this.error = null;
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json().catch(() => ({}));
|
||||||
try {
|
throw new Error(
|
||||||
const response = await fetch(`/api/desa/profile/sejarah-desa/${this.id}`, {
|
errorData.message || `HTTP error! status: ${response.status}`
|
||||||
method: "PUT",
|
);
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(this.form),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
toast.success("Berhasil update profile");
|
|
||||||
// Refresh profile data
|
|
||||||
await sejarahDesa.findUnique.load(this.id);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
throw new Error(result.message || "Gagal update profile");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const errorMessage = (error as Error).message;
|
|
||||||
this.error = errorMessage;
|
|
||||||
console.error("Update profile error:", errorMessage);
|
|
||||||
toast.error("Terjadi kesalahan saat update profile");
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Reset form
|
|
||||||
reset() {
|
|
||||||
this.id = "";
|
|
||||||
this.form = { ...sejarahDesaDefaultForm };
|
|
||||||
this.error = null;
|
|
||||||
this.loading = false;
|
|
||||||
this.isReadOnly = false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
toast.success("Berhasil update profile");
|
||||||
|
// Refresh profile data
|
||||||
|
await sejarahDesa.findUnique.load(this.id);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || "Gagal update profile");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = (error as Error).message;
|
||||||
|
this.error = errorMessage;
|
||||||
|
console.error("Update profile error:", errorMessage);
|
||||||
|
toast.error("Terjadi kesalahan saat update profile");
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Reset form
|
||||||
|
reset() {
|
||||||
|
this.id = "";
|
||||||
|
this.form = { ...sejarahDesaDefaultForm };
|
||||||
|
this.error = null;
|
||||||
|
this.loading = false;
|
||||||
|
this.isReadOnly = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// ========================================= VISI MISI DESA ========================================= //
|
// ========================================= VISI MISI DESA ========================================= //
|
||||||
@@ -187,12 +192,12 @@ const visiMisiDesa = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/desa/profile/visi-misi/${id}`);
|
const response = await fetch(`/api/desa/profile/visi-misi/${id}`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.data = result.data;
|
this.data = result.data;
|
||||||
return result.data;
|
return result.data;
|
||||||
@@ -239,64 +244,66 @@ const visiMisiDesa = proxy({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
// Validate form
|
// Validate form
|
||||||
const validation = visiMisiDesaForm.safeParse(this.form);
|
const validation = visiMisiDesaForm.safeParse(this.form);
|
||||||
|
|
||||||
if (!validation.success) {
|
if (!validation.success) {
|
||||||
const errors = validation.error.issues
|
const errors = validation.error.issues
|
||||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||||
.join(", ");
|
.join(", ");
|
||||||
toast.error(`Form tidak valid: ${errors}`);
|
toast.error(`Form tidak valid: ${errors}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/desa/profile/visi-misi/${this.id}`, {
|
const response = await fetch(`/api/desa/profile/visi-misi/${this.id}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(this.form),
|
body: JSON.stringify(this.form),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
|
throw new Error(
|
||||||
}
|
errorData.message || `HTTP error! status: ${response.status}`
|
||||||
|
);
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
toast.success("Berhasil update visi misi desa");
|
|
||||||
// Refresh profile data
|
|
||||||
await visiMisiDesa.findUnique.load(this.id);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
throw new Error(result.message || "Gagal update visi misi desa");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const errorMessage = (error as Error).message;
|
|
||||||
this.error = errorMessage;
|
|
||||||
console.error("Update visi misi desa error:", errorMessage);
|
|
||||||
toast.error("Terjadi kesalahan saat update visi misi desa");
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Reset form
|
|
||||||
reset() {
|
|
||||||
this.id = "";
|
|
||||||
this.form = { ...visiMisiDesaDefaultForm };
|
|
||||||
this.error = null;
|
|
||||||
this.loading = false;
|
|
||||||
this.isReadOnly = false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
toast.success("Berhasil update visi misi desa");
|
||||||
|
// Refresh profile data
|
||||||
|
await visiMisiDesa.findUnique.load(this.id);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || "Gagal update visi misi desa");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = (error as Error).message;
|
||||||
|
this.error = errorMessage;
|
||||||
|
console.error("Update visi misi desa error:", errorMessage);
|
||||||
|
toast.error("Terjadi kesalahan saat update visi misi desa");
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Reset form
|
||||||
|
reset() {
|
||||||
|
this.id = "";
|
||||||
|
this.form = { ...visiMisiDesaDefaultForm };
|
||||||
|
this.error = null;
|
||||||
|
this.loading = false;
|
||||||
|
this.isReadOnly = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// ========================================= LAMBANG DESA ========================================= //
|
// ========================================= LAMBANG DESA ========================================= //
|
||||||
@@ -334,13 +341,13 @@ const lambangDesa = proxy({
|
|||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/desa/profile/lambang-desa/${id}`);
|
const response = await fetch(`/api/desa/profile/lambang/${id}`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.data = result.data;
|
this.data = result.data;
|
||||||
return result.data;
|
return result.data;
|
||||||
@@ -387,64 +394,69 @@ const lambangDesa = proxy({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
// Validate form
|
// Validate form
|
||||||
const validation = lambangDesaForm.safeParse(this.form);
|
const validation = lambangDesaForm.safeParse(this.form);
|
||||||
|
|
||||||
if (!validation.success) {
|
if (!validation.success) {
|
||||||
const errors = validation.error.issues
|
const errors = validation.error.issues
|
||||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||||
.join(", ");
|
.join(", ");
|
||||||
toast.error(`Form tidak valid: ${errors}`);
|
toast.error(`Form tidak valid: ${errors}`);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
this.error = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/desa/profile/lambang/${this.id}`,
|
||||||
|
{
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(this.form),
|
||||||
}
|
}
|
||||||
|
);
|
||||||
this.loading = true;
|
|
||||||
this.error = null;
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json().catch(() => ({}));
|
||||||
try {
|
throw new Error(
|
||||||
const response = await fetch(`/api/desa/profile/lambang-desa/${this.id}`, {
|
errorData.message || `HTTP error! status: ${response.status}`
|
||||||
method: "PUT",
|
);
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(this.form),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
toast.success("Berhasil update lambang desa");
|
|
||||||
// Refresh profile data
|
|
||||||
await lambangDesa.findUnique.load(this.id);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
throw new Error(result.message || "Gagal update lambang desa");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const errorMessage = (error as Error).message;
|
|
||||||
this.error = errorMessage;
|
|
||||||
console.error("Update lambang desa error:", errorMessage);
|
|
||||||
toast.error("Terjadi kesalahan saat update lambang desa");
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Reset form
|
|
||||||
reset() {
|
|
||||||
this.id = "";
|
|
||||||
this.form = { ...lambangDesaDefaultForm };
|
|
||||||
this.error = null;
|
|
||||||
this.loading = false;
|
|
||||||
this.isReadOnly = false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
toast.success("Berhasil update lambang desa");
|
||||||
|
// Refresh profile data
|
||||||
|
await lambangDesa.findUnique.load(this.id);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || "Gagal update lambang desa");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = (error as Error).message;
|
||||||
|
this.error = errorMessage;
|
||||||
|
console.error("Update lambang desa error:", errorMessage);
|
||||||
|
toast.error("Terjadi kesalahan saat update lambang desa");
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Reset form
|
||||||
|
reset() {
|
||||||
|
this.id = "";
|
||||||
|
this.form = { ...lambangDesaDefaultForm };
|
||||||
|
this.error = null;
|
||||||
|
this.loading = false;
|
||||||
|
this.isReadOnly = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// ========================================= MASKOT DESA ========================================= //
|
// ========================================= MASKOT DESA ========================================= //
|
||||||
@@ -502,7 +514,7 @@ const maskotDesa = proxy({
|
|||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/desa/profile/maskot-desa/${id}`);
|
const response = await fetch(`/api/desa/profile/maskot/${id}`);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (response.ok && result.success) {
|
if (response.ok && result.success) {
|
||||||
@@ -577,7 +589,7 @@ const maskotDesa = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`/api/desa/profile/maskot-desa/${this.id}`,
|
`/api/desa/profile/maskot/${this.id}`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
@@ -678,7 +690,7 @@ const profilPerbekel = proxy({
|
|||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/desa/profile/profil-perbekel/${id}`);
|
const response = await fetch(`/api/desa/profile/profileperbekel/${id}`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
@@ -750,7 +762,7 @@ const profilPerbekel = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`/api/desa/profile/profil-perbekel/${this.id}`,
|
`/api/desa/profile/profileperbekel/${this.id}`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
@@ -806,11 +818,12 @@ const profilPerbekel = proxy({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const stateProfileDesa = {
|
const stateProfileDesa = proxy({
|
||||||
|
lambangDesa,
|
||||||
maskotDesa,
|
maskotDesa,
|
||||||
profilPerbekel,
|
profilPerbekel,
|
||||||
visiMisiDesa,
|
visiMisiDesa,
|
||||||
sejarahDesa,
|
sejarahDesa,
|
||||||
};
|
});
|
||||||
|
|
||||||
export default stateProfileDesa;
|
export default stateProfileDesa;
|
||||||
|
|||||||
@@ -125,16 +125,6 @@ function EditBerita() {
|
|||||||
placeholder="masukkan judul"
|
placeholder="masukkan judul"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SelectCategory
|
|
||||||
value={formData.kategoriBeritaId}
|
|
||||||
onChange={(val) => {
|
|
||||||
setFormData({
|
|
||||||
...formData,
|
|
||||||
kategoriBeritaId: val?.id || ''
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
value={formData.deskripsi}
|
value={formData.deskripsi}
|
||||||
onChange={(e) => setFormData({ ...formData, deskripsi: e.target.value })}
|
onChange={(e) => setFormData({ ...formData, deskripsi: e.target.value })}
|
||||||
@@ -174,6 +164,16 @@ function EditBerita() {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<SelectCategory
|
||||||
|
value={formData.kategoriBeritaId}
|
||||||
|
onChange={(val) => {
|
||||||
|
setFormData({
|
||||||
|
...formData,
|
||||||
|
kategoriBeritaId: val?.id || ''
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<Button onClick={handleSubmit}>Edit Berita</Button>
|
<Button onClick={handleSubmit}>Edit Berita</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ export default function CreateBerita() {
|
|||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box mb={10}>
|
<Box mb={10}>
|
||||||
<Button variant="subtle" onClick={() => router.back()}>
|
<Button variant="subtle" onClick={() => router.back()}>
|
||||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
<Paper bg={colors["white-1"]} p={"md"} w={{ base: "100%", md: "50%" }}>
|
<Paper bg={colors["white-1"]} p={"md"} w={{ base: "100%", md: "50%" }}>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
@@ -79,8 +79,9 @@ export default function CreateBerita() {
|
|||||||
placeholder="masukkan judul"
|
placeholder="masukkan judul"
|
||||||
/>
|
/>
|
||||||
<SelectCategory
|
<SelectCategory
|
||||||
|
value={beritaState.berita.create.form.kategoriBeritaId}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
beritaState.berita.create.form.kategoriBeritaId = val.id;
|
beritaState.berita.create.form.kategoriBeritaId = val?.id || "";
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -114,10 +115,10 @@ export default function CreateBerita() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Text fz={"sm"} fw={"bold"}>Konten</Text>
|
<Text fz={"sm"} fw={"bold"}>Konten</Text>
|
||||||
<CreateEditor
|
<CreateEditor
|
||||||
value={beritaState.berita.create.form.content}
|
value={beritaState.berita.create.form.content}
|
||||||
onChange={(htmlContent) => {
|
onChange={(htmlContent) => {
|
||||||
beritaState.berita.create.form.content = htmlContent;
|
beritaState.berita.create.form.content = htmlContent;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Button bg={colors['blue-button']} onClick={handleSubmit}>Simpan Berita</Button>
|
<Button bg={colors['blue-button']} onClick={handleSubmit}>Simpan Berita</Button>
|
||||||
@@ -126,26 +127,37 @@ export default function CreateBerita() {
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
||||||
function SelectCategory({
|
interface SelectCategoryProps {
|
||||||
onChange,
|
|
||||||
}: {
|
|
||||||
onChange: (value: Prisma.KategoriBeritaGetPayload<{
|
onChange: (value: Prisma.KategoriBeritaGetPayload<{
|
||||||
select: {
|
select: {
|
||||||
name: true;
|
name: true;
|
||||||
id: true;
|
id: true;
|
||||||
};
|
};
|
||||||
}>) => void;
|
}> | null) => void;
|
||||||
}) {
|
value?: string | null;
|
||||||
|
defaultValue?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectCategory({
|
||||||
|
onChange,
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
}: SelectCategoryProps) {
|
||||||
const categoryState = useProxy(stateDashboardBerita.category);
|
const categoryState = useProxy(stateDashboardBerita.category);
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
categoryState.findMany.load();
|
categoryState.findMany.load().then(() => {
|
||||||
|
console.log("Kategori berhasil dimuat:", categoryState.findMany.data);
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!categoryState.findMany.data) {
|
if (!categoryState.findMany.data) {
|
||||||
return <Skeleton height={38} />;
|
return <Skeleton height={38} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const selectedValue = value || defaultValue;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
label={<Text fz={"sm"} fw={"bold"}>Kategori</Text>}
|
label={<Text fz={"sm"} fw={"bold"}>Kategori</Text>}
|
||||||
@@ -154,13 +166,19 @@ export default function CreateBerita() {
|
|||||||
label: item.name,
|
label: item.name,
|
||||||
value: item.id,
|
value: item.id,
|
||||||
}))}
|
}))}
|
||||||
onChange={(val) => {
|
value={selectedValue || null}
|
||||||
const selected = categoryState.findMany.data?.find((item) => item.id === val);
|
onChange={(val: string | null) => {
|
||||||
if (selected) {
|
if (val) {
|
||||||
onChange(selected);
|
const selected = categoryState.findMany.data?.find((item) => item.id === val);
|
||||||
|
if (selected) {
|
||||||
|
onChange(selected);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onChange(null);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
searchable
|
searchable
|
||||||
|
clearable
|
||||||
nothingFoundMessage="Tidak ditemukan"
|
nothingFoundMessage="Tidak ditemukan"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, SimpleGrid, Paper, Stack, Title, Group, Button, Text } from '@mantine/core';
|
|
||||||
import React from 'react';
|
|
||||||
import { DesaEditor } from '../../../_com/desaEditor';
|
|
||||||
|
|
||||||
function LambangDesa() {
|
|
||||||
return (
|
|
||||||
<Box py={10}>
|
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>Lambang Desa</Title>
|
|
||||||
<Text fw={"bold"}>Deskripsi Lambang Desa</Text>
|
|
||||||
<DesaEditor showSubmit={false} />
|
|
||||||
<Group>
|
|
||||||
<Button
|
|
||||||
mt={10}
|
|
||||||
bg={colors['blue-button']}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>List Lambang Desa</Title>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</SimpleGrid>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LambangDesa;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import LayoutTabsEdit from "../_lib/layoutTabsEdit"
|
|
||||||
|
|
||||||
function Layout({children}: {children: React.ReactNode}) {
|
|
||||||
return (
|
|
||||||
<LayoutTabsEdit>
|
|
||||||
{children}
|
|
||||||
</LayoutTabsEdit>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Layout;
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, SimpleGrid, Paper, Stack, Title, Group, Button, Text } from '@mantine/core';
|
|
||||||
import React from 'react';
|
|
||||||
import { DesaEditor } from '../../../_com/desaEditor';
|
|
||||||
|
|
||||||
function MaskotDesa() {
|
|
||||||
return (
|
|
||||||
<Box py={10}>
|
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>Maskot Desa</Title>
|
|
||||||
<Text fw={"bold"}>Deskripsi Maskot Desa</Text>
|
|
||||||
<DesaEditor showSubmit={false} />
|
|
||||||
<Group>
|
|
||||||
<Button
|
|
||||||
mt={10}
|
|
||||||
bg={colors['blue-button']}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>List Maskot Desa</Title>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</SimpleGrid>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MaskotDesa;
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, SimpleGrid, Paper, Stack, Title, Group, Button, TextInput, Text } from '@mantine/core';
|
|
||||||
import React from 'react';
|
|
||||||
import { DesaEditor } from '../../../_com/desaEditor';
|
|
||||||
|
|
||||||
function ProfilePerbekel() {
|
|
||||||
return (
|
|
||||||
<Box py={10}>
|
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>Profil Perbekel</Title>
|
|
||||||
<TextInput
|
|
||||||
label="Nama Perbekel"
|
|
||||||
placeholder="masukkan nama perbekel"
|
|
||||||
/>
|
|
||||||
<Text fz={"sm"} fw={"bold"}>Biodata</Text>
|
|
||||||
<DesaEditor showSubmit={false} />
|
|
||||||
<Text fz={"sm"} fw={"bold"}>Pengalaman</Text>
|
|
||||||
<DesaEditor showSubmit={false} />
|
|
||||||
<Text fz={"sm"} fw={"bold"}>Pengalaman Organisasi</Text>
|
|
||||||
<DesaEditor showSubmit={false} />
|
|
||||||
<Text fz={"sm"} fw={"bold"}>Program Unggulan</Text>
|
|
||||||
<DesaEditor showSubmit={false} />
|
|
||||||
<Group>
|
|
||||||
<Button
|
|
||||||
mt={10}
|
|
||||||
bg={colors['blue-button']}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>List Profil Perbekel</Title>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</SimpleGrid>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ProfilePerbekel;
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Button, Group, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function SejarahDesa() {
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box py={10}>
|
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>Sejarah Desa</Title>
|
|
||||||
<Text fw={"bold"}>Deskripsi Sejarah Desa</Text>
|
|
||||||
<Group>
|
|
||||||
<Button
|
|
||||||
mt={10}
|
|
||||||
bg={colors['blue-button']}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</SimpleGrid>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SejarahDesa;
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Paper, Stack } from '@mantine/core';
|
|
||||||
|
|
||||||
function Page() {
|
|
||||||
return (
|
|
||||||
<Paper bg={colors['white-1']} p={'md'} radius={10}>
|
|
||||||
<Stack gap={"22"}>
|
|
||||||
<Box>
|
|
||||||
<Stack gap={'lg'}>
|
|
||||||
<Paper p={"xl"} bg={colors['BG-trans']}>
|
|
||||||
{/* <Box px={{ base: 0, md: 30 }}>
|
|
||||||
<Text ta={"center"} fz={{ base: "h3", md: "h2" }} fw={"bold"} dangerouslySetInnerHTML={{ __html: listDasarHukum.findById.data.judul }} />
|
|
||||||
</Box>
|
|
||||||
<Box px={{ base: 0, md: 30 }}>
|
|
||||||
<Text fz={{ base: "md", md: "h3" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: listDasarHukum.findById.data.content }} />
|
|
||||||
</Box> */}
|
|
||||||
</Paper>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Page;
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Button, Group, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
|
||||||
import { DesaEditor } from '../../../_com/desaEditor';
|
|
||||||
|
|
||||||
function VisiMisiDesa() {
|
|
||||||
return (
|
|
||||||
<Box py={10}>
|
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>Visi Desa</Title>
|
|
||||||
<Text fw={"bold"}>Deskripsi Visi Desa</Text>
|
|
||||||
<DesaEditor showSubmit={false} />
|
|
||||||
<Group>
|
|
||||||
<Button
|
|
||||||
mt={10}
|
|
||||||
bg={colors['blue-button']}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>List Visi Desa</Title>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</SimpleGrid>
|
|
||||||
<SimpleGrid py={30} cols={{ base: 1, md: 2 }}>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>Misi Desa</Title>
|
|
||||||
<Text fw={"bold"}>Deskripsi Misi Desa</Text>
|
|
||||||
<DesaEditor showSubmit={false}/>
|
|
||||||
<Group>
|
|
||||||
<Button
|
|
||||||
mt={10}
|
|
||||||
bg={colors['blue-button']}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Title order={3}>List Misi Desa</Title>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</SimpleGrid>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default VisiMisiDesa;
|
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
'use client'
|
||||||
|
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
||||||
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { Box, Button, Center, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
|
import { IconArrowBack } from '@tabler/icons-react';
|
||||||
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
|
function Page() {
|
||||||
|
const lambangState = useProxy(stateProfileDesa.lambangDesa)
|
||||||
|
const router = useRouter()
|
||||||
|
const params = useParams()
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const id = params?.id as string;
|
||||||
|
if (!id) {
|
||||||
|
toast.error("ID tidak valid");
|
||||||
|
router.push("/admin/desa/profile/profile-desa");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await lambangState.findUnique.load(id);
|
||||||
|
if (data) {
|
||||||
|
lambangState.update.initialize(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
lambangState.update.reset();
|
||||||
|
lambangState.findUnique.reset(); // opsional: reset juga data lama
|
||||||
|
};
|
||||||
|
}, [params?.id, router]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (isSubmitting || !lambangState.update.form.judul.trim()) {
|
||||||
|
toast.error("Judul wajib diisi");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsSubmitting(true)
|
||||||
|
try {
|
||||||
|
const success = await lambangState.update.submit()
|
||||||
|
if (success) {
|
||||||
|
toast.success("Data berhasil disimpan");
|
||||||
|
router.push("/admin/desa/profile/profile-desa");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error update lambang desa:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat update lambang desa");
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
lambangState.findUnique.loading ||
|
||||||
|
!lambangState.findUnique.data ||
|
||||||
|
lambangState.update.loading
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Center h={400}>
|
||||||
|
<Text>Memuat data...</Text>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Group>
|
||||||
|
<Button variant="subtle" onClick={handleBack}>
|
||||||
|
<IconArrowBack color={colors['blue-button']} size={20} />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
<Paper bg={colors['white-1']} p={'xs'} w={{ base: '100%', md: '50%' }}>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Box>
|
||||||
|
<Box>
|
||||||
|
<Stack>
|
||||||
|
<Title order={3}>Edit Lambang Desa</Title>
|
||||||
|
<TextInput
|
||||||
|
label={<Text fz={"md"} fw={"bold"}>Judul</Text>}
|
||||||
|
placeholder="Judul"
|
||||||
|
value={lambangState.update.form.judul}
|
||||||
|
onChange={(e) => lambangState.update.form.judul = e.currentTarget.value}
|
||||||
|
error={!lambangState.update.form.judul && "Judul wajib diisi"}
|
||||||
|
/>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Deskripsi</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={lambangState.update.form.deskripsi}
|
||||||
|
onChange={(val) => lambangState.update.form.deskripsi = val}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Group>
|
||||||
|
<Button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
bg={colors['blue-button']}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
'use client'
|
||||||
|
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
||||||
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import ApiFetch from '@/lib/api-fetch';
|
||||||
|
import { Box, Button, Group, Image, Paper, SimpleGrid, 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';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
|
function Page() {
|
||||||
|
const maskotState = useProxy(stateProfileDesa.maskotDesa)
|
||||||
|
const router = useRouter()
|
||||||
|
const params = useParams()
|
||||||
|
|
||||||
|
const [images, setImages] = useState<
|
||||||
|
Array<{ file: File; preview: string; label: string }>
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
judul: maskotState.update.form.judul || '',
|
||||||
|
deskripsi: maskotState.update.form.deskripsi || '',
|
||||||
|
images: [] as Array<{ label: string; imageId: string }>
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const id = params?.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await maskotState.findUnique.load(id);
|
||||||
|
if (data) {
|
||||||
|
// 🔥 INI YANG KURANG!
|
||||||
|
maskotState.update.initialize(data);
|
||||||
|
|
||||||
|
setFormData({
|
||||||
|
judul: data.judul || '',
|
||||||
|
deskripsi: data.deskripsi || '',
|
||||||
|
images: (data.images || []).map((img: any) => ({
|
||||||
|
label: img.label,
|
||||||
|
imageId: img.image?.id ?? '',
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data?.images?.length > 0 && data.images[0].image?.link) {
|
||||||
|
setImages(data.images.map((img: any) => ({
|
||||||
|
file: null,
|
||||||
|
preview: img.image.link,
|
||||||
|
label: img.label,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading berita:", error);
|
||||||
|
toast.error("Gagal memuat data berita");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
}, [params?.id]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
const uploadedImages = [];
|
||||||
|
|
||||||
|
// Upload semua gambar baru
|
||||||
|
for (const img of images) {
|
||||||
|
if (!img.file || !(img.file instanceof File)) {
|
||||||
|
toast.error("File tidak valid untuk di-upload");
|
||||||
|
continue; // atau return kalau kamu mau hentikan semua
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.fileStorage.create.post({
|
||||||
|
file: img.file,
|
||||||
|
name: img.file.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploaded = res.data?.data;
|
||||||
|
if (!uploaded?.id) {
|
||||||
|
toast.error("Gagal upload salah satu gambar");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadedImages.push({
|
||||||
|
imageId: uploaded.id,
|
||||||
|
label: img.label || 'main',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update ke global state
|
||||||
|
maskotState.update.updateField("judul", formData.judul);
|
||||||
|
maskotState.update.updateField("deskripsi", formData.deskripsi);
|
||||||
|
maskotState.update.updateField("images", uploadedImages);
|
||||||
|
|
||||||
|
const success = await maskotState.update.submit();
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
toast.success("Maskot berhasil diperbarui!");
|
||||||
|
router.push("/admin/desa/profile/profile-desa");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error update maskot:", error);
|
||||||
|
toast.error("Gagal update maskot");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Group>
|
||||||
|
<Button variant="subtle" onClick={handleBack}>
|
||||||
|
<IconArrowBack color={colors['blue-button']} size={20} />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
<Paper bg={colors['white-1']} p={'xs'} w={{ base: '100%', md: '100%' }}>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Box>
|
||||||
|
<Box>
|
||||||
|
<Stack>
|
||||||
|
<Title order={3}>Edit Maskot Desa</Title>
|
||||||
|
<TextInput
|
||||||
|
w={{ base: '100%', md: '50%' }}
|
||||||
|
label={<Text fz={"md"} fw={"bold"}>Judul</Text>}
|
||||||
|
placeholder="Masukkan judul"
|
||||||
|
value={formData.judul}
|
||||||
|
onChange={(val) => setFormData({ ...formData, judul: val.currentTarget.value })}
|
||||||
|
/>
|
||||||
|
<Box w={{ base: '100%', md: '50%' }}>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Deskripsi</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={formData.deskripsi}
|
||||||
|
onChange={(val) => setFormData({ ...formData, deskripsi: val })}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Gambar</Text>
|
||||||
|
<Box w={{ base: '100%', md: '50%' }}>
|
||||||
|
<Dropzone
|
||||||
|
|
||||||
|
onDrop={(files) => {
|
||||||
|
const newImages = files.map((file) => ({
|
||||||
|
file,
|
||||||
|
preview: URL.createObjectURL(file),
|
||||||
|
label: '',
|
||||||
|
}));
|
||||||
|
setImages((prev) => [...prev, ...newImages]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<SimpleGrid cols={{ base: 2, md: 4 }} >
|
||||||
|
{images.map((img, index) => (
|
||||||
|
<Box key={index} mb="md">
|
||||||
|
<Paper p="sm" radius="md" withBorder style={{ position: 'relative', maxWidth: 300 }}>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Group>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
color="red"
|
||||||
|
variant="light"
|
||||||
|
onClick={() => {
|
||||||
|
const updated = [...images];
|
||||||
|
updated.splice(index, 1);
|
||||||
|
setImages(updated);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Hapus
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
<Image
|
||||||
|
src={img.preview}
|
||||||
|
alt={`Preview ${index}`}
|
||||||
|
width={280}
|
||||||
|
height={180}
|
||||||
|
fit="cover"
|
||||||
|
radius="sm"
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label={`Label Gambar ${index + 1}`}
|
||||||
|
placeholder="Contoh: Logo, Maskot, Dll"
|
||||||
|
value={img.label}
|
||||||
|
onChange={(e) => {
|
||||||
|
const updated = [...images];
|
||||||
|
updated[index].label = e.currentTarget.value;
|
||||||
|
setImages(updated);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
<Group>
|
||||||
|
<Button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
bg={colors['blue-button']}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
'use client'
|
||||||
|
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
||||||
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { Box, Button, Center, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
|
import { IconArrowBack } from '@tabler/icons-react';
|
||||||
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
|
function Page() {
|
||||||
|
const sejarahState = useProxy(stateProfileDesa.sejarahDesa)
|
||||||
|
const router = useRouter()
|
||||||
|
const params = useParams()
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const id = params?.id as string;
|
||||||
|
if (!id) {
|
||||||
|
toast.error("ID tidak valid");
|
||||||
|
router.push("/admin/desa/profile/profile-desa");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await sejarahState.findUnique.load(id);
|
||||||
|
if (data) {
|
||||||
|
sejarahState.update.initialize(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
sejarahState.update.reset();
|
||||||
|
sejarahState.findUnique.reset(); // opsional: reset juga data lama
|
||||||
|
};
|
||||||
|
}, [params?.id, router]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (isSubmitting || !sejarahState.update.form.judul.trim()) {
|
||||||
|
toast.error("Judul wajib diisi");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsSubmitting(true)
|
||||||
|
try {
|
||||||
|
const success = await sejarahState.update.submit()
|
||||||
|
if (success) {
|
||||||
|
toast.success("Data berhasil disimpan");
|
||||||
|
router.push("/admin/desa/profile/profile-desa");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error update sejarah desa:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat update sejarah desa");
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
sejarahState.findUnique.loading ||
|
||||||
|
!sejarahState.findUnique.data ||
|
||||||
|
sejarahState.update.loading
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Center h={400}>
|
||||||
|
<Text>Memuat data...</Text>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Group>
|
||||||
|
<Button variant="subtle" onClick={handleBack}>
|
||||||
|
<IconArrowBack color={colors['blue-button']} size={20} />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
<Paper bg={colors['white-1']} p={'xs'} w={{ base: '100%', md: '50%' }}>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Box>
|
||||||
|
<Box>
|
||||||
|
<Stack>
|
||||||
|
<Title order={3}>Edit Sejarah Desa</Title>
|
||||||
|
<TextInput
|
||||||
|
label={<Text fz={"md"} fw={"bold"}>Judul</Text>}
|
||||||
|
placeholder="Judul"
|
||||||
|
value={sejarahState.update.form.judul}
|
||||||
|
onChange={(e) => sejarahState.update.form.judul = e.currentTarget.value}
|
||||||
|
error={!sejarahState.update.form.judul && "Judul wajib diisi"}
|
||||||
|
/>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Deskripsi</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={sejarahState.update.form.deskripsi}
|
||||||
|
onChange={(val) => sejarahState.update.form.deskripsi = val}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Group>
|
||||||
|
<Button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
bg={colors['blue-button']}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
'use client'
|
||||||
|
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
||||||
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { Box, Button, Center, Group, Paper, Stack, Text, Title } from '@mantine/core';
|
||||||
|
import { IconArrowBack } from '@tabler/icons-react';
|
||||||
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
|
function Page() {
|
||||||
|
const visiMisiState = useProxy(stateProfileDesa.visiMisiDesa)
|
||||||
|
const router = useRouter()
|
||||||
|
const params = useParams()
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const id = params?.id as string;
|
||||||
|
if (!id) {
|
||||||
|
toast.error("ID tidak valid");
|
||||||
|
router.push("/admin/desa/profile/profile-desa");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await visiMisiState.findUnique.load(id);
|
||||||
|
if (data) {
|
||||||
|
visiMisiState.update.initialize(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
visiMisiState.update.reset();
|
||||||
|
visiMisiState.findUnique.reset(); // opsional: reset juga data lama
|
||||||
|
};
|
||||||
|
}, [params?.id, router]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (isSubmitting || !visiMisiState.update.form.visi.trim()) {
|
||||||
|
toast.error("Visi wajib diisi");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsSubmitting(true)
|
||||||
|
try {
|
||||||
|
const success = await visiMisiState.update.submit()
|
||||||
|
if (success) {
|
||||||
|
toast.success("Data berhasil disimpan");
|
||||||
|
router.push("/admin/desa/profile/profile-desa");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error update sejarah desa:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat update sejarah desa");
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
visiMisiState.findUnique.loading ||
|
||||||
|
!visiMisiState.findUnique.data ||
|
||||||
|
visiMisiState.update.loading
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Center h={400}>
|
||||||
|
<Text>Memuat data...</Text>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Group>
|
||||||
|
<Button variant="subtle" onClick={handleBack}>
|
||||||
|
<IconArrowBack color={colors['blue-button']} size={20} />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
<Paper bg={colors['white-1']} p={'xs'} w={{ base: '100%', md: '50%' }}>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Box>
|
||||||
|
<Box>
|
||||||
|
<Stack>
|
||||||
|
<Title order={3}>Edit Visi Misi Desa</Title>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Visi</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={visiMisiState.update.form.visi}
|
||||||
|
onChange={(val) => visiMisiState.update.form.visi = val}
|
||||||
|
/>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Misi</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={visiMisiState.update.form.misi}
|
||||||
|
onChange={(val) => visiMisiState.update.form.misi = val}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Group>
|
||||||
|
<Button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
bg={colors['blue-button']}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -1,131 +1,168 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Paper, Stack, Grid, GridCol, Title, Button, Box, Text, Center, Image, SimpleGrid } from '@mantine/core';
|
import { Box, Button, Card, Center, Grid, GridCol, Group, Image, Paper, Stack, Text, Title } from '@mantine/core';
|
||||||
|
import { useSnapshot } from 'valtio';
|
||||||
|
import stateProfileDesa from '../../../_state/desa/profile';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { IconEdit } from '@tabler/icons-react';
|
import { IconEdit } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
|
const snap = useSnapshot(stateProfileDesa);
|
||||||
|
|
||||||
|
// Panggil load data sekali saat komponen mount
|
||||||
|
useEffect(() => {
|
||||||
|
stateProfileDesa.sejarahDesa.findUnique.load("edit");
|
||||||
|
stateProfileDesa.visiMisiDesa.findUnique.load("edit");
|
||||||
|
stateProfileDesa.lambangDesa.findUnique.load("edit");
|
||||||
|
stateProfileDesa.maskotDesa.findUnique.load("edit");
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const sejarah = snap.sejarahDesa.findUnique.data;
|
||||||
|
const visiMisi = snap.visiMisiDesa.findUnique.data;
|
||||||
|
const lambang = snap.lambangDesa.findUnique.data;
|
||||||
|
const maskot = snap.maskotDesa.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper bg={colors['white-1']} p={'md'} radius={10}>
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
<Stack gap={"22"}>
|
<Stack gap={"lg"}>
|
||||||
<Grid>
|
<Title order={2}>Preview Profile Desa</Title>
|
||||||
<GridCol span={{ base: 12, md: 11 }}>
|
|
||||||
<Title order={2}>Preview Profile Desa</Title>
|
|
||||||
</GridCol>
|
|
||||||
<GridCol span={{ base: 12, md: 1 }}>
|
|
||||||
<Button bg={colors['blue-button']} onClick={() => router.push('/admin/desa/profile/edit/sejarah_desa')}>
|
|
||||||
<IconEdit size={16} />
|
|
||||||
</Button>
|
|
||||||
</GridCol>
|
|
||||||
</Grid>
|
|
||||||
{/* Sejarah Desa */}
|
{/* Sejarah Desa */}
|
||||||
<Box>
|
{sejarah && (
|
||||||
<Stack gap={'lg'}>
|
<Box>
|
||||||
<Paper p={"xl"} bg={colors['BG-trans']}>
|
<Stack gap={'lg'}>
|
||||||
<Box pb={30}>
|
<Paper p={"md"} bg={colors['BG-trans']}>
|
||||||
<Center>
|
<Grid>
|
||||||
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
<GridCol span={{ base: 12, md: 11 }}>
|
||||||
</Center>
|
<Title order={2}>Preview Sejarah Desa</Title>
|
||||||
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Sejarah Desa</Text>
|
</GridCol>
|
||||||
</Box>
|
<GridCol span={{ base: 12, md: 1 }}>
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']} w={{ base: "100%", md: "100%" }}>
|
<Button bg={colors['blue-button']} onClick={() => router.push(`/admin/desa/profile/profile-desa/${sejarah.id}/sejarah_desa`)}>
|
||||||
<Text fz={{ base: "md", md: "h3" }} ta={"justify"}>
|
<IconEdit size={20} />
|
||||||
Test
|
</Button>
|
||||||
</Text>
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
<Box pb={30}>
|
||||||
|
<Center>
|
||||||
|
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||||
|
</Center>
|
||||||
|
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>{sejarah.judul}</Text>
|
||||||
|
</Box>
|
||||||
|
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
||||||
|
<Text fz={{ base: "md", md: "h3" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: sejarah.deskripsi }} />
|
||||||
|
</Paper>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Paper>
|
</Stack>
|
||||||
</Stack>
|
</Box>
|
||||||
</Box>
|
)}
|
||||||
|
|
||||||
{/* Visi Misi Desa */}
|
{/* Visi Misi Desa */}
|
||||||
<Box>
|
{visiMisi && (
|
||||||
<Stack gap={'lg'}>
|
<Box>
|
||||||
<Paper p={"xl"} bg={colors['BG-trans']}>
|
<Stack gap={'lg'}>
|
||||||
<Box pb={30}>
|
<Paper p={"md"} bg={colors['BG-trans']}>
|
||||||
<Center>
|
<Grid>
|
||||||
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
<GridCol span={{ base: 12, md: 11 }}>
|
||||||
</Center>
|
<Title order={2}>Preview Visi Misi Desa</Title>
|
||||||
</Box>
|
</GridCol>
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']} w={{ base: "100%", md: "100%" }}>
|
<GridCol span={{ base: 12, md: 1 }}>
|
||||||
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Visi Desa</Text>
|
<Button onClick={() => router.push(`/admin/desa/profile/profile-desa/${visiMisi.id}/visi_misi_desa`)} bg={colors['blue-button']}>
|
||||||
<Text fz={{ base: "md", md: "h3" }} ta={"justify"}>
|
<IconEdit size={20} />
|
||||||
Test
|
</Button>
|
||||||
</Text>
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
<Box pb={30}>
|
||||||
|
<Center>
|
||||||
|
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||||
|
</Center>
|
||||||
|
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Visi Misi Desa</Text>
|
||||||
|
</Box>
|
||||||
|
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
||||||
|
<Text fw={"bold"} fz={{ base: "lg", md: "h2" }}>Visi Desa</Text>
|
||||||
|
<Text fz={{ base: "md", md: "h3" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: visiMisi.visi }} />
|
||||||
|
<Text fw={"bold"} fz={{ base: "lg", md: "h2" }}>Misi Desa</Text>
|
||||||
|
<Text fz={{ base: "md", md: "h3" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: visiMisi.misi }} />
|
||||||
|
</Paper>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']} w={{ base: "100%", md: "100%" }}>
|
</Stack>
|
||||||
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Misi Desa</Text>
|
</Box>
|
||||||
<Text fz={{ base: "md", md: "h3" }} ta={"justify"}>
|
)}
|
||||||
Test
|
|
||||||
</Text>
|
|
||||||
</Paper>
|
|
||||||
</Paper>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
{/* Lambang Desa */}
|
{/* Lambang Desa */}
|
||||||
<Box>
|
{lambang && (
|
||||||
<Stack gap={'lg'}>
|
<Box>
|
||||||
<Paper p={"xl"} bg={colors['BG-trans']}>
|
<Stack gap={'lg'}>
|
||||||
<Box pb={30}>
|
<Paper p={"md"} bg={colors['BG-trans']}>
|
||||||
<Center>
|
<Grid>
|
||||||
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
<GridCol span={{ base: 12, md: 11 }}>
|
||||||
</Center>
|
<Title order={2}>Preview Lambang Desa</Title>
|
||||||
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Lambang Desa</Text>
|
</GridCol>
|
||||||
</Box>
|
<GridCol span={{ base: 12, md: 1 }}>
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']} w={{ base: "100%", md: "100%" }}>
|
<Button onClick={() => router.push(`/admin/desa/profile/profile-desa/${lambang.id}/lambang_desa`)} bg={colors['blue-button']}>
|
||||||
<Text fz={{ base: "md", md: "h3" }} ta={"justify"}>
|
<IconEdit size={20} />
|
||||||
Test
|
</Button>
|
||||||
</Text>
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
<Box pb={30}>
|
||||||
|
<Center>
|
||||||
|
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||||
|
</Center>
|
||||||
|
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Lambang Desa</Text>
|
||||||
|
</Box>
|
||||||
|
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
||||||
|
<Text fz={{ base: "md", md: "h3" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: lambang.deskripsi }} />
|
||||||
|
</Paper>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Paper>
|
</Stack>
|
||||||
</Stack>
|
</Box>
|
||||||
</Box>
|
)}
|
||||||
|
|
||||||
{/* Maskot Desa */}
|
{/* Maskot Desa */}
|
||||||
<Box>
|
{maskot && (
|
||||||
<Stack gap={'lg'}>
|
<Box>
|
||||||
<Paper p={"xl"} bg={colors['BG-trans']}>
|
<Stack gap={'lg'}>
|
||||||
<Box pb={30}>
|
<Paper p={"md"} bg={colors['BG-trans']}>
|
||||||
<Center>
|
<Grid>
|
||||||
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
<GridCol span={{ base: 12, md: 11 }}>
|
||||||
</Center>
|
<Title order={2}>Preview Maskot Desa</Title>
|
||||||
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Maskot Desa</Text>
|
</GridCol>
|
||||||
</Box>
|
<GridCol span={{ base: 12, md: 1 }}>
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']} w={{ base: "100%", md: "100%" }}>
|
<Button onClick={() => router.push(`/admin/desa/profile/profile-desa/${maskot.id}/maskot_desa`)} bg={colors['blue-button']}>
|
||||||
<Text fz={{ base: "md", md: "h3" }} ta={"justify"}>
|
<IconEdit size={20} />
|
||||||
Test
|
</Button>
|
||||||
</Text>
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
<Box pb={30}>
|
||||||
|
<Center>
|
||||||
|
<Image src={"/pudak-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||||
|
</Center>
|
||||||
|
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Maskot Desa</Text>
|
||||||
|
</Box>
|
||||||
|
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
||||||
|
<Text fz={{ base: "md", md: "h3" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: maskot.deskripsi }} />
|
||||||
|
<Group wrap="wrap" gap="md">
|
||||||
|
{maskot.images.map((img, index) => (
|
||||||
|
<Card key={index} p="xs" w={220}>
|
||||||
|
<Image
|
||||||
|
src={img.image.link}
|
||||||
|
alt={img.label}
|
||||||
|
w={200}
|
||||||
|
h={200}
|
||||||
|
fit="cover"
|
||||||
|
radius="md"
|
||||||
|
style={{ border: '1px solid #ccc', objectFit: 'cover' }}
|
||||||
|
/>
|
||||||
|
<Text ta="center" mt="xs" fw="bold">{img.label}</Text>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</Group>
|
||||||
|
</Paper>
|
||||||
</Paper>
|
</Paper>
|
||||||
<SimpleGrid
|
</Stack>
|
||||||
cols={{
|
</Box>
|
||||||
base: 1,
|
)}
|
||||||
md: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Center>
|
|
||||||
<Box>
|
|
||||||
<Paper p={"lg"}>
|
|
||||||
<Image src={"/api/img/pohonpudak.png"} alt="" w={{ base: 150, md: 250 }} />
|
|
||||||
<Text ta={"center"} fw={"bold"} c={colors["blue-button"]} fz={{ base: "md", md: "h3" }}>Pohon Pudak</Text>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</Center>
|
|
||||||
<Center>
|
|
||||||
<Box>
|
|
||||||
<Paper p={"lg"}>
|
|
||||||
<Image src={"/api/img/bungapudak.png"} alt="" w={{ base: 150, md: 250 }} />
|
|
||||||
<Text ta={"center"} fw={"bold"} c={colors["blue-button"]} fz={{ base: "md", md: "h3" }}>Bunga Pudak</Text>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
</Center>
|
|
||||||
</SimpleGrid>
|
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']} w={{ base: "100%", md: "100%" }}>
|
|
||||||
<Text fz={{ base: "md", md: "h3" }} ta={"justify"}>
|
|
||||||
Test
|
|
||||||
</Text>
|
|
||||||
</Paper>
|
|
||||||
</Paper>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
'use client'
|
||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
||||||
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import ApiFetch from '@/lib/api-fetch';
|
||||||
|
import { Box, Button, Center, FileInput, Group, Image, Paper, Stack, Text, Title } from '@mantine/core';
|
||||||
|
import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react';
|
||||||
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
|
function ProfilePerbekel() {
|
||||||
|
const perbekelState = useProxy(stateProfileDesa.profilPerbekel)
|
||||||
|
const router = useRouter()
|
||||||
|
const params = useParams()
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
||||||
|
const [file, setFile] = useState<File | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const id = params?.id as string;
|
||||||
|
if (!id) {
|
||||||
|
toast.error("ID tidak valid");
|
||||||
|
router.push("/admin/desa/profile/profile-perbekel");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await perbekelState.findUnique.load(id);
|
||||||
|
if (data) {
|
||||||
|
perbekelState.edit.initialize(data);
|
||||||
|
}
|
||||||
|
if (data?.image?.link) {
|
||||||
|
setPreviewImage(data.image.link);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
perbekelState.edit.reset();
|
||||||
|
perbekelState.findUnique.reset(); // opsional: reset juga data lama
|
||||||
|
};
|
||||||
|
}, [params?.id, router]);
|
||||||
|
|
||||||
|
const handleFileChange = (newFile: File | null) => {
|
||||||
|
if (!newFile) {
|
||||||
|
setFile(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFile(newFile);
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
setPreviewImage(event.target?.result as string);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(newFile);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (isSubmitting || !perbekelState.edit.form.biodata.trim()) {
|
||||||
|
toast.error("Biodata wajib diisi");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsSubmitting(true)
|
||||||
|
try {
|
||||||
|
if (file) {
|
||||||
|
const uploadResponse = await ApiFetch.api.fileStorage.create.post({ file, name: file.name });
|
||||||
|
const uploaded = uploadResponse.data?.data;
|
||||||
|
|
||||||
|
if (!uploaded?.id) {
|
||||||
|
toast.error("Gagal upload gambar");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
perbekelState.edit.form.imageId = uploaded.id;
|
||||||
|
}
|
||||||
|
const success = await perbekelState.edit.submit()
|
||||||
|
if (success) {
|
||||||
|
toast.success("Data berhasil disimpan");
|
||||||
|
router.push("/admin/desa/profile/profile-perbekel");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error update sejarah desa:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat update sejarah desa");
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
perbekelState.findUnique.loading ||
|
||||||
|
!perbekelState.findUnique.data ||
|
||||||
|
perbekelState.edit.loading
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Center h={400}>
|
||||||
|
<Text>Memuat data...</Text>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box py={10}>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Group>
|
||||||
|
<Button variant="subtle" onClick={handleBack}>
|
||||||
|
<IconArrowBack color={colors['blue-button']} size={20} />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
<Paper bg={colors['white-1']} p={'xs'} w={{ base: '100%', md: '50%' }}>
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Box>
|
||||||
|
<Box>
|
||||||
|
<Stack>
|
||||||
|
<Title order={3}>Edit Profil Perbekel</Title>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Biodata</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={perbekelState.edit.form.biodata}
|
||||||
|
onChange={(val) => perbekelState.edit.form.biodata = val}
|
||||||
|
/>
|
||||||
|
{/* File Upload */}
|
||||||
|
<FileInput
|
||||||
|
label={<Text fz="sm" fw="bold">Upload Gambar Baru (Opsional)</Text>}
|
||||||
|
value={file}
|
||||||
|
onChange={handleFileChange}
|
||||||
|
accept="image/*"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Preview Gambar */}
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw="bold" mb="xs">Preview Gambar</Text>
|
||||||
|
{previewImage ? (
|
||||||
|
<Image alt="Profile preview" src={previewImage} w={200} h={200} fit="cover" radius="md" />
|
||||||
|
) : (
|
||||||
|
<Center w={200} h={200} bg="gray.2">
|
||||||
|
<Stack align="center" gap="xs">
|
||||||
|
<IconImageInPicture size={48} color="gray" />
|
||||||
|
<Text size="sm" c="gray">Tidak ada gambar</Text>
|
||||||
|
</Stack>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Pengalaman</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={perbekelState.edit.form.pengalaman}
|
||||||
|
onChange={(val) => perbekelState.edit.form.pengalaman = val}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Pengalaman Organisasi</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={perbekelState.edit.form.pengalamanOrganisasi}
|
||||||
|
onChange={(val) => perbekelState.edit.form.pengalamanOrganisasi = val}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"md"} fw={"bold"}>Program Unggulan</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={perbekelState.edit.form.programUnggulan}
|
||||||
|
onChange={(val) => perbekelState.edit.form.programUnggulan = val}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Group>
|
||||||
|
<Button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
bg={colors['blue-button']}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProfilePerbekel;
|
||||||
@@ -1,10 +1,110 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Paper, Text } from '@mantine/core';
|
import { Box, Button, Center, Divider, Grid, GridCol, Image, Paper, Stack, Text, Title } from '@mantine/core';
|
||||||
|
import { IconEdit } from '@tabler/icons-react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useSnapshot } from 'valtio';
|
||||||
|
import stateProfileDesa from '../../../_state/desa/profile';
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const router = useRouter();
|
||||||
|
const snap = useSnapshot(stateProfileDesa);
|
||||||
|
|
||||||
|
// Panggil load data sekali saat komponen mount
|
||||||
|
useEffect(() => {
|
||||||
|
stateProfileDesa.profilPerbekel.findUnique.load("edit");
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const perbekel = snap.profilPerbekel.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
<Text>Test</Text>
|
<Stack gap={"xs"}>
|
||||||
|
<Grid>
|
||||||
|
<GridCol span={{ base: 12, md: 11 }}>
|
||||||
|
<Title order={3}>Preview Profile PPID</Title>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 1 }}>
|
||||||
|
<Button bg={colors['blue-button']} onClick={() => router.push(`/admin/desa/profile/profile-perbekel/${snap.profilPerbekel.findUnique.data?.id}`)}>
|
||||||
|
<IconEdit size={16} />
|
||||||
|
</Button>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
{perbekel && (
|
||||||
|
<Box >
|
||||||
|
<Paper p={"xl"} bg={colors['BG-trans']}>
|
||||||
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
|
<Grid>
|
||||||
|
<GridCol span={{ base: 12, md: 12 }}>
|
||||||
|
<Center>
|
||||||
|
<Image src={"/darmasaba-icon.png"} w={{ base: 100, md: 150 }} alt='' />
|
||||||
|
</Center>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ base: 12, md: 12 }}>
|
||||||
|
<Text ta={"center"} fz={{ base: "1.2rem", md: "1.8rem" }} fw={'bold'}>PROFIL PIMPINAN BADAN PUBLIK DESA DARMASABA </Text>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
<Divider my={"md"} color={colors['blue-button']} />
|
||||||
|
{/* biodata perbekel */}
|
||||||
|
<Box px={{ base: 0, md: 50 }} pb={30}>
|
||||||
|
<Box pb={20} px={{ base: 0, md: 50 }}>
|
||||||
|
<Paper bg={colors['BG-trans']} w={{ base: "100%", md: "100%" }}>
|
||||||
|
<Stack gap={0}>
|
||||||
|
<Center>
|
||||||
|
<Image
|
||||||
|
pt={{ base: 0, md: 90 }}
|
||||||
|
src={perbekel.image?.link || "/perbekel.png"}
|
||||||
|
w={{ base: 250, md: 350 }}
|
||||||
|
alt='Foto Profil PPID'
|
||||||
|
onError={(e) => {
|
||||||
|
e.currentTarget.src = "/perbekel.png";
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
<Paper
|
||||||
|
bg={colors['blue-button']}
|
||||||
|
py={20}
|
||||||
|
className="glass3"
|
||||||
|
px={{ base: 10, md: 10 }}
|
||||||
|
|
||||||
|
>
|
||||||
|
<Text ta={"center"} c={colors['white-1']} fw={"bolder"} fz={{ base: "1.2rem", md: "1.6rem" }}>
|
||||||
|
I.B. Surya Prabhawa Manuaba, S.H.,M.H.,NL.P.
|
||||||
|
</Text>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
<Box pt={10}>
|
||||||
|
<Box>
|
||||||
|
<Text fz={{ base: "1.125rem", md: "1.6rem" }} fw={'bold'}>Biodata</Text>
|
||||||
|
<Text fz={{ base: "1rem", md: "1.5rem" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: perbekel.biodata }} />
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={{ base: "1.125rem", md: "1.6rem" }} fw={'bold'}>Pengalaman</Text>
|
||||||
|
<Text fz={{ base: "1rem", md: "1.5rem" }} dangerouslySetInnerHTML={{ __html: perbekel.pengalaman }} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box pb={30}>
|
||||||
|
<Text fz={{ base: "1.125rem", md: "1.6rem" }} fw={'bold'}>Pengalaman Organisasi</Text>
|
||||||
|
<Box px={20}>
|
||||||
|
<Text fz={{ base: "1rem", md: "1.5rem" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: perbekel.pengalamanOrganisasi }} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box pb={20}>
|
||||||
|
<Text fz={{ base: "1.125rem", md: "1.6rem" }} fw={'bold'}>Program Kerja Unggulan</Text>
|
||||||
|
<Box px={20}>
|
||||||
|
<Text fz={{ base: "1rem", md: "1.5rem" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: perbekel.programUnggulan }} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function Page() {
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const allList = useProxy(stateProfilePPID)
|
const allList = useProxy(stateProfilePPID)
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
allList.profile.load("1") // Assuming "1" is your default ID, adjust as needed
|
allList.profile.load("edit") // Assuming "1" is your default ID, adjust as needed
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (!allList.profile.data) {
|
if (!allList.profile.data) {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ function VisiMisiPPIDList() {
|
|||||||
<Paper p={"xl"} bg={colors['BG-trans']}>
|
<Paper p={"xl"} bg={colors['BG-trans']}>
|
||||||
<Box pb={30}>
|
<Box pb={30}>
|
||||||
<Center>
|
<Center>
|
||||||
<Image src={"/api/img/darmasaba-icon.png"} w={{ base: 100, md: 150 }} alt='' />
|
<Image src={"/darmasaba-icon.png"} w={{ base: 100, md: 150 }} alt='' />
|
||||||
</Center>
|
</Center>
|
||||||
<Text ta={"center"} fz={{ base: "h2", md: "2.5rem" }} fw={"bold"}>
|
<Text ta={"center"} fz={{ base: "h2", md: "2.5rem" }} fw={"bold"}>
|
||||||
MOTO PPID DESA DARMASABA
|
MOTO PPID DESA DARMASABA
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import VisiMisiDesa from "./visi-misi";
|
|||||||
import LambangDesa from "./lambang-desa";
|
import LambangDesa from "./lambang-desa";
|
||||||
import MaskotDesa from "./maskot-desa";
|
import MaskotDesa from "./maskot-desa";
|
||||||
import Elysia from "elysia";
|
import Elysia from "elysia";
|
||||||
|
import ProfilPerbekel from "../profilePerbekel";
|
||||||
|
|
||||||
const ProfileDesa = new Elysia({
|
const ProfileDesa = new Elysia({
|
||||||
prefix: "/profile",
|
prefix: "/profile",
|
||||||
@@ -11,6 +12,7 @@ const ProfileDesa = new Elysia({
|
|||||||
.use(SejarahDesa)
|
.use(SejarahDesa)
|
||||||
.use(VisiMisiDesa)
|
.use(VisiMisiDesa)
|
||||||
.use(LambangDesa)
|
.use(LambangDesa)
|
||||||
.use(MaskotDesa);
|
.use(MaskotDesa)
|
||||||
|
.use(ProfilPerbekel);
|
||||||
|
|
||||||
export default ProfileDesa;
|
export default ProfileDesa;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import maskotDesaFindById from "./find-by-id";
|
|||||||
import Elysia, { t } from "elysia";
|
import Elysia, { t } from "elysia";
|
||||||
|
|
||||||
const MaskotDesa = new Elysia({
|
const MaskotDesa = new Elysia({
|
||||||
prefix: "/maskot",
|
prefix: "/maskot",
|
||||||
tags: ["Desa/Profile"],
|
tags: ["Desa/Profile"],
|
||||||
})
|
})
|
||||||
.get("/:id", async (context) => {
|
.get("/:id", async (context) => {
|
||||||
const response = await maskotDesaFindById(new Request(context.request));
|
const response = await maskotDesaFindById(new Request(context.request));
|
||||||
return response;
|
return response;
|
||||||
})
|
})
|
||||||
@@ -18,7 +18,8 @@ const MaskotDesa = new Elysia({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
maskot: t.String(),
|
judul: t.String(),
|
||||||
|
deskripsi: t.String(),
|
||||||
images: t.Array(
|
images: t.Array(
|
||||||
t.Object({
|
t.Object({
|
||||||
imageId: t.String(),
|
imageId: t.String(),
|
||||||
@@ -27,5 +28,5 @@ const MaskotDesa = new Elysia({
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
export default MaskotDesa;
|
export default MaskotDesa;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import '@mantine/charts/styles.css';
|
|||||||
import '@mantine/dates/styles.css';
|
import '@mantine/dates/styles.css';
|
||||||
import '@mantine/tiptap/styles.css';
|
import '@mantine/tiptap/styles.css';
|
||||||
|
|
||||||
|
|
||||||
import LoadDataFirstClient from "@/app/darmasaba/_com/LoadDataFirstClient";
|
import LoadDataFirstClient from "@/app/darmasaba/_com/LoadDataFirstClient";
|
||||||
import {
|
import {
|
||||||
ColorSchemeScript,
|
ColorSchemeScript,
|
||||||
|
|||||||
Reference in New Issue
Block a user