diff --git a/src/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pasar-desa.ts b/src/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pasar-desa.ts
index 21d8e7b4..c25a99ff 100644
--- a/src/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pasar-desa.ts
+++ b/src/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pasar-desa.ts
@@ -312,15 +312,15 @@ const kategoriProduk = proxy({
page: 1,
totalPages: 1,
loading: false,
- search2: "",
- load: async (page = 1, limit = 10, search2 = "") => {
+ search: "",
+ load: async (page = 1, limit = 10, search = "") => {
kategoriProduk.findMany.loading = true; // ✅ Akses langsung via nama path
kategoriProduk.findMany.page = page;
- kategoriProduk.findMany.search2 = search2;
+ kategoriProduk.findMany.search = search;
try {
const query: any = { page, limit };
- if (search2) query.search2 = search2;
+ if (search) query.search = search;
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many"].get({ query });
diff --git a/src/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi.ts b/src/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi.ts
index cef5c3fa..e347f63c 100644
--- a/src/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi.ts
+++ b/src/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi.ts
@@ -194,7 +194,7 @@ const posisiOrganisasi = proxy({
try {
this.loading = true;
- const res = await ApiFetch.api.ekonomi['struktur-organisasi']['posisi-organisasi']['create'].post(this.form);
+ const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["posisi-organisasi"]["create"].post(this.form);
if (res.status === 200) {
toast.success("Berhasil menambahkan posisi organisasi");
posisiOrganisasi.findMany.load();
diff --git a/src/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan.ts b/src/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan.ts
index 48d707b7..9caeb019 100644
--- a/src/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan.ts
+++ b/src/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan.ts
@@ -60,13 +60,18 @@ const responden = proxy({
totalPages: 1,
total: 0,
loading: false,
- load: async (page = 1, limit = 10) => {
+ search: "",
+ load: async (page = 1, limit = 10, search = "") => {
// Change to arrow function
responden.findMany.loading = true; // Use the full path to access the property
responden.findMany.page = page;
+ responden.findMany.search = search;
try {
+ const query: any = { page, limit };
+ if (search) query.search = search;
+
const res = await ApiFetch.api.landingpage.responden["findMany"].get({
- query: { page, limit },
+ query,
});
if (res.status === 200 && res.data?.success) {
diff --git a/src/app/admin/(dashboard)/_state/pendidikan/data-pendidikan.ts b/src/app/admin/(dashboard)/_state/pendidikan/data-pendidikan.ts
index f8ffa416..5e6d4cb1 100644
--- a/src/app/admin/(dashboard)/_state/pendidikan/data-pendidikan.ts
+++ b/src/app/admin/(dashboard)/_state/pendidikan/data-pendidikan.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";
@@ -65,13 +66,46 @@ const dataPendidikan = proxy({
select: { id: true; name: true; jumlah: true };
}>[]
| null,
+ page: 1,
+ totalPages: 1,
+ total: 0,
loading: false,
- async load() {
- const res = await ApiFetch.api.pendidikan.datapendidikan[
- "findMany"
- ].get();
- if (res.status === 200) {
- dataPendidikan.findMany.data = res.data?.data ?? [];
+ search: "",
+ load: async (page = 1, limit = 10, search = "") => {
+ // Change to arrow function
+ dataPendidikan.findMany.loading = true; // Use the full path to access the property
+ dataPendidikan.findMany.page = page;
+ dataPendidikan.findMany.search = search;
+ try {
+ const query: any = { page, limit };
+ if (search) query.search = search;
+
+ const res = await ApiFetch.api.pendidikan.datapendidikan[
+ "findMany"
+ ].get({
+ query,
+ });
+
+ if (res.status === 200 && res.data?.success) {
+ dataPendidikan.findMany.data = res.data.data || [];
+ dataPendidikan.findMany.total = res.data.total || 0;
+ dataPendidikan.findMany.totalPages = res.data.totalPages || 1;
+ } else {
+ console.error(
+ "Failed to load data pendidikan:",
+ res.data?.message
+ );
+ dataPendidikan.findMany.data = [];
+ dataPendidikan.findMany.total = 0;
+ dataPendidikan.findMany.totalPages = 1;
+ }
+ } catch (error) {
+ console.error("Error loading data pendidikan:", error);
+ dataPendidikan.findMany.data = [];
+ dataPendidikan.findMany.total = 0;
+ dataPendidikan.findMany.totalPages = 1;
+ } finally {
+ dataPendidikan.findMany.loading = false;
}
},
},
diff --git a/src/app/admin/(dashboard)/_state/user/user-state.ts b/src/app/admin/(dashboard)/_state/user/user-state.ts
index e3864904..c049d703 100644
--- a/src/app/admin/(dashboard)/_state/user/user-state.ts
+++ b/src/app/admin/(dashboard)/_state/user/user-state.ts
@@ -220,11 +220,34 @@ const roleState = proxy({
isActive: true;
};
}>[],
+ page: 1,
+ totalPages: 1,
loading: false,
- async load() {
- const res = await ApiFetch.api.role["findMany"].get();
- if (res.status === 200) {
- roleState.findMany.data = res.data?.data ?? [];
+ search: "",
+ load: async (page = 1, limit = 10, search = "") => {
+ roleState.findMany.loading = true; // ✅ Akses langsung via nama path
+ roleState.findMany.page = page;
+ roleState.findMany.search = search;
+
+ try {
+ const query: any = { page, limit };
+ if (search) query.search = search;
+
+ const res = await ApiFetch.api.role["findMany"].get({ query });
+
+ if (res.status === 200 && res.data?.success) {
+ roleState.findMany.data = res.data.data ?? [];
+ roleState.findMany.totalPages = res.data.totalPages ?? 1;
+ } else {
+ roleState.findMany.data = [];
+ roleState.findMany.totalPages = 1;
+ }
+ } catch (err) {
+ console.error("Gagal fetch role paginated:", err);
+ roleState.findMany.data = [];
+ roleState.findMany.totalPages = 1;
+ } finally {
+ roleState.findMany.loading = false;
}
},
},
diff --git a/src/app/admin/(dashboard)/desa/_com/layoutTabLayanan.tsx b/src/app/admin/(dashboard)/desa/_com/layoutTabLayanan.tsx
index 56029f20..c0cf829b 100644
--- a/src/app/admin/(dashboard)/desa/_com/layoutTabLayanan.tsx
+++ b/src/app/admin/(dashboard)/desa/_com/layoutTabLayanan.tsx
@@ -73,17 +73,17 @@ function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
>
{/* ✅ Scroll horizontal wrapper */}
-
+
{tabs.map((tab, i) => (
diff --git a/src/app/admin/(dashboard)/desa/gallery/video/page.tsx b/src/app/admin/(dashboard)/desa/gallery/video/page.tsx
index f642873e..df15c04d 100644
--- a/src/app/admin/(dashboard)/desa/gallery/video/page.tsx
+++ b/src/app/admin/(dashboard)/desa/gallery/video/page.tsx
@@ -88,63 +88,65 @@ function ListVideo({ search }: { search: string }) {
{/* Desktop Table */}
-
-
-
- Judul Video
- Tanggal
- Deskripsi
- Aksi
-
-
-
- {filteredData.length > 0 ? (
- filteredData.map((item) => (
-
-
-
- {item.name}
-
-
-
-
- {new Date(item.createdAt).toLocaleDateString('id-ID', {
- day: 'numeric',
- month: 'long',
- year: 'numeric',
- })}
-
-
-
-
-
-
-
+
+
+
+
+ Judul Video
+ Tanggal
+ Deskripsi
+ Aksi
+
+
+
+ {filteredData.length > 0 ? (
+ filteredData.map((item) => (
+
+
+
+ {item.name}
+
+
+
+
+ {new Date(item.createdAt).toLocaleDateString('id-ID', {
+ day: 'numeric',
+ month: 'long',
+ year: 'numeric',
+ })}
+
+
+
+
+
+
+
+
+
+ ))
+ ) : (
+
+
+
+
+ Tidak ada video yang cocok
+
+
- ))
- ) : (
-
-
-
-
- Tidak ada video yang cocok
-
-
-
-
- )}
-
-
+ )}
+
+
+
{/* Mobile Cards */}
diff --git a/src/app/admin/(dashboard)/desa/layanan/pelayanan_penduduk_non_permanent/page.tsx b/src/app/admin/(dashboard)/desa/layanan/pelayanan_penduduk_non_permanent/page.tsx
index f6b93484..48a3e4dd 100644
--- a/src/app/admin/(dashboard)/desa/layanan/pelayanan_penduduk_non_permanent/page.tsx
+++ b/src/app/admin/(dashboard)/desa/layanan/pelayanan_penduduk_non_permanent/page.tsx
@@ -5,8 +5,7 @@ import {
Button,
Center,
Divider,
- Grid,
- GridCol,
+ Group,
Paper,
Skeleton,
Stack,
@@ -43,32 +42,29 @@ function PelayananPendudukNonPermanent() {
{/* Header */}
-
-
-
- Preview Pelayanan Penduduk Non Permanen
-
-
-
- }
- radius="md"
- onClick={() =>
- router.push(
- `/admin/desa/layanan/pelayanan_penduduk_non_permanent/${data.id}`
- )
- }
- >
- Edit
-
-
-
+
+
+
+ Preview Pelayanan Penduduk Non Permanen
+
+ }
+ radius="md"
+ onClick={() =>
+ router.push(
+ `/admin/desa/layanan/pelayanan_penduduk_non_permanent/${data.id}`
+ )
+ }
+ >
+ Edit
+
+
{/* Content */}
diff --git a/src/app/admin/(dashboard)/desa/layanan/pelayanan_perizinan_berusaha/page.tsx b/src/app/admin/(dashboard)/desa/layanan/pelayanan_perizinan_berusaha/page.tsx
index 43854e4c..712eadc1 100644
--- a/src/app/admin/(dashboard)/desa/layanan/pelayanan_perizinan_berusaha/page.tsx
+++ b/src/app/admin/(dashboard)/desa/layanan/pelayanan_perizinan_berusaha/page.tsx
@@ -6,8 +6,6 @@ import {
Button,
Center,
Divider,
- Grid,
- GridCol,
Group,
Paper,
Skeleton,
@@ -76,28 +74,24 @@ function PerizinanBerusaha() {
{/* Header */}
-
-
-
- Preview Pelayanan Perizinan Berusaha
-
-
-
- }
- radius="md"
- onClick={() =>
- router.push(
- `/admin/desa/layanan/pelayanan_perizinan_berusaha/${data.id}`
- )
- }
- >
- Edit
-
-
-
+
+
+ Preview Pelayanan Perizinan Berusaha
+
+ }
+ radius="md"
+ onClick={() =>
+ router.push(
+ `/admin/desa/layanan/pelayanan_perizinan_berusaha/${data.id}`
+ )
+ }
+ >
+ Edit
+
+
{/* Content */}
@@ -136,7 +130,7 @@ function PerizinanBerusaha() {
umum:
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/src/app/admin/(dashboard)/ekonomi/PADesa-pendapatan-asli-desa/apbdesa/page.tsx b/src/app/admin/(dashboard)/ekonomi/PADesa-pendapatan-asli-desa/apbdesa/page.tsx
index cc7cf319..5015c2a4 100644
--- a/src/app/admin/(dashboard)/ekonomi/PADesa-pendapatan-asli-desa/apbdesa/page.tsx
+++ b/src/app/admin/(dashboard)/ekonomi/PADesa-pendapatan-asli-desa/apbdesa/page.tsx
@@ -166,7 +166,7 @@ function ListAPBDesa({ search }: { search: string }) {
@@ -176,7 +175,6 @@ function ListPendapatan({ search }: { search: string }) {
px="xs"
>
- Hapus
diff --git a/src/app/admin/(dashboard)/ekonomi/Struktur-Organisasi-Dan-Sk-Pengurus-BumDes/posisi-organisasi/page.tsx b/src/app/admin/(dashboard)/ekonomi/Struktur-Organisasi-Dan-Sk-Pengurus-BumDes/posisi-organisasi/page.tsx
index 26d9dba1..a86edc28 100644
--- a/src/app/admin/(dashboard)/ekonomi/Struktur-Organisasi-Dan-Sk-Pengurus-BumDes/posisi-organisasi/page.tsx
+++ b/src/app/admin/(dashboard)/ekonomi/Struktur-Organisasi-Dan-Sk-Pengurus-BumDes/posisi-organisasi/page.tsx
@@ -153,9 +153,14 @@ function ListPosisiOrganisasiBumDes({ search }: { search: string }) {
-
- {item.deskripsi || '-'}
-
+
{item.hierarki || '-'}
@@ -223,9 +228,14 @@ function ListPosisiOrganisasiBumDes({ search }: { search: string }) {
Deskripsi
-
- {item.deskripsi || '-'}
-
+
diff --git a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx
index b65b6172..b3b14f74 100644
--- a/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx
+++ b/src/app/admin/(dashboard)/ekonomi/demografi-pekerjaan/page.tsx
@@ -21,7 +21,7 @@ import {
Text,
Title
} from '@mantine/core';
-import { useShallowEffect } from '@mantine/hooks';
+import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
import { IconEdit, IconPlus, IconSearch, IconTrash } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
@@ -59,6 +59,8 @@ function ListDemografiPekerjaan({ search }: { search: string }) {
const [chartData, setChartData] = useState([]);
const [mounted, setMounted] = useState(false);
const [modalHapus, setModalHapus] = useState(false);
+ const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
+
const [selectedId, setSelectedId] = useState(null);
const {
@@ -79,8 +81,8 @@ function ListDemografiPekerjaan({ search }: { search: string }) {
useShallowEffect(() => {
setMounted(true);
- load(page, 10, search);
- }, [page, search]);
+ load(page, 10, debouncedSearch);
+ }, [page, debouncedSearch]);
useEffect(() => {
if (data) {
diff --git a/src/app/admin/(dashboard)/ekonomi/pasar-desa/kategori-produk/page.tsx b/src/app/admin/(dashboard)/ekonomi/pasar-desa/kategori-produk/page.tsx
index 7fd3749c..048d4099 100644
--- a/src/app/admin/(dashboard)/ekonomi/pasar-desa/kategori-produk/page.tsx
+++ b/src/app/admin/(dashboard)/ekonomi/pasar-desa/kategori-produk/page.tsx
@@ -28,27 +28,27 @@ import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
import pasarDesaState from '../../../_state/ekonomi/pasar-desa/pasar-desa';
function KategoriProduk() {
- const [search2, setSearch2] = useState('');
+ const [search, setSearch] = useState('');
return (
}
- value={search2}
- onChange={(e) => setSearch2(e.currentTarget.value)}
+ value={search}
+ onChange={(e) => setSearch(e.currentTarget.value)}
/>
-
+
);
}
-function ListKategoriProduk({ search2 }: { search2: string }) {
+function ListKategoriProduk({ search }: { search: string }) {
const statePasar = useProxy(pasarDesaState.kategoriProduk);
const [modalHapus, setModalHapus] = useState(false);
const [selectedId, setSelectedId] = useState(null);
const router = useRouter();
- const [debouncedSearch] = useDebouncedValue(search2, 1000);
+ const [debouncedSearch] = useDebouncedValue(search, 1000);
const { data, page, totalPages, loading, load } = statePasar.findMany;
diff --git a/src/app/admin/(dashboard)/inovasi/kolaborasi-inovasi/list-kolaborasi-inovasi/page.tsx b/src/app/admin/(dashboard)/inovasi/kolaborasi-inovasi/list-kolaborasi-inovasi/page.tsx
index ea69ed22..77ef345e 100644
--- a/src/app/admin/(dashboard)/inovasi/kolaborasi-inovasi/list-kolaborasi-inovasi/page.tsx
+++ b/src/app/admin/(dashboard)/inovasi/kolaborasi-inovasi/list-kolaborasi-inovasi/page.tsx
@@ -142,9 +142,7 @@ function ListKolaborasiInovasi({ search }: { search: string }) {
-
- {item.slug}
-
+
(null);
- const [debouncedSearch] = useDebouncedValue(search, 10000);
+ const [debouncedSearch] = useDebouncedValue(search, 1000);
const {
data,
diff --git a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/page.tsx b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/page.tsx
index 27e4f10f..7c6d09e4 100644
--- a/src/app/admin/(dashboard)/kesehatan/kontak-darurat/page.tsx
+++ b/src/app/admin/(dashboard)/kesehatan/kontak-darurat/page.tsx
@@ -96,15 +96,15 @@ function ListKontakDarurat({ search }: { search: string }) {
{filteredData.length > 0 ? (
filteredData.map((item) => (
-
+
{item.name}
-
+
-
+
-
+
-
+
diff --git a/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/responden/page.tsx b/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/responden/page.tsx
index a183535e..69b078c2 100644
--- a/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/responden/page.tsx
+++ b/src/app/admin/(dashboard)/landing-page/indeks-kepuasan-masyarakat/responden/page.tsx
@@ -2,7 +2,7 @@
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { useProxy } from 'valtio/utils';
-import { useShallowEffect } from '@mantine/hooks';
+import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
import {
Box,
Button,
@@ -47,16 +47,14 @@ interface ListRespondenProps {
function ListResponden({ search }: ListRespondenProps) {
const state = useProxy(indeksKepuasanState.responden);
const router = useRouter();
+ const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
const { data, page, totalPages, loading, load } = state.findMany;
useShallowEffect(() => {
- load(page, 10,);
- }, [page]);
+ load(page, 10, debouncedSearch);
+ }, [page, debouncedSearch]);
- const filteredData = (data || []).filter((item) => {
- const keyword = search.toLowerCase();
- return item.name.toLowerCase().includes(keyword);
- });
+ const filteredData = data || [];
if (loading || !data) {
return (
diff --git a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/page.tsx b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/page.tsx
index 27f270ce..c2e26cf6 100644
--- a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/page.tsx
+++ b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/[id]/page.tsx
@@ -84,7 +84,9 @@ function DetailProgramInovasi() {
Deskripsi
-
+
+
+
diff --git a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/page.tsx b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/page.tsx
index 0ed25cfb..938afd30 100644
--- a/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/page.tsx
+++ b/src/app/admin/(dashboard)/landing-page/profil/program-inovasi/page.tsx
@@ -34,8 +34,8 @@ function ListProgramInovasi({ search }: { search: string }) {
const { data, page, totalPages, loading, load } = stateProgramInovasi.findMany;
useShallowEffect(() => {
- load(page, 10, debouncedSearch);
- }, [page, debouncedSearch]);
+ load(page, 10, debouncedSearch);
+ }, [page, debouncedSearch]);
const filteredData = data || [];
@@ -144,9 +144,7 @@ function ListProgramInovasi({ search }: { search: string }) {
{/* Description */}
Deskripsi
-
- {item.description || '-'}
-
+
{/* Link */}
diff --git a/src/app/admin/(dashboard)/pendidikan/data-pendidikan/page.tsx b/src/app/admin/(dashboard)/pendidikan/data-pendidikan/page.tsx
index 8485cc9d..2598154c 100644
--- a/src/app/admin/(dashboard)/pendidikan/data-pendidikan/page.tsx
+++ b/src/app/admin/(dashboard)/pendidikan/data-pendidikan/page.tsx
@@ -1,7 +1,7 @@
'use client'
import colors from '@/con/colors';
-import { Box, Button, Group, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
-import { useShallowEffect } from '@mantine/hooks';
+import { Box, Button, Center, Group, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
+import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
import { IconDatabase, IconEdit, IconPlus, IconSearch, IconTrash } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
@@ -35,6 +35,8 @@ function ListDataPendidikan({ search }: { search: string }) {
const [modalHapus, setModalHapus] = useState(false);
const [selectedId, setSelectedId] = useState(null);
const router = useRouter();
+ const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
+ const { data, page, totalPages, loading, load } = dataPendidikan.findMany;
const handleDelete = () => {
if (selectedId) {
@@ -47,8 +49,8 @@ function ListDataPendidikan({ search }: { search: string }) {
useShallowEffect(() => {
setMounted(true);
- stateDPM.findMany.load();
- }, []);
+ load(page, 10, debouncedSearch);
+ }, [page, debouncedSearch]);
useEffect(() => {
setMounted(true);
@@ -68,9 +70,9 @@ function ListDataPendidikan({ search }: { search: string }) {
return item.name.toLowerCase().includes(keyword) || item.jumlah.toString().includes(keyword);
});
- if (!stateDPM.findMany.data) {
+ if (loading || !data) {
return (
-
+
);
@@ -137,6 +139,17 @@ function ListDataPendidikan({ search }: { search: string }) {
)}
+
+ {
+ load(newPage, 10);
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ }}
+ total={totalPages}
+ color="blue"
+ />
+
diff --git a/src/app/admin/(dashboard)/pendidikan/program-pendidikan-anak/program-unggulan/page.tsx b/src/app/admin/(dashboard)/pendidikan/program-pendidikan-anak/program-unggulan/page.tsx
index 31da5b7c..a6ca6274 100644
--- a/src/app/admin/(dashboard)/pendidikan/program-pendidikan-anak/program-unggulan/page.tsx
+++ b/src/app/admin/(dashboard)/pendidikan/program-pendidikan-anak/program-unggulan/page.tsx
@@ -29,7 +29,7 @@ function Page() {
{/* Header */}
-
+
Pratinjau Program Unggulan
diff --git a/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/[id]/edit/page.tsx b/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/[id]/edit/page.tsx
index 516c8e1c..ba7deb02 100644
--- a/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/[id]/edit/page.tsx
+++ b/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/[id]/edit/page.tsx
@@ -1,11 +1,23 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-'use client'
+/* eslint-disable react-hooks/exhaustive-deps */
+/* eslint-disable @typescript-eslint/no-unused-vars */
+'use client';
import indeksKepuasanState from '@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan';
import colors from '@/con/colors';
-import { Box, Button, Group, Paper, Select, Stack, TextInput, Title } from '@mantine/core';
-import { IconArrowBack, IconDeviceFloppy } from '@tabler/icons-react';
+import {
+ Box,
+ Button,
+ Group,
+ Loader,
+ Paper,
+ Select,
+ Stack,
+ Text,
+ TextInput,
+ Title,
+} from '@mantine/core';
+import { IconArrowBack } from '@tabler/icons-react';
import { useParams, useRouter } from 'next/navigation';
-import { ChangeEvent, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { toast } from 'react-toastify';
import { useProxy } from 'valtio/utils';
@@ -20,9 +32,13 @@ interface FormResponden {
function EditResponden() {
const router = useRouter();
const params = useParams() as { id: string };
- const state = useProxy(indeksKepuasanState.responden);
const id = params.id;
+ // ✅ proxy asli untuk mutasi
+ const state = indeksKepuasanState.responden;
+ // ✅ snapshot untuk re-render (read-only)
+ const snapshot = useProxy(indeksKepuasanState.responden);
+
const [formData, setFormData] = useState({
name: '',
tanggal: '',
@@ -31,59 +47,107 @@ function EditResponden() {
kelompokUmurId: '',
});
- // Helper untuk membuat data Select dari state
- const mapSelectData = (data: any[] | null | undefined) =>
- (data || [])
- .filter(Boolean)
- .map((v: any) => ({
- value: v.id || '',
- label: typeof v.name === 'string' ? v.name : 'Tanpa Nama',
- }));
+ const [originalData, setOriginalData] = useState({
+ name: '',
+ tanggal: '',
+ jenisKelaminId: '',
+ ratingId: '',
+ kelompokUmurId: '',
+ });
- useEffect(() => {
- // Load opsi dropdown
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ // 🔹 Load data pilihan select
+ const loadSelectOptions = useCallback(() => {
indeksKepuasanState.jenisKelaminResponden.findMany.load();
indeksKepuasanState.pilihanRatingResponden.findMany.load();
indeksKepuasanState.kelompokUmurResponden.findMany.load();
+ }, []);
- const loadResponden = async () => {
- if (!id) return;
+ // 🔹 Load data responden by ID
+ const loadResponden = useCallback(async () => {
+ if (!id) return;
+ try {
+ const data = await state.update.load(id);
+ if (!data) return;
- try {
- const data = await state.update.load(id);
- if (data) {
- state.update.id = id;
+ const newForm = {
+ name: data.name || '',
+ tanggal: data.tanggal || '',
+ jenisKelaminId: data.jenisKelaminId || '',
+ ratingId: data.ratingId || '',
+ kelompokUmurId: data.kelompokUmurId || '',
+ };
- // **formData lokal tetap controlled**, tidak overwrite tiap render
- setFormData({
- name: data.name || '',
- tanggal: data.tanggal || '',
- jenisKelaminId: data.jenisKelaminId || '',
- ratingId: data.ratingId || '',
- kelompokUmurId: data.kelompokUmurId || '',
- });
- }
- } catch (error) {
- console.error("Error loading responden:", error);
- toast.error("Gagal memuat data responden");
- }
- };
+ setFormData(newForm);
+ setOriginalData(newForm);
+ } catch (error) {
+ console.error('Error loading responden:', error);
+ toast.error('Gagal memuat data responden');
+ }
+ }, [id]);
+ useEffect(() => {
+ loadSelectOptions();
loadResponden();
- }, [id, state.update]);
-
- const handleChange = (field: keyof FormResponden) => (e: ChangeEvent | string | null) => {
- const value = typeof e === 'string' || e === null ? e || '' : e.currentTarget.value;
- setFormData((prev) => ({ ...prev, [field]: value }));
- };
+ }, [loadSelectOptions, loadResponden]);
+ // 🔹 Submit data
const handleSubmit = async () => {
- state.update.id = id;
- state.update.form = { ...formData }; // hanya update global state saat submit
- await state.update.submit();
- router.push('/admin/ppid/ikm-desa-darmasaba/responden');
+ try {
+ setIsSubmitting(true);
+ state.update.id = id;
+ state.update.form = { ...formData }; // mutasi proxy asli ✅
+ await state.update.submit();
+ toast.success('Responden berhasil diperbarui!');
+ router.push('/admin/ppid/indeks-kepuasan-masyarakat/responden');
+ } catch (error) {
+ console.error('Error updating responden:', error);
+ toast.error('Gagal memperbarui responden');
+ } finally {
+ setIsSubmitting(false);
+ }
};
+ // 🔹 Reset form ke data awal
+ const handleResetForm = () => {
+ setFormData({ ...originalData });
+ toast.info('Form dikembalikan ke data awal');
+ };
+
+ // 🔹 Reusable Select component
+ const ControlledSelect = ({
+ label,
+ value,
+ onChange,
+ options,
+ error,
+ placeholder = 'Pilih',
+ loading = false,
+ }: {
+ label: string;
+ value: string;
+ onChange: (val: string) => void;
+ options: { value: string; label: string }[];
+ error?: string;
+ placeholder?: string;
+ loading?: boolean;
+ }) => (
+
diff --git a/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/[id]/page.tsx b/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/[id]/page.tsx
index dc74a8b0..d288b980 100644
--- a/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/[id]/page.tsx
+++ b/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/[id]/page.tsx
@@ -26,7 +26,7 @@ export default function DetailResponden() {
stateDetail.delete.byId(selectedId)
setModalHapus(false)
setSelectedId(null)
- router.push("/admin/ppid/ikm-desa-darmasaba/responden")
+ router.push("/admin/ppid/indeks-kepuasan-masyarakat/responden")
}
}
@@ -108,7 +108,7 @@ export default function DetailResponden() {
variant="light"
onClick={() => {
if (stateDetail.findUnique.data) {
- router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${stateDetail.findUnique.data.id}/edit`);
+ router.push(`/admin/ppid/indeks-kepuasan-masyarakat/responden/${stateDetail.findUnique.data.id}/edit`);
}
}}
disabled={!stateDetail.findUnique.data}
diff --git a/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/create/page.tsx b/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/create/page.tsx
index 166001f9..37d33418 100644
--- a/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/create/page.tsx
+++ b/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/create/page.tsx
@@ -1,21 +1,20 @@
'use client'
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
-import React from 'react';
-import { useRouter } from 'next/navigation';
-import grafikBerdasarkanJenisKelamin from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin';
-import { useProxy } from 'valtio/utils';
-import { useState } from 'react';
-import colors from '@/con/colors';
-import { Box, Button, Paper, Stack, Title, TextInput, Select, Text } from '@mantine/core';
-import { IconArrowBack } from '@tabler/icons-react';
import indeksKepuasanState from '@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan';
+import colors from '@/con/colors';
+import { Box, Button, Group, Loader, Paper, Select, Stack, TextInput, Title } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
+import { IconArrowBack } from '@tabler/icons-react';
+import { useRouter } from 'next/navigation';
+import { useState } from 'react';
+import { useProxy } from 'valtio/utils';
function RespondenCreate() {
const router = useRouter();
const stategrafikBerdasarkanResponden = useProxy(indeksKepuasanState.responden)
const [donutData, setDonutData] = useState([]);
+ const [isSubmitting, setIsSubmitting] = useState(false);
const resetForm = () => {
stategrafikBerdasarkanResponden.create.form = {
@@ -35,6 +34,7 @@ function RespondenCreate() {
})
const handleSubmit = async () => {
+ setIsSubmitting(true);
try {
const id = await stategrafikBerdasarkanResponden.create.create();
if (typeof id !== 'undefined') {
@@ -45,13 +45,15 @@ function RespondenCreate() {
}
}
resetForm();
- router.push("/admin/ppid/ikm-desa-darmasaba/responden");
+ router.push("/admin/ppid/indeks-kepuasan-masyarakat/responden");
} catch (error) {
console.error('Error submitting form:', error);
+ } finally {
+ setIsSubmitting(false);
}
}
return (
-
+
router.back()}>
@@ -132,13 +134,32 @@ function RespondenCreate() {
}
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
/>
-
- Submit
-
+
+ {/* Tombol Batal */}
+
+ Reset
+
+
+ {/* Tombol Simpan */}
+
+ {isSubmitting ? : 'Simpan'}
+
+
diff --git a/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/page.tsx b/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/page.tsx
index 5631fe9d..c9e16300 100644
--- a/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/page.tsx
+++ b/src/app/admin/(dashboard)/ppid/indeks-kepuasan-masyarakat/responden/page.tsx
@@ -1,4 +1,8 @@
'use client';
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+import { useProxy } from 'valtio/utils';
+import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
import {
Box,
Button,
@@ -16,10 +20,7 @@ import {
Text,
Title,
} from '@mantine/core';
-import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
-import { useRouter } from 'next/navigation';
-import { useState } from 'react';
-import { useProxy } from 'valtio/utils';
+import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
import HeaderSearch from '../../../_com/header';
import indeksKepuasanState from '../../../_state/landing-page/indeks-kepuasan';
@@ -28,7 +29,7 @@ function Responden() {
return (
}
value={search}
@@ -46,193 +47,182 @@ interface ListRespondenProps {
function ListResponden({ search }: ListRespondenProps) {
const state = useProxy(indeksKepuasanState.responden);
const router = useRouter();
+ const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
const { data, page, totalPages, loading, load } = state.findMany;
- const filteredData = (data || []).filter((item) => {
- const keyword = search.toLowerCase();
- return item.name.toLowerCase().includes(keyword);
- });
+ useShallowEffect(() => {
+ load(page, 10, debouncedSearch);
+ }, [page, debouncedSearch]);
+
+ const filteredData = data || [];
if (loading || !data) {
return (
-
-
+
+
);
}
if (data.length === 0) {
return (
-
-
-
- Data Responden
-
-
-
-
-
- No
- Nama
- Tanggal
- Jenis Kelamin
- Aksi
-
-
-
-
-
- Belum ada data responden yang tersedia
-
-
-
+
+
+
+
+ Data Responden
+
+
+ Belum ada data responden yang tersedia
+
+
+
+
);
}
return (
-
-
-
- Data Responden
-
-
+
+
{/* Desktop Table */}
-
-
-
-
- No
-
- Nama
- Tanggal
- Jenis Kelamin
-
- Aksi
-
-
-
-
- {filteredData.length === 0 ? (
+
+
+ Daftar Responden
+
+
+
-
-
- Tidak ada data yang cocok dengan pencarian
-
-
+ No
+ Nama
+ Tanggal
+ Jenis Kelamin
+ Aksi
- ) : (
- filteredData.map((item, index) => (
-
- {index + 1}
- {item.name}
-
- {item.tanggal ? new Date(item.tanggal).toLocaleDateString('id-ID') : '-'}
-
- {item.jenisKelamin.name}
-
- }
- onClick={() =>
- router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${item.id}`)
- }
- >
- Detail
-
+
+
+ {filteredData.length === 0 ? (
+
+
+
+ Tidak ditemukan data dengan kata kunci pencarian
+
- ))
- )}
-
-
+ ) : (
+ filteredData.map((item, index) => (
+
+ {index + 1}
+ {item.name}
+
+ {item.tanggal
+ ? new Date(item.tanggal).toLocaleDateString('id-ID', {
+ day: '2-digit',
+ month: 'long',
+ year: 'numeric',
+ })
+ : '-'}
+
+ {item.jenisKelamin.name}
+
+ }
+ onClick={() =>
+ router.push(
+ `/admin/ppid/indeks-kepuasan-masyarakat/responden/${item.id}`
+ )
+ }
+ >
+ Detail
+
+
+
+ ))
+ )}
+
+
+
- {/* Mobile Card View */}
+ {/* Mobile Cards */}
- {filteredData.length === 0 ? (
-
- Tidak ada data yang cocok dengan pencarian
-
- ) : (
-
- {filteredData.map((item, index) => (
-
+
+
+ Daftar Responden
+
+ {filteredData.length === 0 ? (
+
+
+ Tidak ditemukan data dengan kata kunci pencarian
+
+
+ ) : (
+ filteredData.map((item) => (
+
-
-
- No
-
-
- {index + 1}
-
-
-
-
- Nama
-
-
- {item.name}
-
-
-
-
- Tanggal
-
-
- {item.tanggal
- ? new Date(item.tanggal).toLocaleDateString('id-ID')
- : '-'}
-
-
-
-
- Jenis Kelamin
-
-
- {item.jenisKelamin.name}
-
-
-
- }
- onClick={() =>
- router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${item.id}`)
- }
- >
- Detail
-
-
+ Nama
+ {item.name}
+
+ Tanggal
+
+ {item.tanggal
+ ? new Date(item.tanggal).toLocaleDateString('id-ID', {
+ day: '2-digit',
+ month: 'long',
+ year: 'numeric',
+ })
+ : '-'}
+
+
+ Jenis Kelamin
+ {item.jenisKelamin.name}
+
+ }
+ onClick={() =>
+ router.push(
+ `/admin/ppid/indeks-kepuasan-masyarakat/responden/${item.id}`
+ )
+ }
+ mt="xs"
+ >
+ Detail
+
- ))}
-
- )}
+ ))
+ )}
+
- {filteredData.length > 0 && (
-
- {
- load(newPage, 10);
- window.scrollTo({ top: 0, behavior: 'smooth' });
- }}
- size="md"
- radius="md"
- />
-
- )}
+
+ {
+ load(newPage, 10);
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ }}
+ size="md"
+ radius="md"
+ mt={{ base: 'md', md: 'lg' }}
+ />
+
-
+
);
}
diff --git a/src/app/admin/(dashboard)/user&role/layout.tsx b/src/app/admin/(dashboard)/user&role/layout.tsx
deleted file mode 100644
index 05048967..00000000
--- a/src/app/admin/(dashboard)/user&role/layout.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-/* eslint-disable react-hooks/exhaustive-deps */
-'use client'
-import colors from '@/con/colors';
-import { Box, ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
-import { IconBrush, IconForms, IconUser } 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: "User",
- value: "user",
- href: "/admin/user&role/user",
- icon: ,
- },
- {
- label: "Role",
- value: "role",
- href: "/admin/user&role/role",
- icon: ,
- },
- {
- label: "Menu Access",
- value: "menu-access",
- href: "/admin/user&role/menu-access",
- icon: ,
- }
- ];
-
- 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]);
-
- return (
-
-
- User & Role
-
-
-
-
-
- {tabs.map((tab, i) => (
-
- {tab.label}
-
- ))}
-
-
-
-
-
-
-
-
- {tabs.map((tab, i) => (
-
- {tab.label}
-
- ))}
-
-
-
-
- {tabs.map((tab, i) => (
-
- {children}
-
- ))}
-
-
- );
-}
-
-export default LayoutTabs;
diff --git a/src/app/admin/(dashboard)/user&role/role/page.tsx b/src/app/admin/(dashboard)/user&role/role/page.tsx
index cc8a174d..b4439700 100644
--- a/src/app/admin/(dashboard)/user&role/role/page.tsx
+++ b/src/app/admin/(dashboard)/user&role/role/page.tsx
@@ -1,10 +1,11 @@
-/* eslint-disable react-hooks/exhaustive-deps */
'use client'
import colors from '@/con/colors';
import {
Box,
Button,
+ Center,
Group,
+ Pagination,
Paper,
Skeleton,
Stack,
@@ -17,9 +18,10 @@ import {
Text,
Title
} from '@mantine/core';
+import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
import { IconEdit, IconPlus, IconSearch, IconTrash } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
-import { useEffect, useState } from 'react';
+import { useState } from 'react';
import { useProxy } from 'valtio/utils';
import HeaderSearch from '../../_com/header';
import { ModalKonfirmasiHapus } from '../../_com/modalKonfirmasiHapus';
@@ -46,10 +48,12 @@ function ListRole({ search }: { search: string }) {
const router = useRouter();
const [modalHapus, setModalHapus] = useState(false);
const [selectedId, setSelectedId] = useState(null);
+ const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
+ const { data, page, totalPages, loading, load } = listDataState.findMany;
- useEffect(() => {
- listDataState.findMany.load();
- }, []);
+ useShallowEffect(() => {
+ load(page, 10, debouncedSearch);
+ }, [page, debouncedSearch]);
const handleDelete = () => {
if (selectedId) {
@@ -65,13 +69,14 @@ function ListRole({ search }: { search: string }) {
return item.name.toLowerCase().includes(keyword);
});
- if (!listDataState.findMany.data) {
- return (
-
-
-
- );
- }
+ if (loading || !data) {
+ return (
+
+
+
+ );
+ }
+
return (
@@ -199,6 +204,18 @@ function ListRole({ search }: { search: string }) {
+
+ {
+ load(newPage, 10);
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ }}
+ total={totalPages}
+ color="blue"
+ />
+
+
{/* Modal Konfirmasi Hapus */}
{
+ // Sort berdasarkan hierarki terlebih dahulu
+ if (a.posisi.hierarki !== b.posisi.hierarki) {
+ return a.posisi.hierarki - b.posisi.hierarki;
+ }
+ // Jika hierarki sama, sort berdasarkan nama posisi
+ return a.posisi.nama.localeCompare(b.posisi.nama);
+ });
+
+ // Lakukan pagination manual setelah sorting
+ const paginatedData = sortedData.slice(skip, skip + limit);
const totalPages = Math.ceil(total / limit);
return {
success: true,
- message: "Success fetch pegawai with pagination",
- data,
+ message: "Success fetch pegawai with hierarchy order",
+ data: paginatedData,
page,
totalPages,
total,
};
- } catch (e) {
- console.error("Find many paginated error:", e);
+ } catch (error) {
+ console.error("Find many pegawai error:", error);
return {
success: false,
- message: "Failed fetch pegawai with pagination",
+ message: "Failed fetch pegawai",
data: [],
page: 1,
totalPages: 1,
total: 0,
};
}
-}
\ No newline at end of file
+}
diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-bumdes/pegawai/findManyAll.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-bumdes/pegawai/findManyAll.ts
new file mode 100644
index 00000000..fbef28a0
--- /dev/null
+++ b/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-bumdes/pegawai/findManyAll.ts
@@ -0,0 +1,48 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import prisma from "@/lib/prisma";
+import { Context } from "elysia";
+
+export default async function pegawaiFindManyAll(context: Context) {
+ const search = (context.query.search as string) || "";
+ const isActiveParam = context.query.isActive;
+
+ // Buat where clause dinamis
+ const where: any = {};
+
+ if (isActiveParam !== undefined) {
+ where.isActive = isActiveParam === "true";
+ }
+
+ if (search) {
+ where.OR = [
+ { namaLengkap: { contains: search, mode: "insensitive" } },
+ { alamat: { contains: search, mode: "insensitive" } },
+ ];
+ }
+
+ try {
+ const data = await prisma.pegawaiBumDes.findMany({
+ where,
+ include: {
+ posisi: true,
+ image: true,
+ },
+ orderBy: { posisi: { hierarki: "asc" } },
+ });
+
+ return {
+ success: true,
+ message: "Success fetch all pegawai (non-paginated)",
+ total: data.length,
+ data,
+ };
+ } catch (error) {
+ console.error("Find many all error:", error);
+ return {
+ success: false,
+ message: "Failed fetch all pegawai",
+ total: 0,
+ data: [],
+ };
+ }
+}
diff --git a/src/app/api/[[...slugs]]/_lib/pendidikan/data-pendidikan/findMany.ts b/src/app/api/[[...slugs]]/_lib/pendidikan/data-pendidikan/findMany.ts
index 395beef9..addb6970 100644
--- a/src/app/api/[[...slugs]]/_lib/pendidikan/data-pendidikan/findMany.ts
+++ b/src/app/api/[[...slugs]]/_lib/pendidikan/data-pendidikan/findMany.ts
@@ -1,8 +1,49 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma";
+import { Context } from "elysia";
-export default async function dataPendidikanFindMany() {
- const res = await prisma.dataPendidikan.findMany();
- return {
- data: res,
- };
-}
\ No newline at end of file
+export default async function dataPendidikanFindMany(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;
+
+ const where: any = { isActive: true };
+
+ // Tambahkan pencarian (jika ada)
+ if (search) {
+ where.OR = [
+ { name: { contains: search, mode: 'insensitive' } },
+ { jumlah: { contains: search, mode: 'insensitive' } },
+ ];
+ }
+
+ try {
+ const [data, total] = await Promise.all([
+ prisma.dataPendidikan.findMany({
+ where,
+ skip,
+ take: limit,
+ orderBy: { name: "asc" }, // opsional, kalau mau urut berdasarkan waktu
+ }),
+ prisma.dataPendidikan.count({
+ where: { isActive: true },
+ }),
+ ]);
+
+ return {
+ success: true,
+ message: "Success fetch program inovasi with pagination",
+ data,
+ page,
+ totalPages: Math.ceil(total / limit),
+ total,
+ };
+ } catch (e) {
+ console.error("Find many paginated error:", e);
+ return {
+ success: false,
+ message: "Failed fetch program inovasi with pagination",
+ };
+ }
+ }
\ No newline at end of file
diff --git a/src/app/api/[[...slugs]]/_lib/user/role/findMany.ts b/src/app/api/[[...slugs]]/_lib/user/role/findMany.ts
index f4a3a343..cf8bc346 100644
--- a/src/app/api/[[...slugs]]/_lib/user/role/findMany.ts
+++ b/src/app/api/[[...slugs]]/_lib/user/role/findMany.ts
@@ -1,11 +1,49 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma";
+import { Context } from "elysia";
-export default async function roleFindMany() {
- const data = await prisma.role.findMany();
+export default async function roleFindMany(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;
- return {
- success: true,
- message: "Success get all role",
- data,
- };
+ const where: any = { isActive: true };
+
+ // Tambahkan pencarian (jika ada)
+ if (search) {
+ where.OR = [
+ { name: { contains: search, mode: 'insensitive' } },
+ { description: { contains: search, mode: 'insensitive' } },
+ ];
+ }
+
+ try {
+ const [data, total] = await Promise.all([
+ prisma.role.findMany({
+ where,
+ skip,
+ take: limit,
+ orderBy: { name: "asc" }, // opsional, kalau mau urut berdasarkan waktu
+ }),
+ prisma.role.count({
+ where: { isActive: true },
+ }),
+ ]);
+
+ return {
+ success: true,
+ message: "Success fetch role with pagination",
+ data,
+ page,
+ totalPages: Math.ceil(total / limit),
+ total,
+ };
+ } catch (e) {
+ console.error("Find many paginated error:", e);
+ return {
+ success: false,
+ message: "Failed fetch role with pagination",
+ };
+ }
}