diff --git a/src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts b/src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts index d3b6d99d..5e618388 100644 --- a/src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts +++ b/src/app/admin/(dashboard)/_state/lingkungan/gotong-royong.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import ApiFetch from "@/lib/api-fetch"; import { Prisma } from "@prisma/client"; import { toast } from "react-toastify"; @@ -67,10 +68,46 @@ const kegiatanDesa = proxy({ }; }> > | null, - async load() { - const res = await ApiFetch.api.lingkungan.kegiatandesa["find-many"].get(); - if (res.status === 200) { - kegiatanDesa.findMany.data = res.data?.data ?? []; + page: 1, + totalPages: 1, + total: 0, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "", kategori = "") => { + // Change to arrow function + kegiatanDesa.findMany.loading = true; // Use the full path to access the property + kegiatanDesa.findMany.page = page; + kegiatanDesa.findMany.search = search; + try { + const query: any = { page, limit }; + if (search) query.search = search; + if (kategori) query.kategori = kategori; + const res = await ApiFetch.api.lingkungan.kegiatandesa[ + "find-many" + ].get({ + query, + }); + + if (res.status === 200 && res.data?.success) { + kegiatanDesa.findMany.data = res.data.data || []; + kegiatanDesa.findMany.total = res.data.total || 0; + kegiatanDesa.findMany.totalPages = res.data.totalPages || 1; + } else { + console.error( + "Failed to load kegiatan desa:", + res.data?.message + ); + kegiatanDesa.findMany.data = []; + kegiatanDesa.findMany.total = 0; + kegiatanDesa.findMany.totalPages = 1; + } + } catch (error) { + console.error("Error loading kegiatan desa:", error); + kegiatanDesa.findMany.data = []; + kegiatanDesa.findMany.total = 0; + kegiatanDesa.findMany.totalPages = 1; + } finally { + kegiatanDesa.findMany.loading = false; } }, }, @@ -244,6 +281,35 @@ const kegiatanDesa = proxy({ kegiatanDesa.edit.form = { ...defaultKegiatanDesaForm }; }, }, + findFirst: { + data: null as Prisma.KegiatanDesaGetPayload<{ + include: { + image: true; + kategoriKegiatan: true; + }; + }> | null, + loading: false, + // findFirst.load() + async load(kategori?: string) { + this.loading = true; + try { + const res = await ApiFetch.api.lingkungan.kegiatandesa["find-first"].get({ + query: kategori ? { kategori } : {}, + }); + + if (res.status === 200 && res.data?.success) { + this.data = res.data.data || null; + } else { + this.data = null; + } + } catch (err) { + console.error("Gagal fetch kegiatan desa terbaru:", err); + this.data = null; + } finally { + this.loading = false; + } + }, + }, }); // ========================================= KATEGORI kegiatan ========================================= // @@ -269,9 +335,7 @@ const kategoriKegiatan = proxy({ } try { kategoriKegiatan.create.loading = true; - const res = await ApiFetch.api.lingkungan.kategorikegiatan[ - "create" - ].post(kategoriKegiatan.create.form); + const res = await ApiFetch.api.lingkungan.kategorikegiatan["create"].post(kategoriKegiatan.create.form); if (res.status === 200) { kategoriKegiatan.findMany.load(); return toast.success("Data berhasil ditambahkan"); @@ -305,9 +369,7 @@ const kategoriKegiatan = proxy({ }> | null, async load(id: string) { try { - const res = await fetch( - `/api/lingkungan/kategorikegiatan/${id}` - ); + const res = await fetch(`/api/lingkungan/kategorikegiatan/${id}`); if (res.ok) { const data = await res.json(); kategoriKegiatan.findUnique.data = data.data ?? null; @@ -367,15 +429,12 @@ const kategoriKegiatan = proxy({ } try { - const response = await fetch( - `/api/lingkungan/kategorikegiatan/${id}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await fetch(`/api/lingkungan/kategorikegiatan/${id}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } diff --git a/src/app/admin/(dashboard)/_state/pendidikan/info-sekolah-paud.ts b/src/app/admin/(dashboard)/_state/pendidikan/info-sekolah-paud.ts index c0bd624f..a96f7b1f 100644 --- a/src/app/admin/(dashboard)/_state/pendidikan/info-sekolah-paud.ts +++ b/src/app/admin/(dashboard)/_state/pendidikan/info-sekolah-paud.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import ApiFetch from "@/lib/api-fetch"; import { Prisma } from "@prisma/client"; import { toast } from "react-toastify"; @@ -51,13 +52,46 @@ const jenjangPendidikan = proxy({ id: string; nama: string; }> | null, - async load() { - const res = - await ApiFetch.api.pendidikan.infosekolahpaud.jenjangpendidikan[ - "find-many" - ].get(); - if (res.status === 200) { - jenjangPendidikan.findMany.data = res.data?.data ?? []; + page: 1, + totalPages: 1, + total: 0, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + // Change to arrow function + jenjangPendidikan.findMany.loading = true; // Use the full path to access the property + jenjangPendidikan.findMany.page = page; + jenjangPendidikan.findMany.search = search; + try { + const query: any = { page, limit }; + if (search) query.search = search; + const res = + await ApiFetch.api.pendidikan.infosekolahpaud.jenjangpendidikan[ + "find-many" + ].get({ + query, + }); + + if (res.status === 200 && res.data?.success) { + jenjangPendidikan.findMany.data = res.data.data || []; + jenjangPendidikan.findMany.total = res.data.total || 0; + jenjangPendidikan.findMany.totalPages = res.data.totalPages || 1; + } else { + console.error( + "Failed to load jenjang pendidikan:", + res.data?.message + ); + jenjangPendidikan.findMany.data = []; + jenjangPendidikan.findMany.total = 0; + jenjangPendidikan.findMany.totalPages = 1; + } + } catch (error) { + console.error("Error loading jenjang pendidikan:", error); + jenjangPendidikan.findMany.data = []; + jenjangPendidikan.findMany.total = 0; + jenjangPendidikan.findMany.totalPages = 1; + } finally { + jenjangPendidikan.findMany.loading = false; } }, }, @@ -304,13 +338,46 @@ const lembagaPendidikan = proxy({ }; }> > | null, - async load() { - const res = - await ApiFetch.api.pendidikan.infosekolahpaud.lembagapendidikan[ - "find-many" - ].get(); - if (res.status === 200) { - lembagaPendidikan.findMany.data = res.data?.data ?? []; + page: 1, + totalPages: 1, + total: 0, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + // Change to arrow function + lembagaPendidikan.findMany.loading = true; // Use the full path to access the property + lembagaPendidikan.findMany.page = page; + lembagaPendidikan.findMany.search = search; + try { + const query: any = { page, limit }; + if (search) query.search = search; + const res = + await ApiFetch.api.pendidikan.infosekolahpaud.lembagapendidikan[ + "find-many" + ].get({ + query, + }); + + if (res.status === 200 && res.data?.success) { + lembagaPendidikan.findMany.data = res.data.data || []; + lembagaPendidikan.findMany.total = res.data.total || 0; + lembagaPendidikan.findMany.totalPages = res.data.totalPages || 1; + } else { + console.error( + "Failed to load lembaga pendidikan:", + res.data?.message + ); + lembagaPendidikan.findMany.data = []; + lembagaPendidikan.findMany.total = 0; + lembagaPendidikan.findMany.totalPages = 1; + } + } catch (error) { + console.error("Error loading lembaga pendidikan:", error); + lembagaPendidikan.findMany.data = []; + lembagaPendidikan.findMany.total = 0; + lembagaPendidikan.findMany.totalPages = 1; + } finally { + lembagaPendidikan.findMany.loading = false; } }, }, @@ -558,12 +625,45 @@ const siswa = proxy({ }; }> > | null, - async load() { - const res = await ApiFetch.api.pendidikan.infosekolahpaud.siswa[ - "find-many" - ].get(); - if (res.status === 200) { - siswa.findMany.data = res.data?.data ?? []; + page: 1, + totalPages: 1, + total: 0, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + // Change to arrow function + siswa.findMany.loading = true; // Use the full path to access the property + siswa.findMany.page = page; + siswa.findMany.search = search; + try { + const query: any = { page, limit }; + if (search) query.search = search; + const res = await ApiFetch.api.pendidikan.infosekolahpaud.siswa[ + "find-many" + ].get({ + query, + }); + + if (res.status === 200 && res.data?.success) { + siswa.findMany.data = res.data.data || []; + siswa.findMany.total = res.data.total || 0; + siswa.findMany.totalPages = res.data.totalPages || 1; + } else { + console.error( + "Failed to load siswa:", + res.data?.message + ); + siswa.findMany.data = []; + siswa.findMany.total = 0; + siswa.findMany.totalPages = 1; + } + } catch (error) { + console.error("Error loading siswa:", error); + siswa.findMany.data = []; + siswa.findMany.total = 0; + siswa.findMany.totalPages = 1; + } finally { + siswa.findMany.loading = false; } }, }, @@ -798,12 +898,45 @@ const pengajar = proxy({ }; }> > | null, - async load() { - const res = await ApiFetch.api.pendidikan.infosekolahpaud.pengajar[ - "find-many" - ].get(); - if (res.status === 200) { - pengajar.findMany.data = res.data?.data ?? []; + page: 1, + totalPages: 1, + total: 0, + loading: false, + search: "", + load: async (page = 1, limit = 10, search = "") => { + // Change to arrow function + pengajar.findMany.loading = true; // Use the full path to access the property + pengajar.findMany.page = page; + pengajar.findMany.search = search; + try { + const query: any = { page, limit }; + if (search) query.search = search; + const res = await ApiFetch.api.pendidikan.infosekolahpaud.pengajar[ + "find-many" + ].get({ + query, + }); + + if (res.status === 200 && res.data?.success) { + pengajar.findMany.data = res.data.data || []; + pengajar.findMany.total = res.data.total || 0; + pengajar.findMany.totalPages = res.data.totalPages || 1; + } else { + console.error( + "Failed to load pengajar:", + res.data?.message + ); + pengajar.findMany.data = []; + pengajar.findMany.total = 0; + pengajar.findMany.totalPages = 1; + } + } catch (error) { + console.error("Error loading pengajar:", error); + pengajar.findMany.data = []; + pengajar.findMany.total = 0; + pengajar.findMany.totalPages = 1; + } finally { + pengajar.findMany.loading = false; } }, }, @@ -815,7 +948,9 @@ const pengajar = proxy({ }> | null, async load(id: string) { try { - const res = await fetch(`/api/pendidikan/infosekolahpaud/pengajar/${id}`); + const res = await fetch( + `/api/pendidikan/infosekolahpaud/pengajar/${id}` + ); if (res.ok) { const data = await res.json(); pengajar.findUnique.data = data.data ?? null; @@ -948,7 +1083,8 @@ const pengajar = proxy({ result ); throw new Error( - result?.message || `Gagal mengupdate pengajar (${response.status})` + result?.message || + `Gagal mengupdate pengajar (${response.status})` ); } diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/findFirst.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/findFirst.ts new file mode 100644 index 00000000..2d9a19f7 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/findFirst.ts @@ -0,0 +1,38 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import prisma from "@/lib/prisma"; +import { Context } from "elysia"; + +export default async function KegiatanDesaFindFirst(context: Context) { + const kategori = (context.query.kategori as string) || ''; + + const where: any = { isActive: true }; + + if (kategori) { + where.kategoriKegiatan = { + name: { equals: kategori, mode: 'insensitive' } + }; + } + + try { + const data = await prisma.kegiatanDesa.findFirst({ + where, + include: { + image: true, + kategoriKegiatan: true, + }, + orderBy: { createdAt: 'desc' }, + }); + + return { + success: true, + message: "Berhasil ambil gotong royong terbaru", + data, + }; + } catch (error) { + console.error('Error di findFirst:', error); + return { + success: false, + message: 'Gagal memuat gotong royong terbaru', + }; + } +} diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/findMany.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/findMany.ts index 58a29693..45cfd12f 100644 --- a/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/findMany.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ // /api/berita/findManyPaginated.ts import prisma from "@/lib/prisma"; import { Context } from "elysia"; @@ -5,12 +6,38 @@ import { Context } from "elysia"; async function kegiatanDesaFindMany(context: Context) { const page = Number(context.query.page) || 1; const limit = Number(context.query.limit) || 10; + const search = (context.query.search as string) || ''; + const kategori = (context.query.kategori as string) || ''; // 🔥 Parameter kategori baru const skip = (page - 1) * limit; + // Buat where clause + const where: any = { isActive: true }; + + // Filter berdasarkan kategori (jika ada) + if (kategori) { + where.kategoriKegiatan = { + nama: { + equals: kategori, + mode: 'insensitive' // Tidak case-sensitive + } + }; + } + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [ + { judul: { contains: search, mode: 'insensitive' } }, + { deskripsiSingkat: { contains: search, mode: 'insensitive' } }, + { deskripsiLengkap: { contains: search, mode: 'insensitive' } }, + { kategoriKegiatan: { nama: { contains: search, mode: 'insensitive' } } } + ]; + } + + try { const [data, total] = await Promise.all([ prisma.kegiatanDesa.findMany({ - where: { isActive: true }, + where, include: { kategoriKegiatan: true, image: true, @@ -20,7 +47,7 @@ async function kegiatanDesaFindMany(context: Context) { orderBy: { createdAt: 'desc' }, // opsional, kalau mau urut berdasarkan waktu }), prisma.kegiatanDesa.count({ - where: { isActive: true } + where, }) ]); diff --git a/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/index.ts b/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/index.ts index ee52858b..4b0f66ba 100644 --- a/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/index.ts +++ b/src/app/api/[[...slugs]]/_lib/lingkungan/gotong-royong/index.ts @@ -4,6 +4,7 @@ import KegiatanDesaDelete from "./del"; import KegiatanDesaFindMany from "./findMany"; import KegiatanDesaFindUnique from "./findUnique"; import KegiatanDesaUpdate from "./updt"; +import KegiatanDesaFindFirst from "./findFirst"; const KegiatanDesa = new Elysia({ prefix: "/kegiatandesa", @@ -16,6 +17,9 @@ const KegiatanDesa = new Elysia({ // ✅ Find by ID .get("/:id", KegiatanDesaFindUnique) + // ✅ Find First + .get("/find-first", KegiatanDesaFindFirst) + // ✅ Create .post("/create", KegiatanDesaCreate, { body: t.Object({ diff --git a/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/jenjang-pendidikan/findMany.ts b/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/jenjang-pendidikan/findMany.ts index c8733fe0..8d9c3c7c 100644 --- a/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/jenjang-pendidikan/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/jenjang-pendidikan/findMany.ts @@ -1,15 +1,56 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import prisma from "@/lib/prisma"; +import { Context } from "elysia"; -export default async function jenjangPendidikanFindMany() { - const data = await prisma.jenjangPendidikan.findMany(); - return { - success: true, - data: data.map((item: any) => { - return { - id: item.id, - nama: item.nama, - } - }), +export default async function jenjangPendidikanFindMany(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" } }, + { lembagas: { contains: search, mode: "insensitive" } }, + ]; + } + + try { + // Ambil data dan total count secara paralel + const [data, total] = await Promise.all([ + prisma.jenjangPendidikan.findMany({ + where, + skip, + take: limit, + orderBy: { createdAt: "desc" }, + }), + prisma.jenjangPendidikan.count({ where }), + ]); + + return { + success: true, + message: "Berhasil ambil jenjang pendidikan dengan pagination", + data: data.map((item: any) => { + return { + id: item.id, + nama: item.nama, + lembagas: item.lembagas, + }; + }), + page, + limit, + total, + totalPages: Math.ceil(total / limit), }; -} \ No newline at end of file + } catch (e) { + console.error("Error di findMany paginated:", e); + return { + success: false, + message: "Gagal mengambil data jenjang pendidikan", + }; + } +} diff --git a/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/lembaga/findMany.ts b/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/lembaga/findMany.ts index 6e37a51b..78f63089 100644 --- a/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/lembaga/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/lembaga/findMany.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ // /api/berita/findManyPaginated.ts import prisma from "@/lib/prisma"; import { Context } from "elysia"; @@ -5,12 +6,26 @@ import { Context } from "elysia"; async function lembagaPendidikanFindMany(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" } }, + { siswa: { contains: search, mode: "insensitive" } }, + { pengajar: { contains: search, mode: "insensitive" } }, + { jenjangPendidikan: { contains: search, mode: "insensitive" } }, + ]; + } + try { const [data, total] = await Promise.all([ prisma.lembaga.findMany({ - where: { isActive: true }, + where, include: { jenjangPendidikan: true, siswa: true, @@ -20,8 +35,8 @@ async function lembagaPendidikanFindMany(context: Context) { take: limit, orderBy: { createdAt: 'desc' }, // opsional, kalau mau urut berdasarkan waktu }), - prisma.kegiatanDesa.count({ - where: { isActive: true } + prisma.lembaga.count({ + where, }) ]); @@ -30,6 +45,7 @@ async function lembagaPendidikanFindMany(context: Context) { message: "Success fetch lembaga pendidikan with pagination", data, page, + limit, totalPages: Math.ceil(total / limit), total, }; diff --git a/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/pengajar/findMany.ts b/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/pengajar/findMany.ts index e1f99710..d5232b7c 100644 --- a/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/pengajar/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/pengajar/findMany.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ // /api/berita/findManyPaginated.ts import prisma from "@/lib/prisma"; import { Context } from "elysia"; @@ -6,11 +7,23 @@ async function pengajarFindMany(context: Context) { const page = Number(context.query.page) || 1; const limit = Number(context.query.limit) || 10; const skip = (page - 1) * limit; + const search = (context.query.search as string) || ""; + + // Buat where clause + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [ + { nama: { contains: search, mode: "insensitive" } }, + { lembaga: { contains: search, mode: "insensitive" } }, + ]; + } try { const [data, total] = await Promise.all([ prisma.pengajar.findMany({ - where: { isActive: true }, + where, include: { lembaga: true, }, @@ -19,7 +32,7 @@ async function pengajarFindMany(context: Context) { orderBy: { createdAt: 'desc' }, // opsional, kalau mau urut berdasarkan waktu }), prisma.pengajar.count({ - where: { isActive: true } + where, }) ]); @@ -28,6 +41,7 @@ async function pengajarFindMany(context: Context) { message: "Success fetch pengajar with pagination", data, page, + limit, totalPages: Math.ceil(total / limit), total, }; diff --git a/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/siswa/findMany.ts b/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/siswa/findMany.ts index 346cdfd9..590fdcaf 100644 --- a/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/siswa/findMany.ts +++ b/src/app/api/[[...slugs]]/_lib/pendidikan/info-sekolah-paud/siswa/findMany.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ // /api/berita/findManyPaginated.ts import prisma from "@/lib/prisma"; import { Context } from "elysia"; @@ -6,11 +7,23 @@ async function siswaFindMany(context: Context) { const page = Number(context.query.page) || 1; const limit = Number(context.query.limit) || 10; const skip = (page - 1) * limit; + const search = (context.query.search as string) || ""; + + // Buat where clause + const where: any = { isActive: true }; + + // Tambahkan pencarian (jika ada) + if (search) { + where.OR = [ + { nama: { contains: search, mode: "insensitive" } }, + { lembaga: { contains: search, mode: "insensitive" } }, + ]; + } try { const [data, total] = await Promise.all([ prisma.siswa.findMany({ - where: { isActive: true }, + where, include: { lembaga: true, }, @@ -19,7 +32,7 @@ async function siswaFindMany(context: Context) { orderBy: { createdAt: 'desc' }, // opsional, kalau mau urut berdasarkan waktu }), prisma.siswa.count({ - where: { isActive: true } + where, }) ]); @@ -28,6 +41,7 @@ async function siswaFindMany(context: Context) { message: "Success fetch siswa with pagination", data, page, + limit, totalPages: Math.ceil(total / limit), total, }; diff --git a/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/page.tsx b/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/page.tsx index 4e3f445c..aa559a6d 100644 --- a/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/page.tsx +++ b/src/app/darmasaba/(pages)/lingkungan/edukasi-lingkungan/page.tsx @@ -1,100 +1,87 @@ +'use client' import colors from '@/con/colors'; -import { Box, List, ListItem, Paper, SimpleGrid, Stack, Text } from '@mantine/core'; +import { Box, List, ListItem, Paper, SimpleGrid, Stack, Text, Tooltip } from '@mantine/core'; +import { IconLeaf, IconPlant2, IconRecycle } from '@tabler/icons-react'; import BackButton from '../../desa/layanan/_com/BackButto'; const data = [ { id: 1, title: 'Tujuan Edukasi Lingkungan', - listDeskripsi: - - Meningkatkan kesadaran masyarakat tentang pentingnya lingkungan bersih dan sehat - - - Mendorong partisipasi warga dalam kegiatan pengelolaan sampah, penghijauan, dan konservasi - - - Mengurangi dampak negatif terhadap lingkungan dari kegiatan manusia - - - Membentuk generasi muda yang peduli terhadap isu-isu lingkungan - - + icon: , + listDeskripsi: [ + 'Meningkatkan kesadaran masyarakat akan pentingnya lingkungan bersih dan sehat', + 'Mendorong partisipasi warga dalam pengelolaan sampah, penghijauan, dan konservasi', + 'Mengurangi dampak negatif kegiatan manusia terhadap lingkungan', + 'Membentuk generasi muda peduli isu-isu lingkungan', + ], }, { id: 2, title: 'Materi Edukasi yang Diberikan', - listDeskripsi: - - Pengelolaan Sampah (Pilah sampah organik dan anorganik) - - - Pencegahan pencemaran lingkungan (air, udara, dan tanah) - - - Pemanfaatan lahan hijau dan penghijauan desa - - - Daur ulang dan kreatifitas dari sampah - - - Bahaya pembakaran sampah sembarangan - - + icon: , + listDeskripsi: [ + 'Pengelolaan sampah: pilah organik & anorganik', + 'Pencegahan pencemaran lingkungan (air, udara, tanah)', + 'Pemanfaatan lahan hijau dan penghijauan desa', + 'Daur ulang dan kreativitas dari sampah', + 'Bahaya pembakaran sampah sembarangan', + ], }, - { id: 3, title: 'Contoh Kegiatan di Desa Darmasaba', - listDeskripsi: - - Pelatihan membuat kompos dari sampah rumah tangga - - - Gerakan "Jumat Bersih" rutin - - - Workshop membuat ecobrick - - - Lomba kebersihan antar banjar - - - Sosialisasi lingkungan di sekolah dan posyandu - - + icon: , + listDeskripsi: [ + 'Pelatihan membuat kompos dari sampah rumah tangga', + 'Gerakan "Jumat Bersih" rutin', + 'Workshop pembuatan ecobrick', + 'Lomba kebersihan antar banjar', + 'Sosialisasi lingkungan di sekolah dan posyandu', + ], }, -] +]; + function Page() { return ( - + + - + Edukasi Lingkungan - - Edukasi Lingkungan adalah bagian penting dalam membentuk perilaku masyarakat yang peduli dan bertanggung jawab terhadap kelestarian alam. Melalui program ini, masyarakat diajak untuk memahami pentingnya menjaga lingkungan demi kesehatan, kenyamanan, dan keberlanjutan hidup bersama. + + Program edukasi ini membimbing masyarakat untuk peduli dan bertanggung jawab terhadap alam, + meningkatkan kesehatan, kenyamanan, dan keberlanjutan hidup bersama. - - - {data.map((v, k) => { - return ( - - - {v.title} - {v.listDeskripsi} - - - ) - })} + + + + {data.map((item) => ( + + + + + + {item.icon} + + {item.title} + + + + + + {item.listDeskripsi.map((desc, idx) => ( + {desc} + ))} + + + + ))} 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 new file mode 100644 index 00000000..26c2f814 --- /dev/null +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/[id]/page.tsx @@ -0,0 +1,80 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' + +import gotongRoyongState from '@/app/admin/(dashboard)/_state/lingkungan/gotong-royong'; +import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto'; +import colors from '@/con/colors'; +import { Box, Center, Container, Image, Skeleton, Stack, Text } from '@mantine/core'; +import { useParams } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { useProxy } from 'valtio/utils'; + + + + +function Page() { + const params = useParams<{ id: string }>(); + const id = Array.isArray(params.id) ? params.id[0] : params.id; + const state = useProxy(gotongRoyongState.kegiatanDesa) + const [loading, setLoading] = useState(true) + + useEffect(() => { + const loadData = async () => { + if (!id) return; + try { + setLoading(true); + await state.findUnique.load(id); + } catch (error) { + console.error('Error loading data:', error); + } finally { + setLoading(false); + } + } + loadData() + }, [id]) + + if (loading) { + return ( +
+ +
+ ); + } + + if (!state.findUnique.data) { + return ( +
+ Data tidak ditemukan +
+ ); + } + + + return ( + + + + + + {state.findUnique.data?.judul} + + + Informasi Kegiatan Gotong Royong + + + + + + + + + + + ); +} + +export default Page; diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/content.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/content.tsx new file mode 100644 index 00000000..76df3628 --- /dev/null +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/content.tsx @@ -0,0 +1,168 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' +import gotongRoyongState from '@/app/admin/(dashboard)/_state/lingkungan/gotong-royong'; +import { + Badge, + Box, + Button, + Card, + Center, + Container, + Divider, + Grid, + GridCol, + Group, + Image, + Pagination, + Paper, + SimpleGrid, + Skeleton, + Stack, + Text, + Title, +} from '@mantine/core'; +import { IconArrowRight, IconCalendar } from '@tabler/icons-react'; +import { useTransitionRouter } from 'next-view-transitions'; +import { useEffect, useState } from 'react'; +import { useProxy } from 'valtio/utils'; + +export default function Content({ kategori }: { kategori: string }) { + const router = useTransitionRouter(); + const [page, setPage] = useState(1); + + const state = useProxy(gotongRoyongState.kegiatanDesa); + const featuredState = useProxy(gotongRoyongState.kegiatanDesa.findFirst); + + const featured = featuredState.data; + const paginatedNews = state.findMany.data || []; + const totalPages = state.findMany.totalPages || 1; + + // Load data + useEffect(() => { + gotongRoyongState.kegiatanDesa.findFirst.load(kategori); + }, [kategori]); + + useEffect(() => { + state.findMany.load(page, 3, '', kategori); + }, [page, kategori]); + + return ( + + + {/* === Gotong Royong Utama === */} + {featuredState.loading ? ( +
+ ) : featured ? ( + + Gotong Royong Utama + + + + {featured.judul + + + +
+ + {featured.kategoriKegiatan?.nama || kategori} + + {featured.judul} + {featured.deskripsiLengkap} +
+ + + + + {new Date(featured.createdAt).toLocaleDateString('id-ID', { + day: 'numeric', + month: 'long', + year: 'numeric', + })} + + + + +
+
+
+
+
+ ) : null} + + {/* === Daftar Gotong Royong === */} + + Daftar Gotong Royong + + + {state.findMany.loading ? ( + + {Array(3).fill(0).map((_, i) => ( + + ))} + + ) : paginatedNews.length === 0 ? ( + Belum ada gotong royong di kategori "{kategori}". + ) : ( + + {paginatedNews.map((item) => ( + router.push(`/darmasaba/lingkungan/gotong-royong/${kategori}/${item.id}`)} + style={{ cursor: 'pointer' }} + > + + {item.judul} + + + {item.kategoriKegiatan?.nama || kategori} + + {item.judul} + + + + {new Date(item.createdAt).toLocaleDateString('id-ID', { + day: 'numeric', + month: 'short', + year: 'numeric', + })} + + Baca Selengkapnya + + + ))} + + )} + + {/* Pagination */} +
+ setPage(newPage)} + siblings={1} + boundaries={1} + withEdges + /> +
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/page.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/page.tsx new file mode 100644 index 00000000..3c40cc0c --- /dev/null +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/[kategori]/page.tsx @@ -0,0 +1,14 @@ +// src/app/darmasaba/(pages)/desa/berita/[kategori]/page.tsx +import { Suspense } from "react"; +import Content from "./content"; + + +export default async function Page({ params }: { params: Promise<{ kategori: string }> }) { + const { kategori } = await params; + + return ( + Loading...}> + + + ); +} \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/_lib/layoutTabs.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/_lib/layoutTabs.tsx new file mode 100644 index 00000000..1a6dbcb4 --- /dev/null +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/_lib/layoutTabs.tsx @@ -0,0 +1,171 @@ +'use client' +import colors from '@/con/colors'; +import { Box, Container, Grid, GridCol, Stack, Tabs, TabsList, TabsTab, Text, TextInput } from '@mantine/core'; +import { IconSearch } from '@tabler/icons-react'; +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; +import React, { useEffect, useState } from 'react'; +import BackButton from '../../../desa/layanan/_com/BackButto'; + + +type HeaderSearchProps = { + placeholder?: string; + searchIcon?: React.ReactNode; + value?: string; + onChange?: (event: React.ChangeEvent) => void; + children?: React.ReactNode; +}; + +function LayoutTabsGotongRoyong({ + children, + placeholder = "pencarian", + searchIcon = +}: HeaderSearchProps) { + const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + + // Get active tab from URL path + const activeTab = pathname.split('/').pop() || 'semua'; + + // Get initial search value from URL + const initialSearch = searchParams.get('search') || ''; + const [searchValue, setSearchValue] = useState(initialSearch); + const [searchTimeout, setSearchTimeout] = useState(null); + + // Update active tab state when pathname changes + const [activeTabState, setActiveTabState] = useState(activeTab); + useEffect(() => { + setActiveTabState(activeTab); + }, [activeTab]); + + // Clean up timeouts on unmount + useEffect(() => { + return () => { + if (searchTimeout !== null) { + clearTimeout(searchTimeout); + } + }; + }, [searchTimeout]); + + // Handle search input change with debounce + const handleSearchChange = (event: React.ChangeEvent) => { + const value = event.target.value; + setSearchValue(value); + + // Clear previous timeout + if (searchTimeout !== null) { + clearTimeout(searchTimeout); + } + + // Set new timeout + const newTimeout = window.setTimeout(() => { + const params = new URLSearchParams(searchParams.toString()); + + if (value) { + params.set('search', value); + } else { + params.delete('search'); + } + + // Only update URL if the search value has actually changed + if (params.toString() !== searchParams.toString()) { + router.push(`/darmasaba/lingkungan/gotong-royong/${activeTab}?${params.toString()}`); + } + }, 500); // 500ms debounce delay + + setSearchTimeout(newTimeout); + }; + const tabs = [ + { + label: "Semua", + value: "semua", + href: "/darmasaba/lingkungan/gotong-royong/semua" + }, + { + label: "Kebersihan", + value: "kebersihan", + href: "/darmasaba/lingkungan/gotong-royong/kebersihan" + }, + { + label: "Infrasturktur", + value: "infrasturktur", + href: "/darmasaba/lingkungan/gotong-royong/infrasturktur" + }, + { + label: "Sosial", + value: "sosial", + href: "/darmasaba/lingkungan/gotong-royong/sosial" + }, + { + label: "Lingkungan", + value: "lingkungan", + href: "/darmasaba/lingkungan/gotong-royong/lingkungan" + } + ]; + const handleTabChange = (value: string | null) => { + if (!value) return; + const tab = tabs.find(t => t.value === value); + if (tab) { + const params = new URLSearchParams(searchParams.toString()); + router.push(`/darmasaba/lingkungan/gotong-royong/${value}${params.toString() ? `?${params.toString()}` : ''}`); + } + }; + + return ( + + {/* Header */} + + + + + + + Gotong Royong Desa Darmasaba + + + Gotong royong rutin dilakukan oleh warga desa untuk meningkatkan kualitas hidup dan kesejahteraan masyarakat Desa Darmasaba + + + + + + + + + + {tabs.map((tab, index) => ( + router.push(tab.href)} + > + {tab.label} + + ))} + + + + + + + + + {children} + + + ); +} + +export default LayoutTabsGotongRoyong; \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/layout.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/layout.tsx new file mode 100644 index 00000000..ff7ea037 --- /dev/null +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/layout.tsx @@ -0,0 +1,12 @@ +// app/desa/berita/BeritaLayoutClient.tsx +'use client' +import dynamic from 'next/dynamic'; + +const LayoutTabsGotongRoyong = dynamic( + () => import('./_lib/layoutTabs'), + { ssr: false } +); + +export default function GotongRoyongLayoutClient({ children }: { children: React.ReactNode }) { + return {children}; +} \ No newline at end of file diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/page.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/page.tsx deleted file mode 100644 index 041d7620..00000000 --- a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/page.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import colors from '@/con/colors'; -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'; -import BackButton from '../../desa/layanan/_com/BackButto'; -import Link from 'next/link'; - -function Page() { - return ( - - {/* 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. - - - - - - - - ); -} - -export default Page; diff --git a/src/app/darmasaba/(pages)/lingkungan/gotong-royong/semua/page.tsx b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/semua/page.tsx new file mode 100644 index 00000000..3effe8a3 --- /dev/null +++ b/src/app/darmasaba/(pages)/lingkungan/gotong-royong/semua/page.tsx @@ -0,0 +1,183 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client' +import gotongRoyongState from '@/app/admin/(dashboard)/_state/lingkungan/gotong-royong'; +import { Badge, Box, Button, Card, Center, Container, Divider, Flex, Grid, GridCol, Group, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core'; +import { IconArrowRight, IconCalendar } from '@tabler/icons-react'; +import { useTransitionRouter } from 'next-view-transitions'; +import { useSearchParams } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { useProxy } from 'valtio/utils'; + +function Page() { + const searchParams = useSearchParams(); + const router = useTransitionRouter(); + + // Parameter URL + const search = searchParams.get('search') || ''; + const currentPage = parseInt(searchParams.get('page') || '1'); + const [page, setPage] = useState(currentPage); + + // Gunakan proxy untuk state + const state = useProxy(gotongRoyongState.kegiatanDesa); + const featured = useProxy(gotongRoyongState.kegiatanDesa.findFirst); // ✅ Berita utama + const loadingGrid = state.findMany.loading; + const loadingFeatured = featured.loading; + + // Load berita utama (hanya sekali) + useEffect(() => { + if (!featured.data && !loadingFeatured) { + gotongRoyongState.kegiatanDesa.findFirst.load(); + } + }, [featured.data, loadingFeatured]); + + // Load berita terbaru (untuk grid) saat page/search berubah + useEffect(() => { + const limit = 3; // Sesuaikan dengan tampilan grid + state.findMany.load(page, limit, search); + }, [page, search]); + + // Update URL saat page berubah + useEffect(() => { + const url = new URLSearchParams(); + if (search) url.set('search', search); + if (page > 1) url.set('page', page.toString()); + router.replace(`?${url.toString()}`); + }, [page, search]); + + const featuredData = featured.data; + const paginatedNews = state.findMany.data || []; + const totalPages = state.findMany.totalPages || 1; + + return ( + + + {/* === Gotong royong Utama (Tetap) === */} + {loadingFeatured ? ( +
+ ) : featuredData ? ( + + Gotong royong Utama + + + + {featuredData.judul + + + +
+ + {featuredData.kategoriKegiatan?.nama || 'Gotong royong'} + + {featuredData.judul} + + {featuredData.deskripsiSingkat} + +
+ + + + + {new Date(featuredData.createdAt).toLocaleDateString('id-ID', { + day: 'numeric', + month: 'long', + year: 'numeric' + })} + + + + +
+
+
+
+
+ ) : null} + + {/* === Gotong royong Terbaru (Berubah Saat Pagination) === */} + + Gotong royong Terbaru + + + {loadingGrid ? ( + + {Array(3).fill(0).map((_, i) => ( + + ))} + + ) : paginatedNews.length === 0 ? ( + Tidak ada gotong royong ditemukan. + ) : ( + + {paginatedNews.map((item) => ( + + + {item.judul} + + + + {item.kategoriKegiatan?.nama || 'Gotong royong'} + + + {item.judul} + + {item.deskripsiSingkat} + + + + {new Date(item.createdAt).toLocaleDateString('id-ID', { + day: 'numeric', + month: 'short', + year: 'numeric' + })} + + + + + + ))} + + )} + + {/* Pagination hanya untuk berita terbaru */} +
+ +
+
+
+
+ ); +} + +export default Page; + 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 c53e1f3d..73360da3 100644 --- a/src/app/darmasaba/(pages)/lingkungan/konservasi-adat-bali/page.tsx +++ b/src/app/darmasaba/(pages)/lingkungan/konservasi-adat-bali/page.tsx @@ -51,7 +51,7 @@ function Page() { Konservasi Adat Bali - + Pelestarian lingkungan di Bali yang berpijak pada kearifan lokal, menjaga harmoni antara alam, budaya, dan manusia. diff --git a/src/app/darmasaba/(pages)/pendidikan/info-sekolah-paud/page.tsx b/src/app/darmasaba/(pages)/pendidikan/info-sekolah-paud/page.tsx index 264c4f17..88b61cff 100644 --- a/src/app/darmasaba/(pages)/pendidikan/info-sekolah-paud/page.tsx +++ b/src/app/darmasaba/(pages)/pendidikan/info-sekolah-paud/page.tsx @@ -1,105 +1,363 @@ +/* eslint-disable react-hooks/exhaustive-deps */ 'use client' -import colors from '@/con/colors'; -import { Box, Button, Center, Group, Paper, SimpleGrid, Stack, Text, TextInput } from '@mantine/core'; -import { IconChalkboard, IconMicroscope, IconSchool, IconSearch } from '@tabler/icons-react'; -import BackButton from '../../desa/layanan/_com/BackButto'; +import React, { useMemo, useState } from 'react'; +import { + ActionIcon, + Badge, + Box, + Button, + Center, + Container, + Group, + Paper, + Progress, + SimpleGrid, + Stack, + Text, + TextInput, + Tooltip, + VisuallyHidden, +} from '@mantine/core'; +import { + IconChalkboard, + IconInfoCircle, + IconMicroscope, + IconSchool, + IconSearch, + IconArrowLeft, +} from '@tabler/icons-react'; import { motion } from 'framer-motion'; +import type { IconProps } from '@tabler/icons-react'; +type Stat = { + id: number; + icon: React.ComponentType; + jumlah: number; + nama: string; + helper?: string; +}; -const dataSekolah = [ +const dataSekolah: Stat[] = [ { id: 1, - icon: , + icon: IconChalkboard, jumlah: 15, - nama: 'Lembaga Pendidikan' + nama: 'Lembaga Pendidikan', + helper: 'Jumlah institusi pendidikan resmi di wilayah ini', }, { id: 2, - icon: , + icon: IconSchool, jumlah: 3209, - nama: 'Siswa Terdaftar' + nama: 'Siswa Terdaftar', + helper: 'Total siswa aktif di semua jenjang', }, { id: 3, - icon: , + icon: IconMicroscope, jumlah: 285, - nama: 'Tenaga Pengajar' + nama: 'Tenaga Pengajar', + helper: 'Jumlah guru dan staf pengajar aktif', }, -] +]; +export default function SekolahPage() { + const [query, setQuery] = useState(''); + const [kategoriAktif, setKategoriAktif] = useState('Semua'); + const kategoriList = ['Semua', 'TK/PAUD', 'SD', 'SMP', 'SMA/SMK']; + const maxJumlah = useMemo(() => Math.max(...dataSekolah.map((d) => d.jumlah)), []); + const filtered = useMemo(() => { + const q = query.trim().toLowerCase(); + return dataSekolah.filter((d) => { + const teks = `${d.nama} ${d.jumlah}`.toLowerCase(); + const matchQuery = q ? teks.includes(q) : true; + return matchQuery; + }); + }, [query, kategoriAktif]); + + const hasilCount = filtered.length; -function Page() { return ( - - - - - - - Cari Informasi Sekolah - - - - Cari - - } - rightSectionWidth={70} - leftSection={} - /> - - - - - Semua - - - {['TK/PAUD', 'SD', 'SMP', 'SMA/SMK'].map((kategori) => ( - - - {kategori} - - - ))} - - - {dataSekolah.map((v, k) => { - return ( - + + + + + window.history.back()} + size="lg" + radius="md" + variant="light" + style={{ + color: '#1e293b', + background: 'white', + boxShadow: '0 2px 12px rgba(0,0,0,0.06)', + }} + > + + Tombol kembali + + + + + +
- - -
- {v.icon} -
- {v.jumlah} - {v.nama} -
-
+ + Cari Informasi Sekolah + + + Masukkan nama, jenjang, atau alamat sekolah untuk hasil lebih spesifik. +
- - ) - })} - - - +
+ + + setQuery(e.currentTarget.value)} + placeholder="Contoh: SMP Negeri, SD 01, Kelurahan..." + leftSection={} + aria-label="Masukkan kata kunci pencarian" + radius="xl" + size="md" + rightSection={ + + } + rightSectionWidth={120} + style={{ + width: '100%', + maxWidth: 920, + }} + /> + + + + {kategoriList.map((k) => { + const aktif = k === kategoriAktif; + return ( + + + + ); + })} + +
+
+ + + + Menampilkan {hasilCount} hasil. + + + + + {filtered.length === 0 ? ( + +
+ + Tidak ditemukan + + + Coba gunakan kata kunci lain atau setel ulang filter. + + +
+
+ ) : ( + filtered.map((v) => { + const percent = Math.round((v.jumlah / maxJumlah) * 100) || 0; + return ( + + + +
+ + {React.createElement(v.icon, { + color: '#2563eb', + size: 34, + stroke: 1.6, + })} + +
+ + + + + {v.jumlah.toLocaleString()} + + + + {v.nama} + + + + + + + + + + + Statistik + + + + + + + Perbandingan dengan jumlah terbesar. + + +
+ + + + +
+
+ ); + }) + )} +
+
+
+
); } - -export default Page; diff --git a/src/con/navbar-list-menu.ts b/src/con/navbar-list-menu.ts index 795711d4..0ff3d936 100644 --- a/src/con/navbar-list-menu.ts +++ b/src/con/navbar-list-menu.ts @@ -286,7 +286,7 @@ const navbarListMenu = [ { id: "7.4", name: "Gotong Royong", - href: "/darmasaba/lingkungan/gotong-royong" + href: "/darmasaba/lingkungan/gotong-royong/semua" }, { id: "7.5",