From 342e9bbc651fcabc9d32da5b35b0116f0bbef211 Mon Sep 17 00:00:00 2001 From: nico Date: Tue, 16 Dec 2025 10:19:15 +0800 Subject: [PATCH 1/2] Fix QC Kak Ayu Tgl 12 Fix QC Kak Ino Tgl 12 Fix UI Mobile Menu Keamanan Fix UI Mobile Admin Menu Landing Page --- postcss.config.cjs | 23 +- .../keamanan/polsek-terdekat/create/page.tsx | 67 ++- .../(dashboard)/landing-page/SDGs/page.tsx | 203 +++++---- .../desa-anti-korupsi/_lib/layouTabs.tsx | 100 +++-- .../kategori-desa-anti-korupsi/[id]/page.tsx | 2 +- .../create/page.tsx | 2 +- .../kategori-desa-anti-korupsi/page.tsx | 290 ++++++++----- .../list-desa-anti-korupsi/[id]/edit/page.tsx | 2 +- .../list-desa-anti-korupsi/[id]/page.tsx | 4 +- .../list-desa-anti-korupsi/create/page.tsx | 2 +- .../list-desa-anti-korupsi/page.tsx | 109 +++-- .../_lib/layoutTab.tsx | 65 +-- .../responden/[id]/edit/page.tsx | 2 +- .../responden/[id]/page.tsx | 4 +- .../responden/page.tsx | 123 ++++-- .../landing-page/profil/_lib/layoutTabs.tsx | 99 +++-- .../profil/media-sosial/[id]/edit/page.tsx | 2 +- .../profil/media-sosial/[id]/page.tsx | 4 +- .../profil/media-sosial/create/page.tsx | 28 +- .../landing-page/profil/media-sosial/page.tsx | 278 ++++++++---- .../profil/pejabat-desa/[id]/page.tsx | 2 +- .../landing-page/profil/pejabat-desa/page.tsx | 23 +- .../profil/program-inovasi/[id]/edit/page.tsx | 2 +- .../profil/program-inovasi/[id]/page.tsx | 60 +-- .../profil/program-inovasi/create/page.tsx | 2 +- .../profil/program-inovasi/page.tsx | 190 ++++++--- src/app/admin/layout.tsx | 396 ------------------ .../ekonomi/sektor-unggulan-desa/page.tsx | 44 +- .../desa-digital-smart-village/page.tsx | 2 +- .../[id]/page.tsx | 103 ++--- .../page.tsx | 36 +- .../(pages)/keamanan/kontak-darurat/page.tsx | 49 ++- .../keamanan/pencegahan-kriminalitas/page.tsx | 52 ++- .../(pages)/keamanan/polsek-terdekat/page.tsx | 46 +- .../polsek-terdekat/semua-polsek/page.tsx | 109 +++-- .../component/edukasiCard.tsx | 59 +-- .../lingkungan/edukasi-lingkungan/page.tsx | 14 +- .../gotong-royong/[kategori]/[id]/page.tsx | 26 +- .../lingkungan/gotong-royong/layout.tsx | 20 + .../lingkungan/gotong-royong/semua/page.tsx | 32 +- .../lingkungan/konservasi-adat-bali/page.tsx | 132 +++--- .../pelajari-lebih-lanjut/page.tsx | 212 +++++++--- .../bimbingan-belajar-desa/page.tsx | 39 +- 43 files changed, 1715 insertions(+), 1344 deletions(-) diff --git a/postcss.config.cjs b/postcss.config.cjs index 069b0528..9e9652a2 100644 --- a/postcss.config.cjs +++ b/postcss.config.cjs @@ -1,14 +1,15 @@ module.exports = { - plugins: { - 'postcss-preset-mantine': {}, - 'postcss-simple-vars': { - variables: { - 'mantine-breakpoint-xs': '36em', - 'mantine-breakpoint-sm': '48em', - 'mantine-breakpoint-md': '62em', - 'mantine-breakpoint-lg': '75em', - 'mantine-breakpoint-xl': '88em', - }, + plugins: { + 'postcss-preset-mantine': {}, + 'postcss-simple-vars': { + variables: { + /* Mobile first */ + 'mantine-breakpoint-xs': '30em', // 480px → mobile kecil–normal + 'mantine-breakpoint-sm': '48em', // 768px → tablet / mobile landscape + 'mantine-breakpoint-md': '64em', // 1024px → laptop & desktop kecil + 'mantine-breakpoint-lg': '80em', // 1280px → desktop standar + 'mantine-breakpoint-xl': '90em', // 1440px+ → desktop besar }, }, - }; \ No newline at end of file + }, +}; diff --git a/src/app/admin/(dashboard)/keamanan/polsek-terdekat/create/page.tsx b/src/app/admin/(dashboard)/keamanan/polsek-terdekat/create/page.tsx index 49dc48b6..20b855f7 100644 --- a/src/app/admin/(dashboard)/keamanan/polsek-terdekat/create/page.tsx +++ b/src/app/admin/(dashboard)/keamanan/polsek-terdekat/create/page.tsx @@ -44,18 +44,56 @@ function CreatePolsekTerdekat() { }; }; + const isValidGoogleMapsEmbed = (url: string): boolean => { + try { + const u = new URL(url); + return ( + u.hostname === 'www.google.com' && + u.pathname === '/maps/embed' && + u.searchParams.has('pb') + ); + } catch { + return false; + } +}; + const handleSubmit = async () => { - try { - setIsSubmitting(true); - await polsekState.create.create(); - resetForm(); - router.push("/admin/keamanan/polsek-terdekat"); - } catch (error) { - console.error(error) - toast.error("Gagal menambah polsek terdekat"); - } finally { - setIsSubmitting(false); + const { embedMapUrl } = polsekState.create.form; + + // ✅ Validasi Google Maps Embed URL (jika diisi) + if (embedMapUrl && !isValidGoogleMapsEmbed(embedMapUrl)) { + toast.error("URL embed peta tidak valid. Harap paste iframe dari Google Maps."); + return; + } + + try { + setIsSubmitting(true); + await polsekState.create.create(); + resetForm(); + router.push("/admin/keamanan/polsek-terdekat"); + } catch (error) { + console.error(error); + toast.error("Gagal menambah polsek terdekat"); + } finally { + setIsSubmitting(false); + } +}; + + const extractEmbedUrl = (input: string): string => { + // Jika sudah berupa URL embed yang valid + if (input.startsWith('https://www.google.com/maps/embed?')) { + return input.trim(); } + + // Coba parse sebagai HTML string (iframe) + const iframeRegex = /]*src=["']([^"']*)["'][^>]*>/i; + const match = input.match(iframeRegex); + if (match && match[1]?.startsWith('https://www.google.com/maps/embed?')) { + return match[1].trim(); + } + + // Jika tidak cocok, kembalikan input asli (atau string kosong) + return input.trim(); }; const fetchLayanan = async () => { @@ -190,9 +228,14 @@ function CreatePolsekTerdekat() { /> (polsekState.create.form.embedMapUrl = val.target.value)} + onChange={(e) => { + const rawValue = e.currentTarget.value; + const cleanUrl = extractEmbedUrl(rawValue); + polsekState.create.form.embedMapUrl = cleanUrl; + }} + description="Contoh: https://www.google.com/maps/embed?pb=..." label={Embed Map URL} - placeholder="Masukkan embed map url" + placeholder="Paste iframe dari Google Maps atau URL embed langsung" /> { - load(page, 10, search) - }, [page, search]) + load(page, 10, search); + }, [page, search]); - const filteredData = data || [] + const filteredData = data || []; // Handle loading state if (loading || !data) { @@ -53,79 +52,71 @@ function ListSdgsDesa({ search }: { search: string }) { ); } - if (data.length === 0) { - return ( - - - - Daftar Sdgs Desa - - - - - - - Nama Sdgs Desa - Jumlah - Aksi - - - - - - Tidak ada data Sdgs Desa - - - -
-
-
-
- ); - } + const isEmpty = data.length === 0; return ( - - - - Daftar Sdgs Desa - + + + + + Daftar Sdgs Desa + + - - + + {/* Desktop Table */} + +
- Nama Sdgs Desa - Jumlah - Aksi + + + Nama Sdgs Desa + + + + + Jumlah + + + + + Aksi + + - {filteredData.map((item) => ( - - - - {item.name} + {isEmpty ? ( + + + + Tidak ada data Sdgs Desa - - - {item.jumlah || '0'} - - - - - - - ))} + + + )) + )}
+ + {/* Mobile Cards */} + + {isEmpty ? ( +
+ + Tidak ada data Sdgs Desa + +
+ ) : ( + + {filteredData.map((item) => ( + + + + {item.name} + + + Jumlah: {item.jumlah || '0'} + + + + + + + ))} + + )} +
-
- { - load(newPage, 10); - window.scrollTo(0, 0); - }} - total={Math.max(1, totalPages)} - withEdges - radius="md" - /> -
+ + {!isEmpty && ( +
+ { + load(newPage, 10); + window.scrollTo(0, 0); + }} + total={Math.max(1, totalPages)} + withEdges + radius="md" + /> +
+ )}
- ) + ); } -export default SdgsDesa; +export default SdgsDesa; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/landing-page/desa-anti-korupsi/_lib/layouTabs.tsx b/src/app/admin/(dashboard)/landing-page/desa-anti-korupsi/_lib/layouTabs.tsx index 401f85a3..d327fb3b 100644 --- a/src/app/admin/(dashboard)/landing-page/desa-anti-korupsi/_lib/layouTabs.tsx +++ b/src/app/admin/(dashboard)/landing-page/desa-anti-korupsi/_lib/layouTabs.tsx @@ -3,6 +3,7 @@ import colors from "@/con/colors"; import { + Box, ScrollArea, Stack, Tabs, @@ -68,37 +69,76 @@ function LayoutTabs({ children }: { children: React.ReactNode }) { keepMounted={false} > {/* ✅ Scroll horizontal wrapper */} - - - {tabs.map((tab, i) => ( - - {tab.label} - - ))} - - + + + + {tabs.map((tab, i) => ( + + {tab.label} + + ))} + + + + + + + + {tabs.map((tab, i) => ( + + {tab.label} + + ))} + + + {tabs.map((tab, i) => ( + - - - - - - Nama Kategori - Edit - Hapus + // Mobile cards + const renderMobileCards = () => ( + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( + + + + + {item.name} + + + + + + + + + )) + ) : ( + + + Tidak ada data kategori yang ditemukan + + + )} + + ); + + // Desktop table + const renderDesktopTable = () => ( + +
+ + + + + Nama Kategori + + + + + Edit + + + + + Hapus + + + + + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( + + + + {item.name} + + + + + + + + - - - {filteredData.length > 0 ? ( - filteredData.map((item) => ( - - - - {item.name} - - - - - - - - - - )) - ) : ( - - -
- Tidak ada data kategori yang ditemukan -
-
-
- )} -
-
-
+ )) + ) : ( + + + + Tidak ada data kategori yang ditemukan + + + + )} + + +
+ ); + + return ( + + + + + Daftar Kategori Kegiatan + + + + + {renderDesktopTable()} + {renderMobileCards()} -
- { - load(newPage, 10); - window.scrollTo({ top: 0, behavior: 'smooth' }); - }} - total={totalPages} - mt="md" - mb="md" - color="blue" - radius="md" - /> -
- {/* Modal Konfirmasi Hapus */} + + {totalPages > 1 && ( +
+ { + load(newPage, 10); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + color="blue" + radius="md" + /> +
+ )} + setModalHapus(false)} @@ -158,4 +236,4 @@ function ListKategoriKegiatan({ search }: { search: string }) { ); } -export default KategoriDesaAntiKorupsi +export default KategoriDesaAntiKorupsi; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/landing-page/desa-anti-korupsi/list-desa-anti-korupsi/[id]/edit/page.tsx b/src/app/admin/(dashboard)/landing-page/desa-anti-korupsi/list-desa-anti-korupsi/[id]/edit/page.tsx index eaf0c853..423a1f99 100644 --- a/src/app/admin/(dashboard)/landing-page/desa-anti-korupsi/list-desa-anti-korupsi/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/desa-anti-korupsi/list-desa-anti-korupsi/[id]/edit/page.tsx @@ -150,7 +150,7 @@ export default function EditDesaAntiKorupsi() { }; return ( - + + + + + + + Daftar Program Desa Anti Korupsi + + - + + {/* Desktop Table */} + - Nama Program - Kategori - Aksi + Nama Program + Kategori + + Aksi + {filteredData.length > 0 ? ( filteredData.map((item) => ( - - + + {item.name || '-'} - - - + + {item.kategori?.name || '-'} - - +
+ + {/* Mobile Cards */} + + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( + + + + {item.name || '-'} + + + Kategori: {item.kategori?.name || '-'} + + + + + + + )) + ) : ( + + + Tidak ditemukan data dengan kata kunci pencarian + + + )} + +
@@ -144,7 +196,6 @@ function ListDesaAntiKorupsi({ search }: { search: string }) { }} size="md" radius="md" - mt="md" />
@@ -152,4 +203,4 @@ function ListDesaAntiKorupsi({ search }: { search: string }) { ); } -export default DesaAntiKorupsi; +export default DesaAntiKorupsi; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/_lib/layoutTab.tsx b/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/_lib/layoutTab.tsx index 4b910589..cb633834 100644 --- a/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/_lib/layoutTab.tsx +++ b/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/_lib/layoutTab.tsx @@ -1,7 +1,7 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core'; +import { Box, ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core'; import { IconChartBar, IconUsers } from '@tabler/icons-react'; import { usePathname, useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; @@ -53,36 +53,41 @@ function LayoutTabsKepuasan({ children }: { children: React.ReactNode }) { radius="lg" keepMounted={false} > + {/* ✅ Scroll horizontal wrapper */} - - - {tabs.map((e, i) => ( - - {e.label} - - ))} - - + + + + {tabs.map((tab, i) => ( + + {tab.label} + + ))} + + + + {tabs.map((e, i) => ( <> diff --git a/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/responden/[id]/edit/page.tsx b/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/responden/[id]/edit/page.tsx index 6e123982..3cd5d1b0 100644 --- a/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/responden/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/responden/[id]/edit/page.tsx @@ -149,7 +149,7 @@ function EditResponden() { ); return ( - + + +
+ )) + )} + +
+
@@ -175,4 +228,4 @@ function ListResponden({ search }: ListRespondenProps) { ); } -export default Responden; +export default Responden; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/landing-page/profil/_lib/layoutTabs.tsx b/src/app/admin/(dashboard)/landing-page/profil/_lib/layoutTabs.tsx index 6d889a1f..7210d917 100644 --- a/src/app/admin/(dashboard)/landing-page/profil/_lib/layoutTabs.tsx +++ b/src/app/admin/(dashboard)/landing-page/profil/_lib/layoutTabs.tsx @@ -2,6 +2,7 @@ 'use client' import colors from '@/con/colors'; import { + Box, ScrollArea, Stack, Tabs, @@ -74,36 +75,76 @@ function LayoutTabs({ children }: { children: React.ReactNode }) { keepMounted={false} > {/* ✅ Scroll horizontal wrapper */} - - + + + {tabs.map((tab, i) => ( + + {tab.label} + + ))} + + +
+ + + - {tabs.map((tab, i) => ( - - {tab.label} - - ))} - - + + + {tabs.map((tab, i) => ( + + {tab.label} + + ))} + + + {tabs.map((tab, i) => ( + - + <Title order={2} ml="sm" c="dark" lh={1.2} fz={{ base: 'md', md: 'lg' }}> Tambah Media Sosial @@ -155,7 +153,7 @@ export default function CreateMediaSosial() { {/* Custom icon uploader */} {selectedSosmed === 'custom' && ( - + Upload Custom Icon @@ -185,8 +183,10 @@ export default function CreateMediaSosial() { - Seret gambar atau klik untuk pilih - + + Seret gambar atau klik untuk pilih + + Maksimal 5MB, format .png, .jpg, .jpeg, webp @@ -229,7 +229,11 @@ export default function CreateMediaSosial() { {/* Input name */} + Nama Media Sosial + + } placeholder="Masukkan nama media sosial" value={stateMediaSosial.create.form.name ?? ''} onChange={(e) => (stateMediaSosial.create.form.name = e.target.value)} @@ -238,7 +242,11 @@ export default function CreateMediaSosial() { {/* Input link */} + Link / Kontak + + } placeholder="Masukkan link atau nomor" value={stateMediaSosial.create.form.iconUrl ?? ''} onChange={(e) => (stateMediaSosial.create.form.iconUrl = e.target.value)} @@ -266,4 +274,4 @@ export default function CreateMediaSosial() {
); -} +} \ No newline at end of file diff --git a/src/app/admin/(dashboard)/landing-page/profil/media-sosial/page.tsx b/src/app/admin/(dashboard)/landing-page/profil/media-sosial/page.tsx index 540037c5..ffc1c669 100644 --- a/src/app/admin/(dashboard)/landing-page/profil/media-sosial/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/profil/media-sosial/page.tsx @@ -1,7 +1,25 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Center, Group, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; +import { + Box, + Button, + Center, + Group, + Image, + Pagination, + Paper, + Skeleton, + Stack, + Table, + TableTbody, + TableTd, + TableTh, + TableThead, + TableTr, + Text, + Title, +} from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; @@ -28,11 +46,11 @@ function MediaSosial() { } function ListMediaSosial({ search }: { search: string }) { - const stateMediaSosial = useProxy(profileLandingPageState.mediaSosial) + const stateMediaSosial = useProxy(profileLandingPageState.mediaSosial); const router = useRouter(); const getIconSource = (item: any) => { - if (item.image?.link) return item.image.link; + if (item.image?.link) return item.image.link; if (item.icon && sosmedMap[item.icon as keyof typeof sosmedMap]?.src) { return sosmedMap[item.icon as keyof typeof sosmedMap].src; } @@ -48,101 +66,201 @@ function ListMediaSosial({ search }: { search: string }) { } = stateMediaSosial.findMany; useShallowEffect(() => { - load(page, 10, search) - }, [page, search]) + load(page, 10, search); + }, [page, search]); - const filteredData = data || [] + const filteredData = data || []; if (loading || !data) { return ( - + ); } return ( - - - - Daftar Media Sosial - - - - - - Nama Media Sosial / Kontak - Gambar - Link / No. Telepon - Aksi - - - - {filteredData.length > 0 ? ( - filteredData.map((item) => ( - - - {item.name} - - - - {(() => { - const src = getIconSource(item); - - if (src) { - return ( - - ); - } - - return ; - })()} - - - - - - - {item.iconUrl || item.noTelp || '-'} + + {/* Desktop: Table | Mobile: Card-based vertical layout */} + +
+ + + + + Nama Media Sosial / Kontak + + + + + Gambar + + + + + Link / No. Telepon + + + + + Aksi + + + + + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( + + + + {item.name} - - - - + + + + {(() => { + const src = getIconSource(item); + if (src) { + return ( + + ); + } + return ; + })()} + + + + + + {item.iconUrl || item.noTelp || '-'} + + + + + + + + )) + ) : ( + + +
+ + Tidak ada data media sosial yang cocok + +
- )) - ) : ( - - -
- Tidak ada data media sosial yang cocok -
-
-
- )} -
-
+ )} + + +
+ + {/* Mobile layout */} + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( + + + + + {item.name} + + + + {(() => { + const src = getIconSource(item); + if (src) { + return ( + {item.name} + ); + } + return ; + })()} + + + + + + {item.iconUrl || item.noTelp || '-'} + + + + + + + + )) + ) : ( +
+ + Tidak ada data media sosial yang cocok + +
+ )} +
+
+ + {dataArray.map((item) => ( @@ -52,7 +51,7 @@ function Page() {
- Logo Desa + Logo Desa
@@ -93,7 +92,7 @@ function Page() { Jabatan - + {item.position} diff --git a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/edit/page.tsx b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/edit/page.tsx index 9d41f051..c988b087 100644 --- a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/edit/page.tsx @@ -130,7 +130,7 @@ function EditProgramInovasi() { }; return ( - + + + + + Gambar {data.image?.link ? ( - Gambar Program - + - +
diff --git a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/create/page.tsx b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/create/page.tsx index f13ab8ef..eac0393f 100644 --- a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/create/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/create/page.tsx @@ -76,7 +76,7 @@ function CreateProgramInovasi() { }; return ( - + + color="blue" + leftSection={} + variant="light" + radius="md" + onClick={() => router.push('/admin/landing-page/profil/program-inovasi/create')} + > + Tambah Program + - - - - - Nama Program - Deskripsi - Link - Aksi - - - - {filteredData.length === 0 ? ( + + +
+ - -
- Belum ada data program inovasi -
-
+ Nama Program + Deskripsi + Link + Aksi
- ) : ( - filteredData.map((item) => ( - - - {item.name} - - - - - - - - {item.link} - - - - - +
+ + {filteredData.length === 0 ? ( + + +
+ Belum ada data program inovasi +
- )) - )} -
-
+ ) : ( + filteredData.map((item) => ( + + + {item.name} + + + + + + + + {item.link} + + + + + + + + )) + )} + + +
+ + + {filteredData.map((item) => ( + + + {/* Title */} + {item.name} + + {/* Description */} + + {item.description || '-'} + + + {/* Link */} + + + + {item.link} + + + + + {/* Action */} + + + + + + ))} + + + {filteredData.length > 0 && (
_.lowerCase(s)); - -// // const { user } = useSnapshot(authStore); - -// // console.log("Current user in store:", user); - -// // ✅ FIX: Selalu fetch user data setiap kali komponen mount -// useEffect(() => { -// const fetchUser = async () => { -// try { -// const res = await fetch('/api/auth/me'); -// const data = await res.json(); - -// if (data.user) { -// // ✅ Check if user is NOT active → redirect to waiting room -// if (!data.user.isActive) { -// authStore.setUser(null); -// router.replace('/waiting-room'); -// return; -// } - -// // ✅ Fetch menuIds -// const menuRes = await fetch(`/api/admin/user-menu-access?userId=${data.user.id}`); -// const menuData = await menuRes.json(); - -// const menuIds = menuData.success && Array.isArray(menuData.menuIds) -// ? [...menuData.menuIds] -// : null; - -// // ✅ Set user dengan menuIds yang fresh -// authStore.setUser({ -// id: data.user.id, -// name: data.user.name, -// roleId: Number(data.user.roleId), -// menuIds, -// isActive: data.user.isActive -// }); - -// // ✅ TAMBAHKAN INI: Redirect ke dashboard sesuai roleId -// const currentPath = window.location.pathname; -// const expectedPath = getRedirectPath(Number(data.user.roleId)); - -// // Jika user di halaman /admin tapi bukan di path yang sesuai roleId -// if (currentPath === '/admin' || !currentPath.startsWith(expectedPath)) { -// router.replace(expectedPath); -// } - -// } else { -// authStore.setUser(null); -// router.replace('/login'); -// } -// } catch (error) { -// console.error('Gagal memuat data pengguna:', error); -// authStore.setUser(null); -// router.replace('/login'); -// } finally { -// setLoading(false); -// } -// }; - -// fetchUser(); -// }, [router]); - -// // ✅ Fungsi helper untuk get redirect path -// const getRedirectPath = (roleId: number): string => { -// switch (roleId) { -// case 0: // DEVELOPER -// case 1: // SUPERADMIN -// case 2: // ADMIN_DESA -// return '/admin/landing-page/profil/program-inovasi'; -// case 3: // ADMIN_KESEHATAN -// return '/admin/kesehatan/posyandu'; -// case 4: // ADMIN_PENDIDIKAN -// return '/admin/pendidikan/info-sekolah/jenjang-pendidikan'; -// default: -// return '/admin'; -// } -// }; - -// if (loading) { -// return ( -// -// -//
-// -//
-//
-//
-// ); -// } - -// // ✅ Ambil menu berdasarkan roleId dan menuIds -// const currentNav = authStore.user -// ? getNavbar({ roleId: authStore.user.roleId, menuIds: authStore.user.menuIds }) -// : []; - -// const handleLogout = async () => { -// try { -// setIsLoggingOut(true); - -// // ✅ Panggil API logout untuk clear session di server -// const response = await fetch('/api/auth/logout', { method: 'POST' }); -// const result = await response.json(); - -// if (result.success) { -// // Clear user data dari store -// authStore.setUser(null); - -// // Clear localStorage -// localStorage.removeItem('auth_nomor'); -// localStorage.removeItem('auth_kodeId'); - -// // Force reload untuk reset semua state -// window.location.href = '/login'; -// } else { -// console.error('Logout failed:', result.message); -// // Tetap redirect meskipun gagal -// authStore.setUser(null); -// window.location.href = '/login'; -// } -// } catch (error) { -// console.error('Error during logout:', error); -// // Tetap clear store dan redirect jika error -// authStore.setUser(null); -// window.location.href = '/login'; -// } finally { -// setIsLoggingOut(false); -// } -// }; - -// return ( -// -// -// -// -// Logo Darmasaba -// -// Admin Darmasaba -// -// - -// -// {!desktopOpened && ( -// -// -// -// -// -// )} - -// - -// -// { -// router.push("/darmasaba"); -// }} -// color={colors["blue-button"]} -// radius="xl" -// size="lg" -// variant="gradient" -// gradient={{ from: colors["blue-button"], to: "#228be6" }} -// > -// Logo Darmasaba -// -// -// -// -// -// -// -// -// -// - -// -// -// {currentNav.map((v, k) => { -// const isParentActive = segments.includes(_.lowerCase(v.name)); - -// return ( -// -// {v.name} -// -// } -// style={{ -// borderRadius: rem(10), -// marginBottom: rem(4), -// transition: "background 150ms ease", -// }} -// styles={{ -// root: { -// '&:hover': { -// backgroundColor: 'rgba(25, 113, 194, 0.05)', -// }, -// }, -// }} -// variant="light" -// active={isParentActive} -// > -// {v.children.map((child, key) => { -// const isChildActive = segments.includes( -// _.lowerCase(child.name) -// ); - -// return ( -// -// {child.name} -// -// } -// styles={{ -// root: { -// borderRadius: rem(8), -// marginBottom: rem(2), -// transition: 'background 150ms ease', -// padding: '6px 12px', -// '&:hover': { -// backgroundColor: isChildActive ? 'rgba(25, 113, 194, 0.15)' : 'rgba(25, 113, 194, 0.05)', -// }, -// ...(isChildActive && { -// backgroundColor: 'rgba(25, 113, 194, 0.1)', -// }), -// }, -// }} -// active={isChildActive} -// component={Link} -// /> -// ); -// })} -// -// ); -// })} -// - -// -// -// -// -// -// -// -// -// -// - -// -// {children} -// -// -// ); -// } - - -// app/admin/layout.tsx - 'use client' import colors from "@/con/colors"; diff --git a/src/app/darmasaba/(pages)/ekonomi/sektor-unggulan-desa/page.tsx b/src/app/darmasaba/(pages)/ekonomi/sektor-unggulan-desa/page.tsx index ff9953e0..2ceb23f2 100644 --- a/src/app/darmasaba/(pages)/ekonomi/sektor-unggulan-desa/page.tsx +++ b/src/app/darmasaba/(pages)/ekonomi/sektor-unggulan-desa/page.tsx @@ -1,6 +1,6 @@ 'use client' import colors from '@/con/colors'; -import { Stack, Box, Text, Paper, Skeleton } from '@mantine/core'; +import { Stack, Box, Text, Paper, Skeleton, Center } from '@mantine/core'; import React from 'react'; import BackButton from '../../desa/layanan/_com/BackButto'; import { BarChart } from '@mantine/charts'; @@ -80,26 +80,28 @@ function Page() { Statistik Sektor Unggulan Darmasaba - +
+ +
diff --git a/src/app/darmasaba/(pages)/inovasi/desa-digital-smart-village/page.tsx b/src/app/darmasaba/(pages)/inovasi/desa-digital-smart-village/page.tsx index b4aca08d..4fd1380f 100644 --- a/src/app/darmasaba/(pages)/inovasi/desa-digital-smart-village/page.tsx +++ b/src/app/darmasaba/(pages)/inovasi/desa-digital-smart-village/page.tsx @@ -54,7 +54,7 @@ function Page() { value={search} onChange={(e) => setSearch(e.target.value)} leftSection={} - w={{ base: "50%", md: "100%" }} + w={"100%"} /> diff --git a/src/app/darmasaba/(pages)/keamanan/keamanan-lingkungan-pecalang-patwal/[id]/page.tsx b/src/app/darmasaba/(pages)/keamanan/keamanan-lingkungan-pecalang-patwal/[id]/page.tsx index 5d33fd81..8f313af7 100644 --- a/src/app/darmasaba/(pages)/keamanan/keamanan-lingkungan-pecalang-patwal/[id]/page.tsx +++ b/src/app/darmasaba/(pages)/keamanan/keamanan-lingkungan-pecalang-patwal/[id]/page.tsx @@ -1,6 +1,6 @@ 'use client' -import { Box, Center, Image, Paper, Skeleton, Stack, Text } from '@mantine/core' +import { Box, Center, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core' import { useShallowEffect } from '@mantine/hooks' import { useParams } from 'next/navigation' import { useProxy } from 'valtio/utils' @@ -31,59 +31,62 @@ function DetailKeamananLingkunganUser() { return ( - - + + - {/* Wrapper Detail */} - - - {/* Judul */} - - {data?.name || 'Tanpa Judul'} - + {/* Wrapper Detail */} + + + {/* Judul */} + + {data?.name || 'Tanpa Judul'} + - {/* Gambar */} -
- {data?.name -
+ {/* Gambar */} +
+ {data?.name +
- {/* Deskripsi */} - - - Deskripsi - - - -
-
-
+ {/* Deskripsi */} + + + Deskripsi + + + + + +
+ + ) } -export default DetailKeamananLingkunganUser +export default DetailKeamananLingkunganUser \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/keamanan/keamanan-lingkungan-pecalang-patwal/page.tsx b/src/app/darmasaba/(pages)/keamanan/keamanan-lingkungan-pecalang-patwal/page.tsx index 7761bb69..d54568ec 100644 --- a/src/app/darmasaba/(pages)/keamanan/keamanan-lingkungan-pecalang-patwal/page.tsx +++ b/src/app/darmasaba/(pages)/keamanan/keamanan-lingkungan-pecalang-patwal/page.tsx @@ -1,7 +1,7 @@ 'use client' import keamananLingkunganState from '@/app/admin/(dashboard)/_state/keamanan/keamanan-lingkungan'; import colors from '@/con/colors'; -import { Box, Button, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core'; +import { Box, Button, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core'; import { useDebouncedValue, useShallowEffect } from '@mantine/hooks'; import { IconSearch } from '@tabler/icons-react'; import { useState } from 'react'; @@ -14,7 +14,7 @@ function Page() { const state = useProxy(keamananLingkunganState) const router = useRouter() const [search, setSearch] = useState('') - const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay + const [debouncedSearch] = useDebouncedValue(search, 1000); const { data, page, @@ -43,9 +43,9 @@ function Page() { - + Keamanan Lingkungan (Pecalang / Patwal) - </Text> + setSearch(e.target.value)} leftSection={} - w={{ base: "50%", md: "100%" }} + w={"100%"} /> - + Pecalang dan Patwal (Patroli Pengawal) bertugas memastikan desa tetap aman, tertib, dan kondusif bagi seluruh warga. + cols={{ base: 1, sm: 2, md: 3 }} + spacing="xl" + mt="lg" + > {data.map((v, k) => ( (e.currentTarget.style.transform = 'scale(1)')} /> - + {v.name} - </Text> + - + Kontak Darurat - </Text> - <Text fz="md" > + + Desa Darmasaba, Kecamatan Abiansemal, Kabupaten Badung. @@ -66,17 +66,21 @@ function Page() { - + Nomor Darurat Utama - 112 + + 112 +
- Tidak ada kontak darurat yang ditemukan + + Tidak ada kontak darurat yang ditemukan +
); @@ -89,10 +93,10 @@ function Page() { - + Kontak Darurat - </Text> - <Text fz={{ base: "h4", md: "h3" }} > + + Desa Darmasaba, Kecamatan Abiansemal, Kabupaten Badung. @@ -113,10 +117,12 @@ function Page() { - + Nomor Darurat Utama - 112 + + 112 + @@ -124,19 +130,13 @@ function Page() { - {/* Layanan Darurat */} {data.map((item) => ( - + {item.icon && ( @@ -147,12 +147,11 @@ function Page() { /> )} - + {item.nama} - </Text> + - {/* Kontak Items */} {item.kontakItems?.map((kontak) => ( )} - + {kontak.kontakItem?.nama} - + {kontak.kontakItem?.nomorTelepon}
@@ -204,4 +203,4 @@ function Page() { ); } -export default Page; +export default Page; \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/keamanan/pencegahan-kriminalitas/page.tsx b/src/app/darmasaba/(pages)/keamanan/pencegahan-kriminalitas/page.tsx index b859cf1e..574009f3 100644 --- a/src/app/darmasaba/(pages)/keamanan/pencegahan-kriminalitas/page.tsx +++ b/src/app/darmasaba/(pages)/keamanan/pencegahan-kriminalitas/page.tsx @@ -2,7 +2,7 @@ 'use client' import pencegahanKriminalitasState from '@/app/admin/(dashboard)/_state/keamanan/pencegahan-kriminalitas'; import colors from '@/con/colors'; -import { Box, Button, Center, Paper, SimpleGrid, Skeleton, Stack, Text } from '@mantine/core'; +import { Box, Button, Center, Paper, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconArrowRight } from '@tabler/icons-react'; import { useTransitionRouter } from 'next-view-transitions'; @@ -26,7 +26,7 @@ function Page() { if (!findFirst.data && !findFirst.loading) { kriminalitasState.findFirst.load(); } - }, [findFirst.data, findFirst.loading]); + }, []); useShallowEffect(() => { const LIMIT = 3; @@ -45,10 +45,10 @@ function Page() { return ( - + Pencegahan Kriminalitas - </Text> - <Text fz='md'> + + Keamanan Komunitas & Pencegahan Kriminal @@ -58,11 +58,11 @@ function Page() { spacing="xl" > - + Program Keamanan Berjalan - </Text> + - + Tidak ada data pencegahan kriminalitas yang cocok @@ -75,10 +75,10 @@ function Page() { return ( - + Pencegahan Kriminalitas - </Text> - <Text fz='md'> + + Keamanan Komunitas & Pencegahan Kriminal @@ -88,13 +88,13 @@ function Page() { spacing="xl" > - + Program Keamanan Berjalan - </Text> + {data.length > 0 ? ( @@ -120,14 +120,16 @@ function Page() { } > - + {item.judul} - </Text> + )) ) : ( - Tidak ada data pencegahan kriminalitas yang cocok + + Tidak ada data pencegahan kriminalitas yang cocok + )} - - - - ) - })} + + + + {data.map((v, k) => ( + + + + {v.nama} + + + Alamat: {v.alamat} + + + Jarak: {v.jarakKeDesa} + + + Telepon: {v.nomorTelepon} + + + Jam Operasional: {v.jamOperasional} + + + + + + + + + + ))} +
load(newPage)} // ini penting! + onChange={(newPage) => load(newPage)} total={totalPages} mt="md" mb="md" @@ -99,4 +126,4 @@ function Page() { ); } -export default Page; +export default Page; \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/component/edukasiCard.tsx b/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/component/edukasiCard.tsx index 3e5c1d5b..de2af2fe 100644 --- a/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/component/edukasiCard.tsx +++ b/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/component/edukasiCard.tsx @@ -1,7 +1,7 @@ -// Create a new component: components/EdukasiCard.tsx +// components/EdukasiCard.tsx 'use client'; -import { Box, Paper, Stack, Text } from '@mantine/core'; +import { Box, Paper, Stack, Text, Title } from '@mantine/core'; import { ReactNode } from 'react'; interface EdukasiCardProps { @@ -18,7 +18,7 @@ export function EdukasiCard({ icon, title, description, color = '#1e88e5' }: Edu radius="md" shadow="sm" withBorder - style={{ + style={{ height: '100%', transition: 'transform 0.2s, box-shadow 0.2s', '&:hover': { @@ -31,32 +31,35 @@ export function EdukasiCard({ icon, title, description, color = '#1e88e5' }: Edu {icon} - + </Stack> - <Text - size="sm" - pl={20} - style={{ - wordBreak: 'break-word', - lineHeight: 1.6, - color: 'var(--mantine-color-gray-7)' - }} - dangerouslySetInnerHTML={{ __html: description }} - /> + <Box pl={20}> + <Text + fz={{ base: 'sm', md: 'md' }} + lh={1.5} + c="gray.7" + ta="justify" + style={{ + wordBreak: 'break-word' + }} + dangerouslySetInnerHTML={{ __html: description }} + /> + </Box> </Box> </Stack> </Paper> diff --git a/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/page.tsx b/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/page.tsx index 14a4a925..9074daaa 100644 --- a/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/page.tsx +++ b/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Box, Container, SimpleGrid, Skeleton, Stack, Text } from '@mantine/core'; +import { Box, Container, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconLeaf, IconPlant2, IconRecycle } from '@tabler/icons-react'; import { useProxy } from 'valtio/utils'; @@ -51,19 +51,21 @@ export default function EdukasiLingkunganPage() { </Box> <Container size="lg" ta="center"> - <Text - component="h1" - fz={{ base: 'h2', md: '2.5rem' }} + <Title + order={1} c={colors['blue-button']} fw={700} mb="md" + lh={1.15} > Edukasi Lingkungan - </Text> + Program edukasi ini membimbing masyarakat untuk peduli dan bertanggung jawab terhadap alam, meningkatkan kesehatan, kenyamanan, dan keberlanjutan hidup bersama. diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/[id]/page.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/[id]/page.tsx index fc930270..6c032d55 100644 --- a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/[id]/page.tsx +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/[id]/page.tsx @@ -41,23 +41,23 @@ function DetailKegiatanDesaUser() { shadow="sm" maw={900} mx="auto" - > + > - {data.image?.link && ( - {data.judul - )} {/* Judul */} - + <Title order={1} ta={"center"} c={colors['blue-button']}> {data.judul || 'Kegiatan Desa'} + {data.image?.link && ( + {data.judul + )} {/* Meta Info */} diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/layout.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/layout.tsx index ff7ea037..933d5b47 100644 --- a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/layout.tsx +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/layout.tsx @@ -1,6 +1,10 @@ // app/desa/berita/BeritaLayoutClient.tsx 'use client' +import colors from '@/con/colors'; +import { Box } from '@mantine/core'; import dynamic from 'next/dynamic'; +import { usePathname } from 'next/navigation'; +import BackButton from '../../desa/layanan/_com/BackButto'; const LayoutTabsGotongRoyong = dynamic( () => import('./_lib/layoutTabs'), @@ -8,5 +12,21 @@ const LayoutTabsGotongRoyong = dynamic( ); export default function GotongRoyongLayoutClient({ children }: { children: React.ReactNode }) { + const pathname = usePathname() + const segments = pathname.split('/').filter(Boolean) + const isDetailPage = segments.length === 5; + + if (isDetailPage) { + // Tampilkan tanpa tab menu + return ( + + + + + {children} + + ); + } + return {children}; } \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/semua/page.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/semua/page.tsx index 785e5b92..beb8f4e4 100644 --- a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/semua/page.tsx +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/semua/page.tsx @@ -11,7 +11,6 @@ import { Center, Container, Divider, - Flex, Grid, GridCol, Group, @@ -23,7 +22,7 @@ import { Stack, Text, Title, - Transition, + Transition } from '@mantine/core'; import { IconArrowRight, IconCalendar } from '@tabler/icons-react'; import { motion } from 'framer-motion'; @@ -46,7 +45,7 @@ export default function Page() { // Load featured data once on component mount useEffect(() => { let mounted = true; - + const loadFeatured = async () => { try { if (!featured.data && !loadingFeatured) { @@ -68,7 +67,7 @@ export default function Page() { useEffect(() => { let mounted = true; - + const loadData = async () => { try { const limit = 3; @@ -92,7 +91,7 @@ export default function Page() { if (search) url.set('search', search); if (newPage > 1) url.set('page', newPage.toString()); else url.delete('page'); - + // Use push instead of replace to keep browser history router.push(`?${url.toString()}`, { scroll: false }); }; @@ -139,7 +138,6 @@ export default function Page() { height={400} fit="cover" radius="md" - style={{ borderBottomRightRadius: 0, borderTopRightRadius: 0 }} loading="lazy" /> @@ -222,6 +220,7 @@ export default function Page() { alt={item.judul} fit="cover" loading="lazy" + radius={"md"} /> @@ -241,14 +240,17 @@ export default function Page() { dangerouslySetInnerHTML={{ __html: item.deskripsiSingkat }} /> - - - {new Date(item.createdAt).toLocaleDateString('id-ID', { - day: 'numeric', - month: 'short', - year: 'numeric', - })} - + + + + + {new Date(item.createdAt).toLocaleDateString('id-ID', { + day: 'numeric', + month: 'short', + year: 'numeric', + })} + + - + ))} diff --git a/src/app/darmasaba/(pages)/lingkungan/konservasi-adat-bali/page.tsx b/src/app/darmasaba/(pages)/lingkungan/konservasi-adat-bali/page.tsx index 76a39cf6..c8b87968 100644 --- a/src/app/darmasaba/(pages)/lingkungan/konservasi-adat-bali/page.tsx +++ b/src/app/darmasaba/(pages)/lingkungan/konservasi-adat-bali/page.tsx @@ -1,11 +1,12 @@ 'use client' import stateKonservasiAdatBali from '@/app/admin/(dashboard)/_state/lingkungan/konservasi-adat-bali'; import colors from '@/con/colors'; -import { Box, Center, Paper, SimpleGrid, Skeleton, Stack, Text } from '@mantine/core'; +import { Box, Center, Paper, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { useProxy } from 'valtio/utils'; import BackButton from '../../desa/layanan/_com/BackButto'; + function Page() { const filosofi = useProxy(stateKonservasiAdatBali.stateFilosofiTriHita.findById) const nilai = useProxy(stateKonservasiAdatBali.stateNilaiKonservasiAdat.findById) @@ -30,11 +31,24 @@ function Page() { - - + + Konservasi Adat Bali - </Text> - <Text px={20} ta="center" fz="lg" c="black"> + + Pelestarian lingkungan di Bali yang berpijak pada kearifan lokal, menjaga harmoni antara alam, budaya, dan manusia. @@ -54,53 +68,31 @@ function Page() { >
- + {filosofi.data?.judul} - </Text> - </Center> - <div - style={{ - wordBreak: "break-word", - whiteSpace: "normal", - flexGrow: 1 - }} - dangerouslySetInnerHTML={{ __html: filosofi.data?.deskripsi || '' }} - /> - </Stack> - </Paper> - </Box> - {/* Nilai */} - <Box style={{ display: 'flex', height: '100%' }}> - <Paper - p="lg" - style={{ - borderRadius: 16, - width: '100%', - display: 'flex', - flexDirection: 'column', - boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)' - }} - > - <Stack gap="md" px={20} style={{ height: '100%' }}> - <Center> - <Text fz="xl" fw="bold" c="black"> - {nilai.data?.judul} - </Text> +
- - {/* Bentuk */} - + + {/* Nilai */} +
- - {bentuk.data?.judul} - + + {nilai.data?.judul} +
+ + + + {/* Bentuk */} + + + +
+ + {bentuk.data?.judul} + +
+
- + ); } -export default Page; +export default Page; \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/pendidikan/beasiswa-desa/pelajari-lebih-lanjut/page.tsx b/src/app/darmasaba/(pages)/pendidikan/beasiswa-desa/pelajari-lebih-lanjut/page.tsx index 89db8ad0..c408b5b1 100644 --- a/src/app/darmasaba/(pages)/pendidikan/beasiswa-desa/pelajari-lebih-lanjut/page.tsx +++ b/src/app/darmasaba/(pages)/pendidikan/beasiswa-desa/pelajari-lebih-lanjut/page.tsx @@ -5,6 +5,7 @@ import { Button, Container, Divider, + Flex, Group, Modal, Paper, @@ -23,11 +24,11 @@ import { useProxy } from 'valtio/utils'; import beasiswaDesaState from '@/app/admin/(dashboard)/_state/pendidikan/beasiswa-desa'; import colors from '@/con/colors'; - export default function BeasiswaPage() { const router = useRouter(); - const beasiswaDesa = useProxy(beasiswaDesaState.beasiswaPendaftar) + const beasiswaDesa = useProxy(beasiswaDesaState.beasiswaPendaftar); const [opened, { open, close }] = useDisclosure(false); + const resetForm = () => { beasiswaDesa.create.form = { namaLengkap: "", @@ -61,6 +62,7 @@ export default function BeasiswaPage() { leftSection={} onClick={() => router.back()} mb="lg" + style={{ fontSize: '1rem', fontWeight: 500 }} > Kembali @@ -69,11 +71,18 @@ export default function BeasiswaPage() { {/* Hero Section */} - + - Program Beasiswa Pendidikan Desa Darmasaba - - + + Program Beasiswa Pendidikan Desa Darmasaba + + + Program ini bertujuan untuk mendukung pendidikan generasi muda di Desa Darmasaba agar dapat melanjutkan studi ke jenjang lebih tinggi dengan dukungan finansial dan pendampingan. @@ -84,20 +93,22 @@ export default function BeasiswaPage() { - Tentang Program + + Tentang Program + - + Program Beasiswa Desa Darmasaba adalah inisiatif pemerintah desa untuk meningkatkan akses pendidikan bagi siswa berprestasi dan kurang mampu. Melalui program ini, desa memberikan bantuan biaya sekolah, bimbingan akademik, serta pelatihan soft skill bagi peserta terpilih. - {/* Tambahkan info tahun berjalan di sini */} + {/* Periode Beasiswa */} - + Periode Beasiswa Tahun 2025 - + Pendaftaran beasiswa dibuka mulai 1 Januari 2025 dan ditutup pada 31 Mei 2025. Pengumuman hasil seleksi akan diumumkan pada pertengahan Juni 2025 melalui website resmi Desa Darmasaba. @@ -108,27 +119,35 @@ export default function BeasiswaPage() { - Syarat Pendaftaran + + Syarat Pendaftaran + - Domisili Desa Darmasaba - + + Domisili Desa Darmasaba + + Peserta harus merupakan warga desa yang berdomisili minimal 2 tahun. - Nilai Akademik - + + Nilai Akademik + + Rata-rata nilai raport minimal 80 atau setara. - Surat Rekomendasi - + + Surat Rekomendasi + + Diperlukan surat rekomendasi dari sekolah atau guru wali kelas. @@ -139,75 +158,102 @@ export default function BeasiswaPage() { - Proses Seleksi + + Proses Seleksi + - - + + Pendaftaran Online + + } + > + Calon peserta mengisi formulir pendaftaran dan mengunggah dokumen pendukung. - + Estimasi waktu: 1 Februari – 31 Mei 2025 - - + + Seleksi Administrasi + + } + > + Panitia memverifikasi kelengkapan dan validitas berkas. - + Estimasi waktu: 5–7 hari kerja setelah penutupan pendaftaran - - + + Wawancara dan Penilaian + + } + > + Peserta yang lolos administrasi akan diundang untuk wawancara langsung dengan tim seleksi. - + Estimasi waktu: 7–10 hari kerja setelah pengumuman seleksi administrasi - - + + Pengumuman Penerima + + } + > + Daftar penerima beasiswa diumumkan melalui website resmi Desa Darmasaba. - + Estimasi waktu: 5 hari kerja setelah tahap wawancara selesai - + Total estimasi keseluruhan proses: sekitar 3–4 minggu setelah penutupan pendaftaran - {/* Testimoni */} - Cerita Sukses Penerima Beasiswa + + Cerita Sukses Penerima Beasiswa + - + “Program ini sangat membantu saya melanjutkan kuliah di Universitas Udayana. Terima kasih Desa Darmasaba!” - + – Ni Kadek Ayu S., Penerima Beasiswa 2024 - + “Selain bantuan dana, kami juga mendapatkan pelatihan komputer dan bahasa Inggris.” - + – I Made Gede A., Penerima Beasiswa 2023 @@ -218,16 +264,25 @@ export default function BeasiswaPage() { - Siap Bergabung dengan Program Ini? + + Siap Bergabung dengan Program Ini? + - + Segera daftar dan wujudkan mimpimu bersama Desa Darmasaba. - + {/* Modal Formulir */} + Formulir Beasiswa } @@ -245,64 +300,105 @@ export default function BeasiswaPage() { { beasiswaDesa.create.form.namaLengkap = val.target.value }} /> + labelProps={{ style: { fontSize: '0.9375rem', fontWeight: 600, lineHeight: 1.4 } }} + onChange={(val) => { beasiswaDesa.create.form.namaLengkap = val.target.value }} + /> { beasiswaDesa.create.form.nis = val.target.value }} /> + labelProps={{ style: { fontSize: '0.9375rem', fontWeight: 600, lineHeight: 1.4 } }} + onChange={(val) => { beasiswaDesa.create.form.nis = val.target.value }} + /> { beasiswaDesa.create.form.kelas = val.target.value }} /> + labelProps={{ style: { fontSize: '0.9375rem', fontWeight: 600, lineHeight: 1.4 } }} + onChange={(val) => { beasiswaDesa.create.form.kelas = val.target.value }} + />