diff --git a/src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts b/src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts index 5e618388..d966a861 100644 --- a/src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts +++ b/src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts @@ -354,14 +354,39 @@ const kategoriKegiatan = proxy({ id: string; nama: string; }> | null, - async load() { - const res = await ApiFetch.api.lingkungan.kategorikegiatan[ - "find-many" - ].get(); - if (res.status === 200) { - kategoriKegiatan.findMany.data = res.data?.data ?? []; - } - }, + page: 1, + totalPages: 1, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + kategoriKegiatan.findMany.loading = true; // ✅ Akses langsung via nama path + kategoriKegiatan.findMany.page = page; + kategoriKegiatan.findMany.search = search; + + try { + const query: any = { page, limit }; + if (search) query.search = search; + + const res = + await ApiFetch.api.lingkungan.kategorikegiatan[ + "find-many" + ].get({ query }); + + if (res.status === 200 && res.data?.success) { + kategoriKegiatan.findMany.data = res.data.data ?? []; + kategoriKegiatan.findMany.totalPages = res.data.totalPages ?? 1; + } else { + kategoriKegiatan.findMany.data = []; + kategoriKegiatan.findMany.totalPages = 1; + } + } catch (err) { + console.error("Gagal fetch kategori kegiatan paginated:", err); + kategoriKegiatan.findMany.data = []; + kategoriKegiatan.findMany.totalPages = 1; + } finally { + kategoriKegiatan.findMany.loading = false; + } + }, }, findUnique: { data: null as Prisma.KategoriKegiatanGetPayload<{ diff --git a/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/[id]/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/[id]/edit/page.tsx index 9899c887..33dbccb4 100644 --- a/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/[id]/edit/page.tsx @@ -3,7 +3,17 @@ import EditEditor from '@/app/admin/(dashboard)/_com/editEditor'; import dataLingkunganDesaState from '@/app/admin/(dashboard)/_state/lingkungan/data-lingkungan-desa'; import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + Text, + TextInput, + Title, + Tooltip, +} from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; @@ -19,34 +29,34 @@ interface FormDataLingkunganDesa { } type IconKey = - 'ekowisata' | - 'kompetisi' | - 'wisata' | - 'ekonomi' | - 'sampah' | - 'truck' | - 'scale' | - 'clipboard' | - 'trash' | - 'lingkunganSehat' | - 'sumberOksigen' | - 'ekonomiBerkelanjutan' | - 'mencegahBencana' | - 'rumah' | - 'pohon' | - 'air'; - + | 'ekowisata' + | 'kompetisi' + | 'wisata' + | 'ekonomi' + | 'sampah' + | 'truck' + | 'scale' + | 'clipboard' + | 'trash' + | 'lingkunganSehat' + | 'sumberOksigen' + | 'ekonomiBerkelanjutan' + | 'mencegahBencana' + | 'rumah' + | 'pohon' + | 'air'; function EditDataLingkunganDesa() { - const stateDataLingkunganDesa = useProxy(dataLingkunganDesaState) - const params = useParams() + const stateDataLingkunganDesa = useProxy(dataLingkunganDesaState); + const params = useParams(); const router = useRouter(); + const [formData, setFormData] = useState({ name: '', deskripsi: '', jumlah: '', icon: '', - }) + }); useEffect(() => { const loadProgramKreatif = async () => { @@ -56,7 +66,6 @@ function EditDataLingkunganDesa() { try { const data = await stateDataLingkunganDesa.update.load(id); if (data) { - // ⬇️ FIX PENTING: tambahkan ini stateDataLingkunganDesa.update.id = id; stateDataLingkunganDesa.update.form = { @@ -74,16 +83,14 @@ function EditDataLingkunganDesa() { }); } } catch (error) { - console.error("Error loading data lingkungan desa:", error); - toast.error("Gagal memuat data data lingkungan desa"); + console.error('Error loading data lingkungan desa:', error); + toast.error('Gagal memuat data lingkungan desa'); } - } + }; loadProgramKreatif(); }, [params?.id]); - - const handleSubmit = async () => { try { stateDataLingkunganDesa.update.form = { @@ -92,49 +99,68 @@ function EditDataLingkunganDesa() { deskripsi: formData.deskripsi.trim(), jumlah: formData.jumlah.trim(), icon: formData.icon.trim(), - } + }; await stateDataLingkunganDesa.update.submit(); - router.push("/admin/lingkungan/data-lingkungan-desa"); + toast.success('Data lingkungan desa berhasil diperbarui!'); + router.push('/admin/lingkungan/data-lingkungan-desa'); } catch (error) { - console.error("Error updating data lingkungan desa:", error); - toast.error("Gagal memuat data data lingkungan desa"); + console.error('Error updating data lingkungan desa:', error); + toast.error('Terjadi kesalahan saat memperbarui data lingkungan desa'); } - } - return ( - - - - + }; - - - Edit Data Lingkungan Desa + return ( + + + + + + + Edit Data Lingkungan Desa + + + + + Nama Data Lingkungan Desa} - placeholder="masukkan nama data lingkungan desa" - onChange={(val) => { + label={Nama Data Lingkungan Desa} + placeholder="Masukkan nama data lingkungan desa" + onChange={(val) => setFormData({ ...formData, - name: val.target.value + name: val.target.value, }) - }} + } + required /> + Jumlah Data Lingkungan Desa} - placeholder="masukkan jumlah data lingkungan desa" - onChange={(val) => { + label={Jumlah Data Lingkungan Desa} + placeholder="Masukkan jumlah data lingkungan desa" + onChange={(val) => setFormData({ ...formData, - jumlah: val.target.value + jumlah: val.target.value, }) - }} + } + required /> + - Deskripsi + + Deskripsi + { @@ -143,16 +169,34 @@ function EditDataLingkunganDesa() { }} /> + - Ikon Data Lingkungan Desa + + Ikon Data Lingkungan Desa + { setFormData((prev) => ({ ...prev, icon: value })); stateDataLingkunganDesa.update.form.icon = value; - }} /> + }} + /> - + + + + diff --git a/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/[id]/page.tsx b/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/[id]/page.tsx index 2b38662a..5f1d6095 100644 --- a/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/[id]/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/[id]/page.tsx @@ -1,23 +1,40 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core'; +import { Box, Button, Group, Paper, Skeleton, Stack, Text, Tooltip } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconArrowBack, IconChartLine, IconChristmasTreeFilled, IconClipboard, IconDroplet, IconEdit, IconHome, IconHomeEco, IconLeaf, IconRecycle, IconScale, IconShieldFilled, IconTent, IconTrash, IconTree, IconTrendingUp, IconTrophy, IconTruck, IconX } from '@tabler/icons-react'; +import { + IconArrowBack, + IconChartLine, + IconChristmasTreeFilled, + IconClipboard, + IconDroplet, + IconEdit, + IconHome, + IconHomeEco, + IconLeaf, + IconRecycle, + IconScale, + IconShieldFilled, + IconTent, + IconTrash, + IconTree, + IconTrendingUp, + IconTrophy, + IconTruck, +} from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import React, { useState } from 'react'; import { useProxy } from 'valtio/utils'; -import dataLingkunganDesaState from '../../../_state/lingkungan/data-lingkungan-desa'; import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; - -// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; +import dataLingkunganDesaState from '../../../_state/lingkungan/data-lingkungan-desa'; function DetailDataLingkunganDesa() { - const [modalHapus, setModalHapus] = useState(false) - const stateDataLingkungan = useProxy(dataLingkunganDesaState) - const router = useRouter() - const params = useParams() - const [selectedId, setSelectedId] = useState(null) + const [modalHapus, setModalHapus] = useState(false); + const stateDataLingkungan = useProxy(dataLingkunganDesaState); + const router = useRouter(); + const params = useParams(); + const [selectedId, setSelectedId] = useState(null); const iconMap: Record> = { ekowisata: IconLeaf, @@ -35,90 +52,117 @@ function DetailDataLingkunganDesa() { mencegahBencana: IconShieldFilled, rumah: IconHome, pohon: IconTree, - air: IconDroplet + air: IconDroplet, }; useShallowEffect(() => { - stateDataLingkungan.findUnique.load(params?.id as string) - }, [params?.id]) + stateDataLingkungan.findUnique.load(params?.id as string); + }, [params?.id]); const handleHapus = () => { if (selectedId) { - stateDataLingkungan.delete.byId(selectedId) - setModalHapus(false) - setSelectedId(null) - router.push("/admin/lingkungan/data-lingkungan-desa") + stateDataLingkungan.delete.byId(selectedId); + setModalHapus(false); + setSelectedId(null); + router.push('/admin/lingkungan/data-lingkungan-desa'); } - } + }; if (!stateDataLingkungan.findUnique.data) { return ( - - + + - ) + ); } - return ( - - - - - - - Detail Data Lingkungan Desa + const data = stateDataLingkungan.findUnique.data; - - + return ( + + {/* Back Button */} + + + {/* Main Card */} + + + {/* Title */} + + Detail Data Lingkungan Desa + + + {/* Content Card */} + + - Nama Data Lingkungan Desa - {stateDataLingkungan.findUnique.data?.name} + Nama Data Lingkungan Desa + {data?.name || '-'} + - Jumlah Data Lingkungan Desa - {stateDataLingkungan.findUnique.data?.jumlah} + Jumlah Data Lingkungan Desa + {data?.jumlah || '-'} + - Ikon Data Lingkungan Desa - {iconMap[stateDataLingkungan.findUnique.data?.icon] && ( - - {React.createElement(iconMap[stateDataLingkungan.findUnique.data?.icon], { size: 24 })} + Ikon Data Lingkungan Desa + {iconMap[data?.icon] ? ( + + {React.createElement(iconMap[data.icon], { size: 28, color: colors['blue-button'] })} + ) : ( + Tidak ada ikon )} + - Deskripsi - + Deskripsi + - - + + {/* Action Buttons */} + + + + + - - + + @@ -130,7 +174,7 @@ function DetailDataLingkunganDesa() { onClose={() => setModalHapus(false)} onConfirm={handleHapus} text="Apakah anda yakin ingin menghapus data lingkungan desa ini?" - /> + /> ); } diff --git a/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/create/page.tsx b/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/create/page.tsx index ada9e94f..54dd409d 100644 --- a/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/create/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/create/page.tsx @@ -1,6 +1,16 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + Text, + TextInput, + Title, + Tooltip, +} from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useProxy } from 'valtio/utils'; @@ -8,60 +18,105 @@ import CreateEditor from '../../../_com/createEditor'; import SelectIconProgram from '../../../_com/selectIcon'; import dataLingkunganDesaState from '../../../_state/lingkungan/data-lingkungan-desa'; - function CreateDataLingkunganDesa() { - const stateCreate = useProxy(dataLingkunganDesaState) + const stateCreate = useProxy(dataLingkunganDesaState); const router = useRouter(); const resetForm = () => { stateCreate.create.form = { - name: "", - deskripsi: "", - jumlah: "", - icon: "", - } - } + name: '', + deskripsi: '', + jumlah: '', + icon: '', + }; + }; const handleSubmit = async () => { await stateCreate.create.create(); resetForm(); - router.push("/admin/lingkungan/data-lingkungan-desa") - } - return ( - - - - + router.push('/admin/lingkungan/data-lingkungan-desa'); + }; - - - Create Data Lingkungan Desa + return ( + + {/* Header */} + + + + + + Tambah Data Lingkungan Desa + + + + {/* Card Form */} + + Nama Data Lingkungan Desa} - placeholder="masukkan nama data lingkungan desa" - onChange={(val) => stateCreate.create.form.name = val.target.value} + label={Nama Data Lingkungan Desa} + placeholder="Masukkan nama data lingkungan desa" + value={stateCreate.create.form.name || ''} + onChange={(val) => (stateCreate.create.form.name = val.target.value)} + required /> + - Ikon Data Lingkungan Desa - stateCreate.create.form.icon = value} /> - - stateCreate.create.form.jumlah = e.currentTarget.value} - label={Jmlah data lingkungan desa} - placeholder='Masukkan jumlah data lingkungan desa' - /> - - Deskripsi data lingkungan desa - stateCreate.create.form.deskripsi = htmlContent} + + Ikon Data Lingkungan Desa + + (stateCreate.create.form.icon = value)} /> - - + + Jumlah Data Lingkungan Desa} + placeholder="Masukkan jumlah data lingkungan desa" + value={stateCreate.create.form.jumlah || ''} + onChange={(e) => (stateCreate.create.form.jumlah = e.currentTarget.value)} + required + /> + + + + Deskripsi Data Lingkungan Desa + + + (stateCreate.create.form.deskripsi = htmlContent) + } + /> + + + {/* Submit Button */} + + diff --git a/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/page.tsx b/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/page.tsx index cda0e3bb..acc56ac6 100644 --- a/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/data-lingkungan-desa/page.tsx @@ -2,21 +2,23 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; import { - IconChartLine, IconChristmasTreeFilled, IconClipboardTextFilled, IconDeviceImac, IconDroplet, IconHome, IconHomeEco, IconLeaf, + Box, Button, Center, Group, Pagination, Paper, Skeleton, Stack, + Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, + Title, + Tooltip +} from '@mantine/core'; +import { + IconChartLine, IconChristmasTreeFilled, IconClipboardTextFilled, + IconDeviceImacCog, IconDroplet, IconHome, IconHomeEco, IconLeaf, + IconPlus, IconRecycle, IconScale, IconSearch, IconShieldFilled, IconTent, - IconTrashFilled, - IconTree, - IconTrendingUp, - IconTrophy, - IconTruckFilled + IconTrashFilled, IconTree, IconTrendingUp, IconTrophy, IconTruckFilled } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '../../_com/header'; -import JudulList from '../../_com/judulList'; import dataLingkunganDesaState from '../../_state/lingkungan/data-lingkungan-desa'; @@ -26,7 +28,7 @@ function DataLingkunganDesa() { } value={search} onChange={(e) => setSearch(e.currentTarget.value)} @@ -64,76 +66,98 @@ function ListDataLingkunganDesa({ search }: { search: string }) { rumah: IconHome, pohon: IconTree, air: IconDroplet - }; if (loading || !data) { return ( - + ); } + if (data.length === 0) { return ( - + - - + + Daftar Data Lingkungan Desa + + + + +
No Nama Data Lingkungan Desa - Jumlah Data Lingkungan Desa + Jumlah Ikon Detail
- Tidak ada data lingkungan desa yang tersedia +
+ Tidak ada data lingkungan desa yang tersedia +
); } + return ( - - - - + + + Daftar Data Lingkungan Desa + + + + + +
No - Nama Data Lingkungan Desa - Jumlah Data Lingkungan Desa - Ikon - Detail + Nama Data + Jumlah + Ikon + Detail {filteredData.map((item, index) => ( - {index + 1} - {item.name} - ± {item.jumlah} - + {index + 1} + + {item.name} + + + ± {item.jumlah} + + {iconMap[item.icon] && ( - {React.createElement(iconMap[item.icon], { size: 24 })} + {React.createElement(iconMap[item.icon], { size: 22 })} )} - - @@ -147,11 +171,13 @@ function ListDataLingkunganDesa({ search }: { search: string }) { value={page} onChange={(newPage) => { load(newPage, 10); - window.scrollTo(0, 0); + window.scrollTo({ top: 0, behavior: 'smooth' }); }} total={totalPages} mt="md" mb="md" + color="blue" + radius="md" /> diff --git a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/_lib/layouTabs.tsx b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/_lib/layouTabs.tsx index c02e28a4..53d91f8c 100644 --- a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/_lib/layouTabs.tsx +++ b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/_lib/layouTabs.tsx @@ -1,67 +1,116 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core'; +import { Box, ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title, Tooltip } from '@mantine/core'; +import { IconBook, IconLeaf, IconSchool } from '@tabler/icons-react'; import { usePathname, useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; function LayoutTabs({ children }: { children: React.ReactNode }) { const router = useRouter() const pathname = usePathname() + const tabs = [ { label: "Tujuan Edukasi Lingkungan", value: "tujuanedukasilingkungan", - href: "/admin/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan" + href: "/admin/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan", + tooltip: "Lihat tujuan edukasi lingkungan", + icon: }, { label: "Materi Edukasi Yang Diberikan", value: "materiedukasiyangdiberikan", - href: "/admin/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan" + href: "/admin/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan", + tooltip: "Kelola materi edukasi yang diberikan", + icon: }, { label: "Contoh Kegiatan Di Desa Darmasaba", value: "contohkegiatan", - href: "/admin/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba" + href: "/admin/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba", + tooltip: "Lihat contoh kegiatan desa Darmasaba", + icon: }, ]; - const curentTab = tabs.find(tab => tab.href === pathname) - const [activeTab, setActiveTab] = useState(curentTab?.value || tabs[0].value); + + const currentTab = tabs.find(tab => tab.href === pathname) + const [activeTab, setActiveTab] = useState(currentTab?.value || tabs[0].value); const handleTabChange = (value: string | null) => { const tab = tabs.find(t => t.value === value) - if (tab) { - router.push(tab.href) - } + if (tab) router.push(tab.href) setActiveTab(value) } useEffect(() => { const match = tabs.find(tab => tab.href === pathname) - if (match) { - setActiveTab(match.value) - } + if (match) setActiveTab(match.value) }, [pathname]) return ( - - Jumlah Penduduk Usia Kerja yang Menganggur - - - {tabs.map((e, i) => ( - {e.label} - ))} - - {tabs.map((e, i) => ( - - {/* Konten dummy, bisa diganti tergantung routing */} - <> + + + Edukasi Lingkungan + + + + + + {tabs.map((tab, i) => ( + + + + {tab.label} + + + + ))} + + + + {tabs.map((tab, i) => ( + + + {children} + ))} - {children} - ); + ) } -export default LayoutTabs; \ No newline at end of file +export default LayoutTabs; diff --git a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba/edit/page.tsx index b4c1a65e..e43c4f1e 100644 --- a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba/edit/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba/edit/page.tsx @@ -9,77 +9,105 @@ import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; -const EdukasiLingkunganTextEditor = dynamic(() => import('../../_lib/edukasiLingkunganTextEditor').then(mod => mod.EdukasiLingkunganTextEditor), { - ssr: false, -}); +const EdukasiLingkunganTextEditor = dynamic( + () => import('../../_lib/edukasiLingkunganTextEditor').then(mod => mod.EdukasiLingkunganTextEditor), + { ssr: false } +); function EditContohKegiatanDesaDarmasaba() { - const router = useRouter() - const contohEdukasiState = useProxy(stateEdukasiLingkungan.stateContohEdukasiLingkungan) + const router = useRouter(); + const contohEdukasiState = useProxy(stateEdukasiLingkungan.stateContohEdukasiLingkungan); const [judul, setJudul] = useState(''); const [content, setContent] = useState(''); useShallowEffect(() => { if (!contohEdukasiState.findById.data) { - contohEdukasiState.findById.initialize(); // biar masuk ke `findFirst` route kamu + contohEdukasiState.findById.initialize(); } }, []); useEffect(() => { if (contohEdukasiState.findById.data) { - setJudul(contohEdukasiState.findById.data.judul ?? '') - setContent(contohEdukasiState.findById.data.deskripsi ?? '') + setJudul(contohEdukasiState.findById.data.judul ?? ''); + setContent(contohEdukasiState.findById.data.deskripsi ?? ''); } - }, [contohEdukasiState.findById.data]) + }, [contohEdukasiState.findById.data]); const submit = () => { if (contohEdukasiState.findById.data) { contohEdukasiState.findById.data.judul = judul; contohEdukasiState.findById.data.deskripsi = content; - contohEdukasiState.update.save(contohEdukasiState.findById.data) + contohEdukasiState.update.save(contohEdukasiState.findById.data); } - router.push('/admin/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba') - } + router.push('/admin/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba'); + }; + return ( - - - - - - - - - Edit Contoh Kegiatan Di Desa Darmasaba - Judul - - Deskripsi - - - - - - - - + + {/* Header */} + + + + Edit Contoh Kegiatan di Desa Darmasaba + + + + {/* Form Paper */} + + + + + Judul + + + + + + + Deskripsi + + + + + + + + + ); } diff --git a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba/page.tsx b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba/page.tsx index f128e63f..1e13f6df 100644 --- a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/contoh-kegiatan-desa-darmasaba/page.tsx @@ -1,5 +1,4 @@ 'use client' -import colors from '@/con/colors'; import { Box, Button, Grid, GridCol, Paper, Skeleton, Stack, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconEdit } from '@tabler/icons-react'; @@ -8,47 +7,72 @@ import { useProxy } from 'valtio/utils'; import stateEdukasiLingkungan from '../../../_state/lingkungan/edukasi-lingkungan'; function Page() { - const router = useRouter() - const listContohEdukasi = useProxy(stateEdukasiLingkungan.stateContohEdukasiLingkungan) + const router = useRouter(); + const listContohEdukasi = useProxy(stateEdukasiLingkungan.stateContohEdukasiLingkungan); + useShallowEffect(() => { - listContohEdukasi.findById.load('edit') - }, []) + listContohEdukasi.findById.load('edit'); + }, []); if (!listContohEdukasi.findById.data) { return ( - - + + - ) + ); } + return ( - - - + + + - Preview Contoh Kegiatan Di Desa Darmasaba + + Preview Contoh Kegiatan Di Desa Darmasaba + - - - - - - - - - - - - - - - - - ) + + + + + + + + + + + + + + ); } export default Page; diff --git a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan/edit/page.tsx index a0ded4df..ad78350d 100644 --- a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan/edit/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan/edit/page.tsx @@ -9,77 +9,90 @@ import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; -const EdukasiLingkunganTextEditor = dynamic(() => import('../../_lib/edukasiLingkunganTextEditor').then(mod => mod.EdukasiLingkunganTextEditor), { - ssr: false, -}); +const EdukasiLingkunganTextEditor = dynamic( + () => import('../../_lib/edukasiLingkunganTextEditor').then(mod => mod.EdukasiLingkunganTextEditor), + { ssr: false } +); function EditMateriEdukasiYangDiberikan() { - const router = useRouter() - const materiEdukasiState = useProxy(stateEdukasiLingkungan.stateMateriEdukasiLingkungan) + const router = useRouter(); + const materiEdukasiState = useProxy(stateEdukasiLingkungan.stateMateriEdukasiLingkungan); const [judul, setJudul] = useState(''); const [content, setContent] = useState(''); useShallowEffect(() => { if (!materiEdukasiState.findById.data) { - materiEdukasiState.findById.initialize(); // biar masuk ke `findFirst` route kamu + materiEdukasiState.findById.initialize(); } }, []); useEffect(() => { if (materiEdukasiState.findById.data) { - setJudul(materiEdukasiState.findById.data.judul ?? '') - setContent(materiEdukasiState.findById.data.deskripsi ?? '') + setJudul(materiEdukasiState.findById.data.judul ?? ''); + setContent(materiEdukasiState.findById.data.deskripsi ?? ''); } - }, [materiEdukasiState.findById.data]) + }, [materiEdukasiState.findById.data]); const submit = () => { if (materiEdukasiState.findById.data) { materiEdukasiState.findById.data.judul = judul; materiEdukasiState.findById.data.deskripsi = content; - materiEdukasiState.update.save(materiEdukasiState.findById.data) + materiEdukasiState.update.save(materiEdukasiState.findById.data); } - router.push('/admin/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan') - } + router.push('/admin/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan'); + }; + return ( - - - - - - - - - Edit Materi Edukasi Yang Diberikan - Judul - - Content - - - - - - - - + + + + + Edit Materi Edukasi Yang Diberikan + + + + + + + + Judul + + + + + + + Konten + + + + + + + + + ); } diff --git a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan/page.tsx b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan/page.tsx index 4fda84db..330a50ca 100644 --- a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan/page.tsx @@ -1,5 +1,4 @@ 'use client' -import colors from '@/con/colors'; import { Box, Button, Grid, GridCol, Paper, Skeleton, Stack, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconEdit } from '@tabler/icons-react'; @@ -10,44 +9,65 @@ import stateEdukasiLingkungan from '../../../_state/lingkungan/edukasi-lingkunga function Page() { const router = useRouter() const listMateriEdukasi = useProxy(stateEdukasiLingkungan.stateMateriEdukasiLingkungan) + useShallowEffect(() => { listMateriEdukasi.findById.load('edit') }, []) if (!listMateriEdukasi.findById.data) { return ( - - + + ) } + return ( - - - + + + - Preview Materi Edukasi Yang Diberikan + Preview Materi Edukasi Yang Diberikan - - - - - - - - - - - - - - - - + + + + + + + + + + + + + ) } diff --git a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan/edit/page.tsx index 3de3b509..b196c099 100644 --- a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan/edit/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan/edit/page.tsx @@ -9,77 +9,103 @@ import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; -const EdukasiLingkunganTextEditor = dynamic(() => import('../../_lib/edukasiLingkunganTextEditor').then(mod => mod.EdukasiLingkunganTextEditor), { - ssr: false, -}); +const EdukasiLingkunganTextEditor = dynamic( + () => import('../../_lib/edukasiLingkunganTextEditor').then(mod => mod.EdukasiLingkunganTextEditor), + { ssr: false } +); function EditTujuanEdukasiLingkungan() { - const router = useRouter() - const tujuanEdukasiState = useProxy(stateEdukasiLingkungan.stateTujuanEdukasi) + const router = useRouter(); + const tujuanEdukasiState = useProxy(stateEdukasiLingkungan.stateTujuanEdukasi); const [judul, setJudul] = useState(''); const [content, setContent] = useState(''); useShallowEffect(() => { if (!tujuanEdukasiState.findById.data) { - tujuanEdukasiState.findById.initialize(); // biar masuk ke `findFirst` route kamu + tujuanEdukasiState.findById.initialize(); } }, []); useEffect(() => { if (tujuanEdukasiState.findById.data) { - setJudul(tujuanEdukasiState.findById.data.judul ?? '') - setContent(tujuanEdukasiState.findById.data.deskripsi ?? '') + setJudul(tujuanEdukasiState.findById.data.judul ?? ''); + setContent(tujuanEdukasiState.findById.data.deskripsi ?? ''); } - }, [tujuanEdukasiState.findById.data]) + }, [tujuanEdukasiState.findById.data]); const submit = () => { if (tujuanEdukasiState.findById.data) { tujuanEdukasiState.findById.data.judul = judul; tujuanEdukasiState.findById.data.deskripsi = content; - tujuanEdukasiState.update.save(tujuanEdukasiState.findById.data) + tujuanEdukasiState.update.save(tujuanEdukasiState.findById.data); } - router.push('/admin/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan') - } + router.push('/admin/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan'); + }; + return ( - - - - - - - - - Edit Tujuan Edukasi Lingkungan - Judul - - Content - - - - - - - - + + + + + Edit Tujuan Edukasi Lingkungan + + + + + + + + Judul + + + + + + + Konten + + + + + + + + + ); } diff --git a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan/page.tsx b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan/page.tsx index 5d983705..49fd7dd5 100644 --- a/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan/page.tsx @@ -1,5 +1,4 @@ 'use client' -import colors from '@/con/colors'; import { Box, Button, Grid, GridCol, Paper, Skeleton, Stack, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconEdit } from '@tabler/icons-react'; @@ -8,47 +7,68 @@ import { useProxy } from 'valtio/utils'; import stateEdukasiLingkungan from '../../../_state/lingkungan/edukasi-lingkungan'; function Page() { - const router = useRouter() - const listTujuanEdukasi = useProxy(stateEdukasiLingkungan.stateTujuanEdukasi) + const router = useRouter(); + const listTujuanEdukasi = useProxy(stateEdukasiLingkungan.stateTujuanEdukasi); + useShallowEffect(() => { - listTujuanEdukasi.findById.load('edit') - }, []) + listTujuanEdukasi.findById.load('edit'); + }, []); if (!listTujuanEdukasi.findById.data) { return ( - - + + - ) + ); } + return ( - - - + + + - Preview Tujuan Edukasi Lingkungan + Preview Tujuan Edukasi Lingkungan - - - - - - - - - - - - - - - - - ) + + + + + + + + + + + + + + ); } export default Page; diff --git a/src/app/admin/(dashboard)/lingkungan/gotong-royong/_lib/layoutTabs.tsx b/src/app/admin/(dashboard)/lingkungan/gotong-royong/_lib/layoutTabs.tsx index b9cb795c..d9aec0eb 100644 --- a/src/app/admin/(dashboard)/lingkungan/gotong-royong/_lib/layoutTabs.tsx +++ b/src/app/admin/(dashboard)/lingkungan/gotong-royong/_lib/layoutTabs.tsx @@ -1,62 +1,121 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core'; +import { ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title, Tooltip } from '@mantine/core'; import { usePathname, useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; +import { IconClipboardList, IconTags } from '@tabler/icons-react'; function LayoutTabs({ children }: { children: React.ReactNode }) { - const router = useRouter() - const pathname = usePathname() - const tabs = [ - { - label: "Kegiatan Desa", - value: "kegiatanDesa", - href: "/admin/lingkungan/gotong-royong/kegiatan-desa" - }, - { - label: "Kategori Kegiatan", - value: "kategoriKegiatan", - href: "/admin/lingkungan/gotong-royong/kategori-kegiatan" - }, - ]; - const curentTab = tabs.find(tab => tab.href === pathname) - const [activeTab, setActiveTab] = useState(curentTab?.value || tabs[0].value); + const router = useRouter(); + const pathname = usePathname(); - const handleTabChange = (value: string | null) => { - const tab = tabs.find(t => t.value === value) - if (tab) { - router.push(tab.href) - } - setActiveTab(value) + const tabs = [ + { + label: "Kegiatan Desa", + value: "kegiatanDesa", + href: "/admin/lingkungan/gotong-royong/kegiatan-desa", + icon: , + tooltip: "Lihat dan kelola kegiatan desa", + }, + { + label: "Kategori Kegiatan", + value: "kategoriKegiatan", + href: "/admin/lingkungan/gotong-royong/kategori-kegiatan", + icon: , + tooltip: "Kelola kategori kegiatan desa", + }, + ]; + + const currentTab = tabs.find(tab => tab.href === pathname); + const [activeTab, setActiveTab] = useState(currentTab?.value || tabs[0].value); + + const handleTabChange = (value: string | null) => { + const tab = tabs.find(t => t.value === value); + if (tab) { + router.push(tab.href); } + setActiveTab(value); + }; - useEffect(() => { - const match = tabs.find(tab => tab.href === pathname) - if (match) { - setActiveTab(match.value) - } - }, [pathname]) + useEffect(() => { + const match = tabs.find(tab => tab.href === pathname); + if (match) { + setActiveTab(match.value); + } + }, [pathname]); - return ( - - Gotong Royong - - - {tabs.map((e, i) => ( - {e.label} - ))} - - {tabs.map((e, i) => ( - - {/* Konten dummy, bisa diganti tergantung routing */} - <> - - ))} - + return ( + + {/* ✅ Title lebih tegas */} + + Gotong Royong + + + + {/* ✅ Scroll horizontal */} + + + {tabs.map((tab, i) => ( + + + {tab.label} + + + ))} + + + + {/* ✅ Panel dengan gaya kartu */} + {tabs.map((tab, i) => ( + {children} - - ); + + ))} + + + ); } -export default LayoutTabs; \ No newline at end of file +export default LayoutTabs; diff --git a/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/[id]/page.tsx b/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/[id]/page.tsx index 3ef19b4f..f6b81aa7 100644 --- a/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/[id]/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/[id]/page.tsx @@ -2,7 +2,7 @@ 'use client' import gotongRoyongState from '@/app/admin/(dashboard)/_state/lingkungan/gotong-royong'; import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { Box, Button, Group, Paper, Stack, Text, TextInput, Title, Tooltip } from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; @@ -16,7 +16,7 @@ function EditKategoriKegiatan() { const stateKategori = useProxy(gotongRoyongState.kategoriKegiatan); const [formData, setFormData] = useState({ - nama: "", + nama: '', }); useEffect(() => { @@ -27,15 +27,14 @@ function EditKategoriKegiatan() { const data = await stateKategori.edit.load(id); if (data) { - // pastikan id-nya masuk ke state edit stateKategori.edit.id = id; setFormData({ nama: data.nama || '', }); } } catch (error) { - console.error("Error loading kategori kegiatan:", error); - toast.error("Gagal memuat data kategori kegiatan"); + console.error('Error loading kategori kegiatan:', error); + toast.error('Gagal memuat data kategori kegiatan'); } }; @@ -49,45 +48,63 @@ function EditKategoriKegiatan() { return; } - stateKategori.edit.form = { - nama: formData.nama.trim(), - }; - - // Safety check tambahan: pastikan ID tidak kosong - if (!stateKategori.edit.id) { - stateKategori.edit.id = id; // fallback - } + stateKategori.edit.form = { nama: formData.nama.trim() }; + if (!stateKategori.edit.id) stateKategori.edit.id = id; const success = await stateKategori.edit.update(); if (success) { - router.push("/admin/lingkungan/gotong-royong/kategori-kegiatan"); + toast.success('Kategori kegiatan berhasil diperbarui!'); + router.push('/admin/lingkungan/gotong-royong/kategori-kegiatan'); } } catch (error) { - console.error("Error updating kategori kegiatan:", error); - // toast akan ditampilkan dari fungsi update + console.error('Error updating kategori kegiatan:', error); } }; return ( - - - - + + + + + + + Edit Kategori Kegiatan + + - - - Edit Kategori kegiatan + + setFormData({ ...formData, nama: e.target.value })} - label={Nama Kategori kegiatan} - placeholder='Masukkan nama kategori kegiatan' + label={Nama Kategori Kegiatan} + placeholder="Masukkan nama kategori kegiatan" + required /> - - + + + diff --git a/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/create/page.tsx b/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/create/page.tsx index e87b3a78..3930a195 100644 --- a/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/create/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/create/page.tsx @@ -1,7 +1,7 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { Box, Button, Group, Paper, Stack, Text, TextInput, Title, Tooltip } from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useEffect } from 'react'; @@ -29,31 +29,53 @@ function CreateKategoriKegiatan() { } return ( - - - - - + + + Tambah Kategori Kegiatan + + - - - Create Kategori Kegiatan - { - stateKategori.create.form.nama = val.target.value; + {/* Form */} + + + (stateKategori.create.form.nama = val.target.value)} + label={Nama Kategori Kegiatan} + placeholder="Masukkan nama kategori kegiatan" + required + /> + + + - - - - + > + Simpan + + + + ); } diff --git a/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/page.tsx b/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/page.tsx index daf3fbd8..ff03a0e5 100644 --- a/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/gotong-royong/kategori-kegiatan/page.tsx @@ -1,24 +1,40 @@ 'use client' import colors from '@/con/colors'; -import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core'; +import { + Box, + Button, + Center, + Group, + Pagination, + Paper, + Skeleton, + Stack, + Table, + TableTbody, + TableTd, + TableTh, + TableThead, + TableTr, + Text, + Title, + Tooltip, +} from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconEdit, IconSearch, IconX } from '@tabler/icons-react'; +import { IconEdit, IconPlus, IconSearch, IconTrash } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '../../../_com/header'; -import JudulList from '../../../_com/judulList'; import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; import gotongRoyongState from '../../../_state/lingkungan/gotong-royong'; - function KategoriKegiatan() { const [search, setSearch] = useState("") return ( } value={search} onChange={(e) => setSearch(e.currentTarget.value)} @@ -34,6 +50,14 @@ function ListKategoriKegiatan({ search }: { search: string }) { const [selectedId, setSelectedId] = useState(null) const router = useRouter() + const { + data, + page, + totalPages, + loading, + load, + } = stateKategori.findMany + const handleHapus = () => { if (selectedId) { stateKategori.delete.byId(selectedId) @@ -43,61 +67,110 @@ function ListKategoriKegiatan({ search }: { search: string }) { } useShallowEffect(() => { - stateKategori.findMany.load() - }, []) + load(page, 10, search) + }, [page, search]) - const filteredData = (stateKategori.findMany.data || []).filter(item => { - const keyword = search.toLowerCase(); - return ( - item.nama.toLowerCase().includes(keyword) - ); - }); + const filteredData = data || [] - if (!stateKategori.findMany.data) { + if (loading || !data) { return ( - + ) } return ( - - -
- - - Nama Kategori - Edit - Delete - - - - {filteredData.map((item) => ( - - {item.nama} - - - - - - + + + Daftar Kategori Kegiatan + + + + + + +
+ + + Nama Kategori + Edit + Delete - ))} - -
+ + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( + + + {item.nama} + + + + + + + + + )) + ) : ( + + +
+ Tidak ada kategori kegiatan yang cocok +
+
+
+ )} +
+ +
+ +
+ { + load(newPage, 10); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + mt="md" + mb="md" + color="blue" + radius="md" + /> +
+ {/* Modal Konfirmasi Hapus */} - - - + + + + + + + Edit Kegiatan Desa + + - - - Edit Kegiatan Desa + + Judul Kegiatan Desa} placeholder="masukkan judul kegiatan desa" onChange={(e) => setFormData({ ...formData, judul: e.target.value })} + required /> Deskripsi Singkat Kegiatan Desa} placeholder="masukkan deskripsi singkat kegiatan desa" onChange={(e) => setFormData({ ...formData, deskripsiSingkat: e.target.value })} + required /> { - stateKegiatanDesa.create.form.kategoriKegiatanId = val ?? ""; - }} - label={Kategori Kegiatan} - placeholder="Pilih kategori produk" + onChange={(val) => (stateKegiatanDesa.create.form.kategoriKegiatanId = val ?? '')} data={ gotongRoyongState.kategoriKegiatan.findMany.data?.map((v) => ({ value: v.id, label: v.nama, })) || [] } + required /> - - + {/* Submit */} + + diff --git a/src/app/admin/(dashboard)/lingkungan/gotong-royong/kegiatan-desa/page.tsx b/src/app/admin/(dashboard)/lingkungan/gotong-royong/kegiatan-desa/page.tsx index a014029d..ab7b83f0 100644 --- a/src/app/admin/(dashboard)/lingkungan/gotong-royong/kegiatan-desa/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/gotong-royong/kegiatan-desa/page.tsx @@ -1,13 +1,29 @@ -/* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; -import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react'; +import { + Box, + Button, + Center, + Group, + 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'; -import HeaderSearch from '../../../_com/header'; -import JudulList from '../../../_com/judulList'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useProxy } from 'valtio/utils'; +import HeaderSearch from '../../../_com/header'; import gotongRoyongState from '../../../_state/lingkungan/gotong-royong'; function KegiatanDesa() { @@ -15,8 +31,8 @@ function KegiatanDesa() { return ( } value={search} onChange={(e) => setSearch(e.currentTarget.value)} @@ -27,71 +43,123 @@ function KegiatanDesa() { } function ListKegiatanDesa({ search }: { search: string }) { - const listState = useProxy(gotongRoyongState.kegiatanDesa) + const listState = useProxy(gotongRoyongState.kegiatanDesa); const router = useRouter(); - useEffect(() => { - listState.findMany.load() - }, []) - const filteredData = (listState.findMany.data || []).filter(item => { - const keyword = search.toLowerCase(); - return ( - item.judul.toLowerCase().includes(keyword) || - item.lokasi.toLowerCase().includes(keyword) || - item.kategoriKegiatan?.nama?.toLowerCase().includes(keyword) - ); - }); + const { + data, + page, + totalPages, + loading, + load, + } = listState.findMany; - if (!listState.findMany.data) { + useShallowEffect(() => { + load(page, 10, search) + }, [page, search]) + + const filteredData = data || [] + + if (loading || !data) { return ( - + - ) + ); } return ( - - - - - - - - Judul Kegiatan Desa - Kategori Kegiatan Desa - Lokasi Kegiatan Desa - Detail - - - - {filteredData.map((item) => ( + + + Daftar Kegiatan Desa + + + +
+ + + Judul + Kategori + Lokasi + Aksi + + + + {filteredData.length > 0 ? ( + filteredData.map((item) => ( - - {item.judul} - + + {item.judul} + - {item.kategoriKegiatan?.nama} - {item.lokasi} - - ))} - -
-
-
+ )) + ) : ( + + +
+ + Tidak ada kegiatan desa yang cocok dengan pencarian + +
+
+
+ )} + + +
+
+ { + load(newPage, 10); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }} + total={totalPages} + mt="md" + mb="md" + color="blue" + radius="md" + /> +
- ) + ); } export default KegiatanDesa; diff --git a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/_lib/layoutTabs.tsx b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/_lib/layoutTabs.tsx index 558de4a2..f391660c 100644 --- a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/_lib/layoutTabs.tsx +++ b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/_lib/layoutTabs.tsx @@ -1,67 +1,116 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core'; +import { Box, ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title, Tooltip } from '@mantine/core'; +import { IconBook, IconLeaf, IconSchool } from '@tabler/icons-react'; import { usePathname, useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; function LayoutTabs({ children }: { children: React.ReactNode }) { const router = useRouter() const pathname = usePathname() + const tabs = [ { label: "Filosofi Tri Hita", value: "filosofi-tri-hita", - href: "/admin/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana" + href: "/admin/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana", + tooltip: "Lihat filosofi Tri Hita Karana", + icon: }, { label: "Nilai Konservasi Adat", value: "nilai-konservasi-adat", - href: "/admin/lingkungan/konservasi-adat-bali/nilai-konservasi-adat" + href: "/admin/lingkungan/konservasi-adat-bali/nilai-konservasi-adat", + tooltip: "Kelola nilai konservasi adat", + icon: }, { label: "Bentuk Konservasi Berdasarkan Adat", value: "bentuk-konservasi-berdasarkan-adat", - href: "/admin/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat" + href: "/admin/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat", + tooltip: "Lihat bentuk konservasi berdasarkan adat", + icon: }, ]; - const curentTab = tabs.find(tab => tab.href === pathname) - const [activeTab, setActiveTab] = useState(curentTab?.value || tabs[0].value); + + const currentTab = tabs.find(tab => tab.href === pathname) + const [activeTab, setActiveTab] = useState(currentTab?.value || tabs[0].value); const handleTabChange = (value: string | null) => { const tab = tabs.find(t => t.value === value) - if (tab) { - router.push(tab.href) - } + if (tab) router.push(tab.href) setActiveTab(value) } useEffect(() => { const match = tabs.find(tab => tab.href === pathname) - if (match) { - setActiveTab(match.value) - } + if (match) setActiveTab(match.value) }, [pathname]) return ( - - Konservasi Adat Bali - - - {tabs.map((e, i) => ( - {e.label} - ))} - - {tabs.map((e, i) => ( - - {/* Konten dummy, bisa diganti tergantung routing */} - <> + + + Konservasi Adat Bali + + + + + + {tabs.map((tab, i) => ( + + + + {tab.label} + + + + ))} + + + + {tabs.map((tab, i) => ( + + + {children} + ))} - {children} ); } -export default LayoutTabs; \ No newline at end of file +export default LayoutTabs; diff --git a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat/edit/page.tsx index af38497f..4008f466 100644 --- a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat/edit/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat/edit/page.tsx @@ -9,77 +9,105 @@ import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; -const KonservasiAdatBaliTextEditor = dynamic(() => import('../../_lib/konservasiAdatBaliTextEditor').then(mod => mod.KonservasiAdatBaliTextEditor), { - ssr: false, -}); +const KonservasiAdatBaliTextEditor = dynamic( + () => import('../../_lib/konservasiAdatBaliTextEditor').then(mod => mod.KonservasiAdatBaliTextEditor), + { ssr: false } +); function EditBentukKonservasiBerdasarkanAdat() { - const router = useRouter() - const bentukKonservasiState = useProxy(stateKonservasiAdatBali.stateBentukKonservasiBerdasarkanAdat) + const router = useRouter(); + const bentukKonservasiState = useProxy(stateKonservasiAdatBali.stateBentukKonservasiBerdasarkanAdat); const [judul, setJudul] = useState(''); const [content, setContent] = useState(''); useShallowEffect(() => { if (!bentukKonservasiState.findById.data) { - bentukKonservasiState.findById.initialize(); // biar masuk ke `findFirst` route kamu + bentukKonservasiState.findById.initialize(); } }, []); useEffect(() => { if (bentukKonservasiState.findById.data) { - setJudul(bentukKonservasiState.findById.data.judul ?? '') - setContent(bentukKonservasiState.findById.data.deskripsi ?? '') + setJudul(bentukKonservasiState.findById.data.judul ?? ''); + setContent(bentukKonservasiState.findById.data.deskripsi ?? ''); } - }, [bentukKonservasiState.findById.data]) + }, [bentukKonservasiState.findById.data]); const submit = () => { if (bentukKonservasiState.findById.data) { bentukKonservasiState.findById.data.judul = judul; bentukKonservasiState.findById.data.deskripsi = content; - bentukKonservasiState.update.save(bentukKonservasiState.findById.data) + bentukKonservasiState.update.save(bentukKonservasiState.findById.data); } - router.push('/admin/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat') - } + router.push('/admin/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat'); + }; + return ( - - - - - - - - - Edit Bentuk Konservasi Berdasarkan Adat - Judul - - Content - - - - - - - - + + {/* Header */} + + + + Edit Bentuk Konservasi Berdasarkan Adat + + + + {/* Form Paper */} + + + + + Judul + + + + + + + Deskripsi + + + + + + + + + ); } diff --git a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat/page.tsx b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat/page.tsx index 6763cb25..a9b8330d 100644 --- a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/bentuk-konservasi-berdasarkan-adat/page.tsx @@ -8,47 +8,80 @@ import { useProxy } from 'valtio/utils'; import stateKonservasiAdatBali from '../../../_state/lingkungan/konservasi-adat-bali'; function Page() { - const router = useRouter() - const listBentukKonservasiBerdasarkanAdat = useProxy(stateKonservasiAdatBali.stateBentukKonservasiBerdasarkanAdat) + const router = useRouter(); + const listBentukKonservasiBerdasarkanAdat = useProxy( + stateKonservasiAdatBali.stateBentukKonservasiBerdasarkanAdat + ); + useShallowEffect(() => { - listBentukKonservasiBerdasarkanAdat.findById.load('edit') - }, []) + listBentukKonservasiBerdasarkanAdat.findById.load('edit'); + }, []); if (!listBentukKonservasiBerdasarkanAdat.findById.data) { return ( - - + + - ) + ); } + return ( - - - + + + {/* Header */} + - Preview Bentuk Konservasi Berdasarkan Adat + + Preview Bentuk Konservasi Berdasarkan Adat + - - - - - - - - - - - - - - - - - ) + + {/* Konten */} + + + + + + + + + + +
+
+ ); } export default Page; diff --git a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana/edit/page.tsx index a9053c11..0ec3cd14 100644 --- a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana/edit/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana/edit/page.tsx @@ -9,78 +9,108 @@ import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; - -const KonservasiAdatBaliTextEditor = dynamic(() => import('../../_lib/konservasiAdatBaliTextEditor').then(mod => mod.KonservasiAdatBaliTextEditor), { - ssr: false, -}); +const KonservasiAdatBaliTextEditor = dynamic( + () => + import('../../_lib/konservasiAdatBaliTextEditor').then( + (mod) => mod.KonservasiAdatBaliTextEditor + ), + { ssr: false } +); function EditFilosofiTriHitaKarana() { - const router = useRouter() - const filosofiTriHitaState = useProxy(stateKonservasiAdatBali.stateFilosofiTriHita) + const router = useRouter(); + const filosofiTriHitaState = useProxy(stateKonservasiAdatBali.stateFilosofiTriHita); const [judul, setJudul] = useState(''); const [content, setContent] = useState(''); useShallowEffect(() => { if (!filosofiTriHitaState.findById.data) { - filosofiTriHitaState.findById.initialize(); // biar masuk ke `findFirst` route kamu + filosofiTriHitaState.findById.initialize(); } }, []); useEffect(() => { if (filosofiTriHitaState.findById.data) { - setJudul(filosofiTriHitaState.findById.data.judul ?? '') - setContent(filosofiTriHitaState.findById.data.deskripsi ?? '') + setJudul(filosofiTriHitaState.findById.data.judul ?? ''); + setContent(filosofiTriHitaState.findById.data.deskripsi ?? ''); } - }, [filosofiTriHitaState.findById.data]) + }, [filosofiTriHitaState.findById.data]); const submit = () => { if (filosofiTriHitaState.findById.data) { filosofiTriHitaState.findById.data.judul = judul; filosofiTriHitaState.findById.data.deskripsi = content; - filosofiTriHitaState.update.save(filosofiTriHitaState.findById.data) + filosofiTriHitaState.update.save(filosofiTriHitaState.findById.data); } - router.push('/admin/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana') - } + router.push('/admin/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana'); + }; + return ( - - - - - - - - - Edit Filosofi Tri Hita Karana - Judul - - Content - - - - - - - - + + {/* Header */} + + + + Edit Filosofi Tri Hita Karana + + + + {/* Form Paper */} + + + + + Judul + + + + + + + Deskripsi + + + + + + + + + ); } diff --git a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana/page.tsx b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana/page.tsx index 65a8c1c0..559270c3 100644 --- a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/filosofi-tri-hita-karana/page.tsx @@ -1,5 +1,4 @@ 'use client' -import colors from '@/con/colors'; import { Box, Button, Grid, GridCol, Paper, Skeleton, Stack, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconEdit } from '@tabler/icons-react'; @@ -7,49 +6,73 @@ import { useRouter } from 'next/navigation'; import { useProxy } from 'valtio/utils'; import stateKonservasiAdatBali from '../../../_state/lingkungan/konservasi-adat-bali'; - function Page() { - const router = useRouter() - const listFilosofi = useProxy(stateKonservasiAdatBali.stateFilosofiTriHita) + const router = useRouter(); + const listFilosofi = useProxy(stateKonservasiAdatBali.stateFilosofiTriHita); + useShallowEffect(() => { - listFilosofi.findById.load('edit') - }, []) + listFilosofi.findById.load('edit'); + }, []); if (!listFilosofi.findById.data) { return ( - - + + - ) + ); } + return ( - - - + + + - Preview Filosofi Tri Hita Karana + + Preview Filosofi Tri Hita Karana + - - - - - - - - - - - - - - - - - ) + + + + + + + + + + + +
+
+ ); } export default Page; diff --git a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/nilai-konservasi-adat/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/nilai-konservasi-adat/edit/page.tsx index d0708a30..6f6271a8 100644 --- a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/nilai-konservasi-adat/edit/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/nilai-konservasi-adat/edit/page.tsx @@ -9,77 +9,105 @@ import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; -const KonservasiAdatBaliTextEditor = dynamic(() => import('../../_lib/konservasiAdatBaliTextEditor').then(mod => mod.KonservasiAdatBaliTextEditor), { - ssr: false, -}); +const KonservasiAdatBaliTextEditor = dynamic( + () => import('../../_lib/konservasiAdatBaliTextEditor').then(mod => mod.KonservasiAdatBaliTextEditor), + { ssr: false } +); function EditNilaiKonservasiAdat() { - const router = useRouter() - const nilaiKonservasiState = useProxy(stateKonservasiAdatBali.stateNilaiKonservasiAdat) + const router = useRouter(); + const nilaiKonservasiState = useProxy(stateKonservasiAdatBali.stateNilaiKonservasiAdat); const [judul, setJudul] = useState(''); const [content, setContent] = useState(''); useShallowEffect(() => { if (!nilaiKonservasiState.findById.data) { - nilaiKonservasiState.findById.initialize(); // biar masuk ke `findFirst` route kamu + nilaiKonservasiState.findById.initialize(); } }, []); useEffect(() => { if (nilaiKonservasiState.findById.data) { - setJudul(nilaiKonservasiState.findById.data.judul ?? '') - setContent(nilaiKonservasiState.findById.data.deskripsi ?? '') + setJudul(nilaiKonservasiState.findById.data.judul ?? ''); + setContent(nilaiKonservasiState.findById.data.deskripsi ?? ''); } - }, [nilaiKonservasiState.findById.data]) + }, [nilaiKonservasiState.findById.data]); const submit = () => { if (nilaiKonservasiState.findById.data) { nilaiKonservasiState.findById.data.judul = judul; nilaiKonservasiState.findById.data.deskripsi = content; - nilaiKonservasiState.update.save(nilaiKonservasiState.findById.data) + nilaiKonservasiState.update.save(nilaiKonservasiState.findById.data); } - router.push('/admin/lingkungan/konservasi-adat-bali/nilai-konservasi-adat') - } + router.push('/admin/lingkungan/konservasi-adat-bali/nilai-konservasi-adat'); + }; + return ( - - - - - - - - - Edit Nilai Konservasi Adat - Judul - - Content - - - - - - - - + + {/* Header */} + + + + Edit Nilai Konservasi Adat + + + + {/* Form Paper */} + + + + + Judul + + + + + + + Deskripsi + + + + + + + + + ); } diff --git a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/nilai-konservasi-adat/page.tsx b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/nilai-konservasi-adat/page.tsx index 22065533..644e8d90 100644 --- a/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/nilai-konservasi-adat/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/konservasi-adat-bali/nilai-konservasi-adat/page.tsx @@ -1,5 +1,4 @@ 'use client' -import colors from '@/con/colors'; import { Box, Button, Grid, GridCol, Paper, Skeleton, Stack, Text, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconEdit } from '@tabler/icons-react'; @@ -8,47 +7,70 @@ import { useProxy } from 'valtio/utils'; import stateKonservasiAdatBali from '../../../_state/lingkungan/konservasi-adat-bali'; function Page() { - const router = useRouter() - const listNilaiKonservasiAdat = useProxy(stateKonservasiAdatBali.stateNilaiKonservasiAdat) + const router = useRouter(); + const listNilaiKonservasiAdat = useProxy(stateKonservasiAdatBali.stateNilaiKonservasiAdat); + useShallowEffect(() => { - listNilaiKonservasiAdat.findById.load('edit') - }, []) + listNilaiKonservasiAdat.findById.load('edit'); + }, []); if (!listNilaiKonservasiAdat.findById.data) { return ( - - + + - ) + ); } + return ( - - - + + + - Preview Nilai Konservasi Adat + + Preview Nilai Konservasi Adat + - - - - - - - - - - - - - - - - - ) + + + + + + + + + + + +
+
+ ); } export default Page; diff --git a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/_lib/layoutTabs.tsx b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/_lib/layoutTabs.tsx index 775bb713..5ca918bf 100644 --- a/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/_lib/layoutTabs.tsx +++ b/src/app/admin/(dashboard)/lingkungan/pengelolaan-sampah-bank-sampah/_lib/layoutTabs.tsx @@ -2,8 +2,9 @@ 'use client' import { usePathname, useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; -import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title, Tooltip } from '@mantine/core'; +import { ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title, Tooltip } from '@mantine/core'; import { IconTrash, IconRecycle } from '@tabler/icons-react'; +import colors from '@/con/colors'; function LayoutTabsPengelolaanSampahBankSampah({ children }: { children: React.ReactNode }) { const router = useRouter(); @@ -45,49 +46,75 @@ function LayoutTabsPengelolaanSampahBankSampah({ children }: { children: React.R }, [pathname]); return ( - - Pengelolaan Sampah Bank Sampah - + + Pengelolaan Sampah Bank Sampah + + + - - {tabs.map((tab) => ( - - + + {tabs.map((tab, i) => ( + - {tab.label} - - - ))} - - - {children} - + + {tab.label} + + + ))} + + + + {tabs.map((tab, i) => ( + + {children} + + ))} ); } -export default LayoutTabsPengelolaanSampahBankSampah; \ No newline at end of file +export default LayoutTabsPengelolaanSampahBankSampah; diff --git a/src/app/admin/(dashboard)/lingkungan/program-penghijauan/[id]/edit/page.tsx b/src/app/admin/(dashboard)/lingkungan/program-penghijauan/[id]/edit/page.tsx index 7bd4ea37..274c1d16 100644 --- a/src/app/admin/(dashboard)/lingkungan/program-penghijauan/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/program-penghijauan/[id]/edit/page.tsx @@ -4,14 +4,23 @@ import EditEditor from '@/app/admin/(dashboard)/_com/editEditor'; import SelectIconProgramEdit from '@/app/admin/(dashboard)/_com/selectIconEdit'; import programPenghijauanState from '@/app/admin/(dashboard)/_state/lingkungan/program-penghijauan'; import colors from '@/con/colors'; -import { Box, Button, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + Text, + TextInput, + Title, + Tooltip, +} 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'; - interface FormProgramPenghijauan { name: string; deskripsi: string; @@ -19,19 +28,32 @@ interface FormProgramPenghijauan { icon: string; } -type IconKey = 'ekowisata' | 'kompetisi' | 'wisata' | 'ekonomi' | 'sampah' | 'truck' | 'scale' | 'clipboard' | 'trash' | 'lingkunganSehat' | 'sumberOksigen' | 'ekonomiBerkelanjutan' | 'mencegahBencana'; - +type IconKey = + | 'ekowisata' + | 'kompetisi' + | 'wisata' + | 'ekonomi' + | 'sampah' + | 'truck' + | 'scale' + | 'clipboard' + | 'trash' + | 'lingkunganSehat' + | 'sumberOksigen' + | 'ekonomiBerkelanjutan' + | 'mencegahBencana'; function EditProgramPenghijauan() { - const stateProgramPenghijauan = useProxy(programPenghijauanState) - const params = useParams() + const stateProgramPenghijauan = useProxy(programPenghijauanState); + const params = useParams(); const router = useRouter(); + const [formData, setFormData] = useState({ name: '', deskripsi: '', judul: '', icon: '', - }) + }); useEffect(() => { const loadProgramPenghijauan = async () => { @@ -41,7 +63,6 @@ function EditProgramPenghijauan() { try { const data = await stateProgramPenghijauan.update.load(id); if (data) { - // ⬇️ FIX PENTING: tambahkan ini stateProgramPenghijauan.update.id = id; stateProgramPenghijauan.update.form = { @@ -59,16 +80,14 @@ function EditProgramPenghijauan() { }); } } catch (error) { - console.error("Error loading program penghijauan:", error); - toast.error("Gagal memuat data program penghijauan"); + console.error('Error loading program penghijauan:', error); + toast.error('Gagal memuat data program penghijauan'); } - } + }; loadProgramPenghijauan(); }, [params?.id]); - - const handleSubmit = async () => { try { stateProgramPenghijauan.update.form = { @@ -77,49 +96,74 @@ function EditProgramPenghijauan() { deskripsi: formData.deskripsi.trim(), judul: formData.judul.trim(), icon: formData.icon.trim(), - } + }; await stateProgramPenghijauan.update.submit(); - router.push("/admin/lingkungan/program-penghijauan"); + router.push('/admin/lingkungan/program-penghijauan'); } catch (error) { - console.error("Error updating program penghijauan:", error); - toast.error("Gagal memuat data program penghijauan"); + console.error('Error updating program penghijauan:', error); + toast.error('Gagal memperbarui program penghijauan'); } - } - return ( - - - - + }; - - - Edit Program Penghijauan + return ( + + {/* Header dengan back button */} + + + + + + Edit Program Penghijauan + + + + {/* Card utama */} + + Nama Program Penghijauan} - placeholder="masukkan nama program penghijauan" - onChange={(val) => { + label="Nama Program Penghijauan" + placeholder="Masukkan nama program penghijauan" + onChange={(val) => setFormData({ ...formData, - name: val.target.value + name: val.target.value, }) - }} + } + required /> + Judul Deskripsi Program Penghijauan} - placeholder="masukkan judul deskripsi program penghijauan" - onChange={(val) => { + label="Judul Deskripsi Program Penghijauan" + placeholder="Masukkan judul deskripsi program penghijauan" + onChange={(val) => setFormData({ ...formData, - judul: val.target.value + judul: val.target.value, }) - }} + } + required /> + - Deskripsi + + Deskripsi + { @@ -128,16 +172,35 @@ function EditProgramPenghijauan() { }} /> + - Ikon Program Penghijauan + + Ikon Program Penghijauan + { setFormData((prev) => ({ ...prev, icon: value })); stateProgramPenghijauan.update.form.icon = value; - }} /> + }} + /> - + + {/* Tombol simpan */} + + + diff --git a/src/app/admin/(dashboard)/lingkungan/program-penghijauan/[id]/page.tsx b/src/app/admin/(dashboard)/lingkungan/program-penghijauan/[id]/page.tsx index 567b8388..44df2081 100644 --- a/src/app/admin/(dashboard)/lingkungan/program-penghijauan/[id]/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/program-penghijauan/[id]/page.tsx @@ -1,17 +1,20 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core'; +import { Box, Button, Group, Paper, Skeleton, Stack, Text, Tooltip } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; -import { IconArrowBack, IconChartLine, IconChristmasTreeFilled, IconClipboard, IconEdit, IconHomeEco, IconLeaf, IconRecycle, IconScale, IconShieldFilled, IconTent, IconTrash, IconTrendingUp, IconTrophy, IconTruck, IconX } from '@tabler/icons-react'; +import { + IconArrowBack, IconChartLine, IconChristmasTreeFilled, IconClipboard, + IconEdit, IconHomeEco, IconLeaf, IconRecycle, IconScale, + IconShieldFilled, IconTent, IconTrash, IconTrendingUp, + IconTrophy, IconTruck +} from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import React, { useState } from 'react'; import { useProxy } from 'valtio/utils'; import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; import programPenghijauanState from '../../../_state/lingkungan/program-penghijauan'; -// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; - function DetailProgramPenghijauan() { const [modalHapus, setModalHapus] = useState(false) const stateProgramPenghijauan = useProxy(programPenghijauanState) @@ -50,72 +53,97 @@ function DetailProgramPenghijauan() { if (!stateProgramPenghijauan.findUnique.data) { return ( - - + + ) } - return ( - - - - - - - Detail Program Penghijauan + const data = stateProgramPenghijauan.findUnique.data - - + return ( + + {/* Tombol kembali */} + + + {/* Konten detail */} + + + + Detail Program Penghijauan + + + + - Nama Program Penghijauan - {stateProgramPenghijauan.findUnique.data?.name} + Nama Program + {data?.name || '-'} + - Ikon Program Penghijauan - {iconMap[stateProgramPenghijauan.findUnique.data?.icon] && ( - - {React.createElement(iconMap[stateProgramPenghijauan.findUnique.data?.icon], { size: 24 })} + Ikon Program + {iconMap[data?.icon] ? ( + + {React.createElement(iconMap[data.icon], { size: 28, color: colors['blue-button'] })} + ) : ( + Tidak ada ikon )} + - Judul Deskripsi Program Penghijauan - {stateProgramPenghijauan.findUnique.data?.judul} + Judul Deskripsi + {data?.judul || '-'} + - Deskripsi Program Penghijauan - + Deskripsi + - - + + {/* Tombol aksi */} + + + + + - - + + @@ -126,7 +154,7 @@ function DetailProgramPenghijauan() { opened={modalHapus} onClose={() => setModalHapus(false)} onConfirm={handleHapus} - text="Apakah anda yakin ingin menghapus program penghijauan ini?" + text="Apakah Anda yakin ingin menghapus program penghijauan ini?" /> ); diff --git a/src/app/admin/(dashboard)/lingkungan/program-penghijauan/create/page.tsx b/src/app/admin/(dashboard)/lingkungan/program-penghijauan/create/page.tsx index 760f4c73..a787090d 100644 --- a/src/app/admin/(dashboard)/lingkungan/program-penghijauan/create/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/program-penghijauan/create/page.tsx @@ -1,6 +1,16 @@ -'use client' +'use client'; import colors from '@/con/colors'; -import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; +import { + Box, + Button, + Group, + Paper, + Stack, + Text, + TextInput, + Title, + Tooltip, +} from '@mantine/core'; import { IconArrowBack } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import { useProxy } from 'valtio/utils'; @@ -8,59 +18,104 @@ import CreateEditor from '../../../_com/createEditor'; import SelectIconProgram from '../../../_com/selectIcon'; import programPenghijauanState from '../../../_state/lingkungan/program-penghijauan'; - function CreateProgramPenghijauan() { - const stateCreate = useProxy(programPenghijauanState) + const stateCreate = useProxy(programPenghijauanState); const router = useRouter(); const resetForm = () => { stateCreate.create.form = { - name: "", - deskripsi: "", - judul: "", - icon: "", - } - } + name: '', + deskripsi: '', + judul: '', + icon: '', + }; + }; const handleSubmit = async () => { await stateCreate.create.create(); resetForm(); - router.push("/admin/lingkungan/program-penghijauan") - } - return ( - - - - + router.push('/admin/lingkungan/program-penghijauan'); + }; - - - Create Program Penghijauan + return ( + + {/* Tombol back + title */} + + + + + + Tambah Program Penghijauan + + + + {/* Form */} + + Nama Program Penghijauan} - placeholder="masukkan nama program penghijauan" - onChange={(val) => stateCreate.create.form.name = val.target.value} + label={Nama Program Penghijauan} + placeholder="Masukkan nama program penghijauan" + value={stateCreate.create.form.name || ''} + onChange={(e) => (stateCreate.create.form.name = e.target.value)} + required /> + - Ikon Program Penghijauan - stateCreate.create.form.icon = value} /> - - stateCreate.create.form.judul = e.currentTarget.value} - label={Judul Deskripsi Program Penghijauan} - placeholder='Masukkan judul deskripsi program penghijauan' - /> - - Deskripsi Program Penghijauan - stateCreate.create.form.deskripsi = htmlContent} + + Ikon Program Penghijauan + + (stateCreate.create.form.icon = value)} /> - - + + Judul Deskripsi Program Penghijauan} + placeholder="Masukkan judul deskripsi program penghijauan" + value={stateCreate.create.form.judul || ''} + onChange={(e) => (stateCreate.create.form.judul = e.target.value)} + required + /> + + + + Deskripsi Program Penghijauan + + + (stateCreate.create.form.deskripsi = htmlContent) + } + /> + + + + diff --git a/src/app/admin/(dashboard)/lingkungan/program-penghijauan/page.tsx b/src/app/admin/(dashboard)/lingkungan/program-penghijauan/page.tsx index dc1b4f7e..daa3a543 100644 --- a/src/app/admin/(dashboard)/lingkungan/program-penghijauan/page.tsx +++ b/src/app/admin/(dashboard)/lingkungan/program-penghijauan/page.tsx @@ -2,30 +2,55 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import colors from '@/con/colors'; -import { Box, Button, Center, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; import { - IconChartLine, IconChristmasTreeFilled, IconClipboardTextFilled, IconDeviceImac, IconHomeEco, IconLeaf, - IconRecycle, IconScale, IconSearch, IconShieldFilled, IconTent, + Box, + Button, + Center, + Pagination, + Paper, + Skeleton, + Stack, + Table, + TableTbody, + TableTd, + TableTh, + TableThead, + TableTr, + Text, + Title, + Tooltip +} from '@mantine/core'; +import { + IconChartLine, + IconChristmasTreeFilled, + IconClipboardTextFilled, + IconDeviceImac, + IconHomeEco, + IconLeaf, + IconRecycle, + IconScale, + IconSearch, + IconShieldFilled, + IconTent, IconTrashFilled, IconTrendingUp, IconTrophy, - IconTruckFilled + IconTruckFilled, + IconPlus, } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; import HeaderSearch from '../../_com/header'; -import JudulList from '../../_com/judulList'; import programPenghijauanState from '../../_state/lingkungan/program-penghijauan'; - function ProgramPenghijauan() { const [search, setSearch] = useState(""); return ( } value={search} onChange={(e) => setSearch(e.currentTarget.value)} @@ -41,18 +66,10 @@ function ListProgramPenghijauan({ search }: { search: string }) { const router = useRouter(); useEffect(() => { - load(page, 10) - }, [page]) + load(page, 10, search) + }, [page, search]) - const filteredData = (data || []).filter(item => { - const keyword = search.toLowerCase(); - return ( - item.name.toLowerCase().includes(keyword) || - item.deskripsi.toLowerCase().includes(keyword) || - item.judul.toLowerCase().includes(keyword) || - item.icon.toLowerCase().includes(keyword) - ); - }); + const filteredData = data || [] const iconMap: Record> = { ekowisata: IconLeaf, @@ -73,93 +90,104 @@ function ListProgramPenghijauan({ search }: { search: string }) { if (loading || !data) { return ( - + ); } - if (data.length === 0) { - return ( - - - - - - - - No - Nama Program Penghijauan - Judul Deskripsi Program Penghijauan - Ikon - Detail - - -
- Tidak ada data program penghijauan yang tersedia -
-
-
- ); - } + return ( - - - - + + {/* Header Section */} + + Daftar Program Penghijauan + + + + + + {/* Table Section */} + +
No - Nama Program Penghijauan - Judul Deskripsi Program Penghijauan - Ikon - Detail + Nama Program + Judul / Deskripsi + Ikon + Aksi - {filteredData.map((item, index) => ( - - {index + 1} - {item.name} - - - - - {iconMap[item.icon] && ( - - {React.createElement(iconMap[item.icon], { size: 24 })} - - )} - - - + {filteredData.length > 0 ? ( + filteredData.map((item, index) => ( + + {index + 1} + + {item.name} + + + + + + {iconMap[item.icon] && ( + + {React.createElement(iconMap[item.icon], { size: 22 })} + + )} + + + + + + )) + ) : ( + + +
+ Tidak ada data program penghijauan yang cocok +
- ))} + )}
+ + {/* Pagination */}
{ load(newPage, 10); - window.scrollTo(0, 0); + window.scrollTo({ top: 0, behavior: 'smooth' }); }} total={totalPages} mt="md" mb="md" + color="blue" + radius="md" />
); } + export default ProgramPenghijauan; diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/kategori-kegiatan/findMany.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/kategori-kegiatan/findMany.ts index 18fc7787..bb2fe7e7 100644 --- a/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/kategori-kegiatan/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/kategori-kegiatan/findMany.ts @@ -1,15 +1,53 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import prisma from "@/lib/prisma"; +import { Context } from "elysia"; -export default async function kategoriKegiatanFindMany() { - const data = await prisma.kategoriKegiatan.findMany(); - return { - success: true, - data: data.map((item: any) => { - return { - id: item.id, - nama: item.nama, - } - }), +export default async function kategoriKegiatanFindMany(context: Context) { + const page = Number(context.query.page) || 1; + const limit = Number(context.query.limit) || 10; + const search = (context.query.search as string) || ""; + const skip = (page - 1) * limit; + + // Buat where clause + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [{ nama: { contains: search, mode: "insensitive" } }]; + } + + try { + const [data, total] = await Promise.all([ + prisma.kategoriKegiatan.findMany({ + where: where, + skip, + take: limit, + orderBy: { createdAt: "desc" }, + }), + prisma.kategoriKegiatan.count({ + where: where, + }), + ]); + + return { + success: true, + data: data.map((item: any) => { + return { + id: item.id, + nama: item.nama, + }; + }), + message: "Success fetch administrasi online with pagination", + page, + limit, + totalPages: Math.ceil(total / limit), + total, }; -} \ No newline at end of file + } catch (e) { + console.error("Find many paginated error:", e); + return { + success: false, + message: "Failed fetch administrasi online with pagination", + }; + } +} diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findMany.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findMany.ts index 366d0f4d..8d500a34 100644 --- a/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/pengelolaan-sampah/findMany.ts @@ -24,7 +24,7 @@ export default async function pengelolaanSampahFindMany(context: Context) { where, skip, take: limit, - orderBy: { createdAt: 'desc' }, + orderBy: { createdAt: 'asc' }, }), prisma.pengelolaanSampah.count({ where, diff --git a/src/app/coba/page.tsx b/src/app/coba/page.tsx index cade1983..903aa6fe 100644 --- a/src/app/coba/page.tsx +++ b/src/app/coba/page.tsx @@ -1,105 +1,83 @@ import colors from '@/con/colors'; -import { Box, Center, Image, List, ListItem, Paper, SimpleGrid, Stack, Text } from '@mantine/core'; -import BackButton from '../darmasaba/(pages)/desa/layanan/_com/BackButto'; +import { Stack, Box, Container, Grid, GridCol, Group, Paper, TextInput, Text, Image, Flex, Button } from '@mantine/core'; +import { IconCalendar, IconMapPin, IconSearch, IconUsersGroup } from '@tabler/icons-react'; +import React from 'react'; - -const data1 = [ - { - id: 1, - judul: 'Peran Pecalang dalam Keamanan Desa', - image: '/api/img/pecalang.png', - pengertian: 'Pecalang adalah petugas keamanan adat di Bali yang memiliki peran penting dalam menjaga ketertiban dan budaya lokal. Tugas mereka meliputi:', - deskripsi: - Mengamankan upacara adat dan kegiatan keagamaan. - Mengatur lalu lintas saat ada perayaan atau kegiatan besar. - Berpatroli untuk mencegah gangguan keamanan di lingkungan desa. - Berkoordinasi dengan aparat desa dan kepolisian dalam penanganan situasi darurat. - - }, - { - id: 2, - judul: 'Patwal (Patroli Pengawal) Desa', - image: '/api/img/patwal-1.png', - pengertian: 'Selain Pecalang, Desa Darmasaba juga memiliki Patwal yang bertugas menjaga keamanan sehari-hari. Peran mereka antara lain:', - deskripsi: - Berpatroli secara rutin untuk memastikan lingkungan tetap aman. - Menjaga ketertiban lalu lintas di area desa. - Melakukan tindakan preventif terhadap potensi gangguan keamanan. - Siap siaga dalam keadaan darurat untuk membantu warga. - - }, - { - id: 3, - judul: 'Layanan Keamanan yang Tersedia', - image: '/api/img/pospecalang.png', - pengertian: 'Jika terjadi keadaan darurat atau membutuhkan bantuan keamanan, warga dapat menghubungi:', - deskripsi: - Pos Pecalang Desa: [Masukkan Nomor Kontak]. - Patwal Desa Darmasaba: [Masukkan Nomor Kontak]. - Polsek Terdekat: 110 (Layanan Kepolisian). - - }, - { - id: 4, - judul: 'Program Keamanan Desa', - image: '/api/img/rond.png', - pengertian: 'Untuk meningkatkan keamanan, Desa Darmasaba menjalankan berbagai program, seperti:', - deskripsi: - Ronda Malam Warga: Kegiatan jaga malam secara bergilir oleh warga bersama Pecalang dan Patwal. - Sosialisasi Keamanan: Edukasi bagi warga tentang cara menjaga keamanan lingkungan. - Pengawasan Kamera CCTV: Memantau titik- titik strategis untuk mencegah tindak kejahatan. - - } -] +import Link from 'next/link'; function Page() { return ( - - - - - - - Keamanan Lingkungan (Pecalang / Patwal) - - - Keamanan dan ketertiban lingkungan di Desa Darmasaba dijaga melalui peran aktif Pecalang dan Patwal (Patroli Pengawal). Mereka bertugas memastikan desa tetap aman, tertib, dan kondusif bagi seluruh warga. - - - - - - {data1.map((v, k) => { - return ( - - -
- -
- - - - {v.judul} - - - {v.pengertian} - - - {v.deskripsi} - - - -
-
- ) - })} -
+ + {/* Header */} + + + + Program Gotong Royong + + + Desa Darmasaba + + + + {/* Tabs Menu */} + + + + + + + Semua + + + {['Kebersihan', 'Infrastruktur', 'Sosial', 'Lingkungan'].map((kategori) => ( + + + {kategori} + + + ))} + + + + } + w="100%" + /> + + + + + + Membangun Fasilitas Desa + + + Sosial + + + + Program Pembangunan Fasilitas Desa Maju, Masyarakat Sejahtera. + + + + 1 April 2025 + + + + Banjar Desa Darmasaba + + + + 30 Partisipan + + Deskripsi : Program pembangunan Pura sebagai pusat spiritual dan budaya desa, melibatkan gotong royong masyarakat dalam pembangunan struktur utama serta ornamen tradisional. + + + + + ); diff --git a/src/app/darmasaba/(pages)/inovasi/kolaborasi-inovasi/page.tsx b/src/app/darmasaba/(pages)/inovasi/kolaborasi-inovasi/page.tsx index 3863bf09..d7ff33fa 100644 --- a/src/app/darmasaba/(pages)/inovasi/kolaborasi-inovasi/page.tsx +++ b/src/app/darmasaba/(pages)/inovasi/kolaborasi-inovasi/page.tsx @@ -1,67 +1,76 @@ 'use client' import kolaborasiInovasiState from '@/app/admin/(dashboard)/_state/inovasi/kolaborasi-inovasi'; +import mitraKolaborasi from '@/app/admin/(dashboard)/_state/inovasi/mitra-kolaborasi'; import colors from '@/con/colors'; -import { Box, Center, Grid, GridCol, Group, Image, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core'; +import { + Box, + Center, + Grid, + GridCol, + Group, + Image, + Pagination, + Paper, + Select, + SimpleGrid, + Skeleton, + Stack, + Text, + TextInput +} from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { IconSearch } from '@tabler/icons-react'; import { useState } from 'react'; import { useProxy } from 'valtio/utils'; import BackButton from '../../desa/layanan/_com/BackButto'; + function Page() { - const state = useProxy(kolaborasiInovasiState) + const kolabState = useProxy(kolaborasiInovasiState) + const mitraState = useProxy(mitraKolaborasi) + const [search, setSearch] = useState(''); const [selectedYear, setSelectedYear] = useState(null); - // Get unique years from the data + // Get unique years from kolaborasiInovasi data const years = Array.from( new Set( - state.findMany.data?.map(item => + kolabState.findMany.data?.map(item => new Date(item.createdAt).getFullYear().toString() ) || [] ) ) - .sort((a, b) => b.localeCompare(a)) // Sort descending (newest first) - .map(year => ({ - value: year, - label: year, - })); + .sort((a, b) => b.localeCompare(a)) + .map(year => ({ value: year, label: year })); - const { - data, - page, - totalPages, - loading, - load, - } = state.findMany + const { data, page, totalPages, loading, load } = kolabState.findMany; useShallowEffect(() => { - load(page, 10, search, selectedYear || '') - }, [page, search, selectedYear]) + mitraState.findMany.load(page, 10); + load(page, 10, search, selectedYear || ''); + }, [page, search, selectedYear]); + + const mitraData = mitraState.findMany.data || []; + const mitraLoading = mitraState.findMany.loading; - if (loading || !data) { - return ( - - - - ); - } return ( <> - + + + {/* Header Kolaborasi Inovasi */} - + Kolaborasi Inovasi setSearch(e.target.value)} @@ -71,40 +80,43 @@ function Page() { + + {/* Filter Tahun */} - - + +