Menerapkan pagination di submenu pegawai & berita

This commit is contained in:
2025-07-10 10:46:58 +08:00
parent 7b2b306849
commit 2bc9b2f3c6
6 changed files with 566 additions and 400 deletions

View File

@@ -80,13 +80,33 @@ const berita = proxy({
}; };
}>[] }>[]
| null, | null,
async load() { page: 1,
const res = await ApiFetch.api.desa.berita["find-many"].get(); totalPages: 1,
if (res.status === 200) { loading: false,
berita.findMany.data = (res.data?.data ) ?? [];
async load(page = 1, limit = 10) {
berita.findMany.loading = true;
berita.findMany.page = page;
try {
const res = await ApiFetch.api.desa.berita["find-many"].get({
query: {
page,
limit,
},
});
if (res.status === 200 && res.data?.success) {
berita.findMany.data = res.data.data ?? [];
berita.findMany.totalPages = res.data.totalPages ?? 1;
}
} catch (err) {
console.error("Gagal fetch berita paginated:", err);
} finally {
berita.findMany.loading = false;
} }
}, },
}, },
findUnique: { findUnique: {
data: null as data: null as
| Prisma.BeritaGetPayload<{ | Prisma.BeritaGetPayload<{

View File

@@ -30,9 +30,9 @@ const posisiOrganisasi = proxy({
try { try {
this.loading = true; this.loading = true;
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["posisi-organisasi"]["create"].post( const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
this.form "posisi-organisasi"
); ]["create"].post(this.form);
if (res.status === 200) { if (res.status === 200) {
toast.success("Berhasil menambahkan posisi organisasi"); toast.success("Berhasil menambahkan posisi organisasi");
posisiOrganisasi.findMany.load(); posisiOrganisasi.findMany.load();
@@ -62,12 +62,15 @@ const posisiOrganisasi = proxy({
return null; return null;
} }
try { try {
const response = await fetch(`/api/ekonomi/struktur-organisasi/posisi-organisasi/${id}`, { const response = await fetch(
`/api/ekonomi/struktur-organisasi/posisi-organisasi/${id}`,
{
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}); }
);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }
@@ -160,7 +163,9 @@ const posisiOrganisasi = proxy({
}>, }>,
async load() { async load() {
try { try {
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["posisi-organisasi"]["find-many"].get(); const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
"posisi-organisasi"
]["find-many"].get();
if (res.status === 200) { if (res.status === 200) {
// The API now returns the id field, so we can use it directly // The API now returns the id field, so we can use it directly
this.data = res.data?.data ?? []; this.data = res.data?.data ?? [];
@@ -239,16 +244,16 @@ const templatePegawai = z.object({
async submit() { async submit() {
const cek = templatePegawai.safeParse(pegawai.create.form); const cek = templatePegawai.safeParse(pegawai.create.form);
if (!cek.success) { if (!cek.success) {
const err = cek.error.issues.map(i => i.message).join("\n"); const err = cek.error.issues.map((i) => i.message).join("\n");
toast.error(err); toast.error(err);
return; return;
} }
try { try {
pegawai.create.loading = true; pegawai.create.loading = true;
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["pegawai"]["create"].post( const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
pegawai.create.form "pegawai"
); ]["create"].post(pegawai.create.form);
if (res.status === 200) { if (res.status === 200) {
toast.success("Pegawai berhasil ditambahkan"); toast.success("Pegawai berhasil ditambahkan");
await pegawai.findMany.load(); await pegawai.findMany.load();
@@ -263,36 +268,60 @@ const templatePegawai = z.object({
} }
}, },
}, },
// In struktur-organisasi.ts
findMany: { findMany: {
data: null as (Prisma.PegawaiGetPayload<{ include: { posisi: true, image: true } }> & { isActive: boolean })[] | null, data: null as any[] | null,
async load() { page: 1,
totalPages: 1,
total: 0,
loading: false,
load: async (page = 1, limit = 10) => { // Change to arrow function
pegawai.findMany.loading = true; // Use the full path to access the property
pegawai.findMany.page = page;
try { try {
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["pegawai"]["find-many"].get(); const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
if (res.status === 200) { "pegawai"
pegawai.findMany.data = (res.data?.data ?? []).map((item: any) => ({ ]["find-many"].get({
...item, query: { page, limit },
posisi: item.posisi || { id: '', nama: '' }, // Ensure posisi exists with required fields });
isActive: item.isActive ?? true // Default to true if not provided
})); if (res.status === 200 && res.data?.success) {
pegawai.findMany.data = res.data.data || [];
pegawai.findMany.total = res.data.total || 0;
pegawai.findMany.totalPages = res.data.totalPages || 1;
} else { } else {
console.error('Failed to load pegawai:', res.data?.message); console.error("Failed to load pegawai:", res.data?.message);
pegawai.findMany.data = [];
pegawai.findMany.total = 0;
pegawai.findMany.totalPages = 1;
} }
} catch (error) { } catch (error) {
console.error('Error loading pegawai:', error); console.error("Error loading pegawai:", error);
pegawai.findMany.data = []; pegawai.findMany.data = [];
pegawai.findMany.total = 0;
pegawai.findMany.totalPages = 1;
} finally {
pegawai.findMany.loading = false;
} }
}, },
}, },
findUnique: { findUnique: {
data: null as (Prisma.PegawaiGetPayload<{ include: { posisi: true, image: true } }> & { isActive: boolean }) | null, data: null as
| (Prisma.PegawaiGetPayload<{
include: { posisi: true; image: true };
}> & { isActive: boolean })
| null,
async load(id: string) { async load(id: string) {
const res = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${id}`); const res = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${id}`);
if (res.ok) { if (res.ok) {
const json = await res.json(); const json = await res.json();
pegawai.findUnique.data = json.data ? { pegawai.findUnique.data = json.data
? {
...json.data, ...json.data,
isActive: json.data.isActive ?? json.data.aktif ?? true // Fallback ke aktif:true jika tidak ada data isActive: json.data.isActive ?? json.data.aktif ?? true, // Fallback ke aktif:true jika tidak ada data
} : null; }
: null;
} else { } else {
pegawai.findUnique.data = null; pegawai.findUnique.data = null;
} }
@@ -305,9 +334,12 @@ const templatePegawai = z.object({
if (!id) return toast.warn("ID tidak valid"); if (!id) return toast.warn("ID tidak valid");
try { try {
pegawai.delete.loading = true; pegawai.delete.loading = true;
const res = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/del/${id}`, { const res = await fetch(
`/api/ekonomi/struktur-organisasi/pegawai/del/${id}`,
{
method: "DELETE", method: "DELETE",
}); }
);
const json = await res.json(); const json = await res.json();
if (res.ok) { if (res.ok) {
toast.success(json.message ?? "Berhasil hapus pegawai"); toast.success(json.message ?? "Berhasil hapus pegawai");
@@ -336,12 +368,15 @@ const templatePegawai = z.object({
} }
try { try {
const response = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${id}`, { const response = await fetch(
method: 'GET', `/api/ekonomi/struktur-organisasi/pegawai/${id}`,
{
method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
}, },
}); }
);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
@@ -369,7 +404,9 @@ const templatePegawai = z.object({
} }
} catch (error) { } catch (error) {
console.error("Error loading berita:", error); console.error("Error loading berita:", error);
toast.error(error instanceof Error ? error.message : "Gagal memuat data"); toast.error(
error instanceof Error ? error.message : "Gagal memuat data"
);
return null; return null;
} }
}, },
@@ -392,10 +429,12 @@ const templatePegawai = z.object({
? new Date(this.form.tanggalMasuk).toISOString() ? new Date(this.form.tanggalMasuk).toISOString()
: undefined; : undefined;
const response = await fetch(`/api/ekonomi/struktur-organisasi/pegawai/${this.id}`, { const response = await fetch(
method: 'PUT', `/api/ekonomi/struktur-organisasi/pegawai/${this.id}`,
{
method: "PUT",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
id: this.id, id: this.id,
@@ -409,11 +448,14 @@ const templatePegawai = z.object({
posisiId: this.form.posisiId, posisiId: this.form.posisiId,
isActive: this.form.isActive, isActive: this.form.isActive,
}), }),
}); }
);
if (!response.ok) { if (!response.ok) {
const errorData = await response.json().catch(() => ({})); const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || `HTTP error! status: ${response.status}`); throw new Error(
errorData.message || `HTTP error! status: ${response.status}`
);
} }
const result = await response.json(); const result = await response.json();
@@ -427,7 +469,11 @@ const templatePegawai = z.object({
} }
} catch (error) { } catch (error) {
console.error("Error updating pegawai:", error); console.error("Error updating pegawai:", error);
toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat update pegawai"); toast.error(
error instanceof Error
? error.message
: "Terjadi kesalahan saat update pegawai"
);
return false; return false;
} finally { } finally {
pegawai.edit.loading = false; pegawai.edit.loading = false;
@@ -441,7 +487,6 @@ const templatePegawai = z.object({
}, },
}); });
// Schema Zod untuk form validasi // Schema Zod untuk form validasi
const templateHubunganOrganisasiForm = z.object({ const templateHubunganOrganisasiForm = z.object({
atasanId: z.string().min(1, "Atasan wajib dipilih"), atasanId: z.string().min(1, "Atasan wajib dipilih"),
@@ -474,7 +519,9 @@ const hubunganOrganisasi = proxy({
try { try {
hubunganOrganisasi.create.loading = true; hubunganOrganisasi.create.loading = true;
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["hubungan-organisasi"]["create"].post(hubunganOrganisasi.create.form); const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
"hubungan-organisasi"
]["create"].post(hubunganOrganisasi.create.form);
if (res.status === 200 && res.data?.success) { if (res.status === 200 && res.data?.success) {
hubunganOrganisasi.findMany.load(); hubunganOrganisasi.findMany.load();
@@ -528,20 +575,29 @@ const hubunganOrganisasi = proxy({
async load() { async load() {
try { try {
const res = await ApiFetch.api.ekonomi["struktur-organisasi"]["hubungan-organisasi"]["find-many"].get(); const res = await ApiFetch.api.ekonomi["struktur-organisasi"][
"hubungan-organisasi"
]["find-many"].get();
if (res.status === 200) { if (res.status === 200) {
hubunganOrganisasi.findMany.data = (res.data?.data ?? []).map((item: any) => ({ hubunganOrganisasi.findMany.data = (res.data?.data ?? []).map(
(item: any) => ({
...item, ...item,
atasan: item.atasan ? { atasan: item.atasan
? {
...item.atasan, ...item.atasan,
isActive: item.atasan.isActive ?? item.atasan.aktif ?? true isActive: item.atasan.isActive ?? item.atasan.aktif ?? true,
} : null, }
bawahan: item.bawahan ? { : null,
bawahan: item.bawahan
? {
...item.bawahan, ...item.bawahan,
isActive: item.bawahan.isActive ?? item.bawahan.aktif ?? true isActive:
} : null item.bawahan.isActive ?? item.bawahan.aktif ?? true,
})); }
: null,
})
);
} else { } else {
hubunganOrganisasi.findMany.data = []; hubunganOrganisasi.findMany.data = [];
} }
@@ -591,7 +647,9 @@ const hubunganOrganisasi = proxy({
async load(id: string) { async load(id: string) {
try { try {
const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`); const res = await fetch(
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`
);
const result = await res.json(); const result = await res.json();
if (res.ok && result?.success) { if (res.ok && result?.success) {
@@ -616,7 +674,9 @@ const hubunganOrganisasi = proxy({
if (!id) return toast.warn("ID tidak valid"); if (!id) return toast.warn("ID tidak valid");
try { try {
const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`); const res = await fetch(
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`
);
const result = await res.json(); const result = await res.json();
if (res.ok && result?.success) { if (res.ok && result?.success) {
@@ -633,7 +693,9 @@ const hubunganOrganisasi = proxy({
} }
} catch (error) { } catch (error) {
console.error("Error loading:", error); console.error("Error loading:", error);
toast.error(error instanceof Error ? error.message : "Gagal memuat data"); toast.error(
error instanceof Error ? error.message : "Gagal memuat data"
);
return null; return null;
} }
}, },
@@ -690,9 +752,12 @@ const hubunganOrganisasi = proxy({
try { try {
hubunganOrganisasi.delete.loading = true; hubunganOrganisasi.delete.loading = true;
const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/del/${id}`, { const res = await fetch(
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/del/${id}`,
{
method: "DELETE", method: "DELETE",
}); }
);
const result = await res.json(); const result = await res.json();
if (res.ok && result?.success) { if (res.ok && result?.success) {

View File

@@ -1,6 +1,6 @@
'use client' 'use client'
import colors from '@/con/colors'; import colors from '@/con/colors';
import { Box, Button, Grid, GridCol, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core'; import { Box, Button, Grid, GridCol, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks'; import { useShallowEffect } from '@mantine/hooks';
import { IconCircleDashedPlus, IconDeviceImacCog, IconSearch } from '@tabler/icons-react'; import { IconCircleDashedPlus, IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
@@ -29,12 +29,21 @@ function Berita() {
function ListBerita({ search }: { search: string }) { function ListBerita({ search }: { search: string }) {
const beritaState = useProxy(stateDashboardBerita) const beritaState = useProxy(stateDashboardBerita)
const router = useRouter() const router = useRouter()
const {
data,
page,
totalPages,
loading,
load,
} = beritaState.berita.findMany;
// Fetch pertama kali
useShallowEffect(() => { useShallowEffect(() => {
beritaState.berita.findMany.load() load(page); // awal page = 1
}, []) }, []);
const filteredData = (beritaState.berita.findMany.data || []).filter(item => { const filteredData = (data || []).filter((item) => {
const keyword = search.toLowerCase(); const keyword = search.toLowerCase();
return ( return (
item.judul.toLowerCase().includes(keyword) || item.judul.toLowerCase().includes(keyword) ||
@@ -42,38 +51,50 @@ function ListBerita({ search }: { search: string }) {
); );
}); });
if (loading || !data) {
if (!beritaState.berita.findMany.data) { return <Skeleton h={500} />;
return (
<Stack py={10}>
<Skeleton h={500} />
</Stack>
)
} }
return ( return (
<Box py={10}> <Box py={10}>
<Paper bg={colors['white-1']} p={'md'}> <Pagination
value={page}
onChange={(newPage) => load(newPage)} // ini penting!
total={totalPages}
mt="md"
mb="md"
/>
<Paper bg={colors["white-1"]} p={"md"}>
<Stack> <Stack>
<Grid> <Grid>
<GridCol span={{ base: 12, md: 11 }}> <GridCol span={{ base: 12, md: 11 }}>
<Text fz={"xl"} fw={"bold"}>List Berita</Text> <Text fz={"xl"} fw={"bold"}>
List Berita
</Text>
</GridCol> </GridCol>
<GridCol span={{ base: 12, md: 1 }}> <GridCol span={{ base: 12, md: 1 }}>
<Button onClick={() => router.push("/admin/desa/berita/create")} bg={colors['blue-button']}> <Button
onClick={() => router.push("/admin/desa/berita/create")}
bg={colors["blue-button"]}
>
<IconCircleDashedPlus size={25} /> <IconCircleDashedPlus size={25} />
</Button> </Button>
</GridCol> </GridCol>
</Grid> </Grid>
<Box style={{ overflowX: "auto" }}> <Box style={{ overflowX: "auto" }}>
<Table striped withRowBorders withTableBorder style={{ minWidth: '700px' }}> <Table
striped
withRowBorders
withTableBorder
style={{ minWidth: "700px" }}
>
<TableThead> <TableThead>
<TableTr> <TableTr>
<TableTh w={250}>Judul</TableTh> <TableTh w={250}>Judul</TableTh>
<TableTh w={250}>Kategori</TableTh> <TableTh w={250}>Kategori</TableTh>
<TableTh w={250}>Image</TableTh> <TableTh w={250}>Image</TableTh>
<TableTh w={200}>Detail</TableTh> <TableTh w={200}>Detail</TableTh>
</TableTr> </TableTr>
</TableThead> </TableThead>
<TableTbody> <TableTbody>
@@ -81,7 +102,9 @@ function ListBerita({ search }: { search: string }) {
<TableTr key={item.id}> <TableTr key={item.id}>
<TableTd> <TableTd>
<Box w={100}> <Box w={100}>
<Text truncate="end" fz={"sm"}>{item.judul}</Text> <Text truncate="end" fz={"sm"}>
{item.judul}
</Text>
</Box> </Box>
</TableTd> </TableTd>
<TableTd>{item.kategoriBerita?.name}</TableTd> <TableTd>{item.kategoriBerita?.name}</TableTd>
@@ -89,20 +112,23 @@ function ListBerita({ search }: { search: string }) {
<Image w={100} src={item.image?.link} alt="gambar" /> <Image w={100} src={item.image?.link} alt="gambar" />
</TableTd> </TableTd>
<TableTd> <TableTd>
<Button bg={"green"} onClick={() => router.push(`/admin/desa/berita/${item.id}`)}> <Button
bg={"green"}
onClick={() =>
router.push(`/admin/desa/berita/${item.id}`)
}
>
<IconDeviceImacCog size={25} /> <IconDeviceImacCog size={25} />
</Button> </Button>
</TableTd> </TableTd>
</TableTr> </TableTr>
))} ))}
</TableTbody> </TableTbody>
</Table> </Box> </Table>
</Box>
</Stack> </Stack>
</Paper> </Paper>
</Box> </Box>
) );
} }
export default Berita; export default Berita;

View File

@@ -1,10 +1,10 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
'use client' 'use client'
import colors from '@/con/colors'; import colors from '@/con/colors';
import { Badge, Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core'; import { Badge, Box, Button, Center, Group, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, ThemeIcon } from '@mantine/core';
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react'; import { IconCheck, IconDeviceImacCog, IconSearch, IconX } from '@tabler/icons-react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { useProxy } from 'valtio/utils'; import { useProxy } from 'valtio/utils';
import HeaderSearch from '../../../_com/header'; import HeaderSearch from '../../../_com/header';
import JudulList from '../../../_com/judulList'; import JudulList from '../../../_com/judulList';
@@ -30,35 +30,21 @@ function ListPegawai({ search }: { search: string }) {
const stateOrganisasi = useProxy(strukturorganisasiState.pegawai); const stateOrganisasi = useProxy(strukturorganisasiState.pegawai);
const router = useRouter(); const router = useRouter();
const {
data,
page,
totalPages,
loading,
load,
} = stateOrganisasi.findMany;
useEffect(() => { useEffect(() => {
const loadData = async () => { load(page, 10);
try { }, [page]);
// Clear existing data to ensure we see the loading state
stateOrganisasi.findMany.data = [];
// Load new data const filteredData = useMemo(() => {
await stateOrganisasi.findMany.load(); if (!data) return [];
return data.filter(item => {
// Type guard to ensure data is an array
const data = stateOrganisasi.findMany.data || [];
if (data.length > 0) {
console.log('4. First record sample:', data[0]);
}
} catch (error) {
console.error('Error loading pegawai data:', error);
stateOrganisasi.findMany.data = [];
}
};
loadData();
// Cleanup function
return () => {
console.log('Cleanup: Unmounting component');
};
}, []);
const filteredData = (stateOrganisasi.findMany.data || []).filter(item => {
const keyword = search.toLowerCase(); const keyword = search.toLowerCase();
return ( return (
item.namaLengkap?.toLowerCase().includes(keyword) || item.namaLengkap?.toLowerCase().includes(keyword) ||
@@ -67,9 +53,10 @@ function ListPegawai({ search }: { search: string }) {
item.posisi?.nama?.toLowerCase().includes(keyword) item.posisi?.nama?.toLowerCase().includes(keyword)
); );
}); });
}, [data, search]);
// Handle loading state // Handle loading state
if (stateOrganisasi.findMany.data === null) { if (loading || !data) {
return ( return (
<Stack py={10}> <Stack py={10}>
<Skeleton height={300} /> <Skeleton height={300} />
@@ -77,8 +64,6 @@ function ListPegawai({ search }: { search: string }) {
); );
} }
// Check if data is an empty array
const data = stateOrganisasi.findMany.data || [];
if (data.length === 0) { if (data.length === 0) {
return ( return (
<Box py={10}> <Box py={10}>
@@ -95,6 +80,7 @@ function ListPegawai({ search }: { search: string }) {
title='List Pegawai' title='List Pegawai'
href='/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/create' href='/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/create'
/> />
<Box style={{ overflowX: "auto" }}>
<Table striped withTableBorder withRowBorders> <Table striped withTableBorder withRowBorders>
<TableThead> <TableThead>
<TableTr> <TableTr>
@@ -125,7 +111,24 @@ function ListPegawai({ search }: { search: string }) {
<TableTd>{item.telepon}</TableTd> <TableTd>{item.telepon}</TableTd>
<TableTd>{item.posisi?.nama}</TableTd> <TableTd>{item.posisi?.nama}</TableTd>
<TableTd> <TableTd>
<Badge color={item.isActive ? "green" : "red"}>{item.isActive ? "Aktif" : "Tidak Aktif"}</Badge> <Group gap="xs" wrap="nowrap">
<Box visibleFrom="sm">
<Badge color={item.isActive ? "green" : "red"}>
{item.isActive ? "Aktif" : "Tidak Aktif"}
</Badge>
</Box>
<Box hiddenFrom="sm">
{item.isActive ? (
<ThemeIcon color="green" variant="light" size="sm">
<IconCheck size={16} />
</ThemeIcon>
) : (
<ThemeIcon color="red" variant="light" size="sm">
<IconX size={16} />
</ThemeIcon>
)}
</Box>
</Group>
</TableTd> </TableTd>
<TableTd> <TableTd>
<Button bg={"green"} onClick={() => router.push(`/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/${item.id}`)}> <Button bg={"green"} onClick={() => router.push(`/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/${item.id}`)}>
@@ -136,7 +139,20 @@ function ListPegawai({ search }: { search: string }) {
))} ))}
</TableTbody> </TableTbody>
</Table> </Table>
</Box>
</Paper> </Paper>
<Center>
<Pagination
value={page}
onChange={(newPage) => {
load(newPage, 10);
window.scrollTo(0, 0);
}}
total={totalPages}
mt="md"
mb="md"
/>
</Center>
</Box> </Box>
); );
} }

View File

@@ -1,27 +1,44 @@
// /api/berita/findManyPaginated.ts
import prisma from "@/lib/prisma"; import prisma from "@/lib/prisma";
import { Context } from "elysia";
async function beritaFindManyPaginated(context: Context) {
const page = Number(context.query.page) || 1;
const limit = Number(context.query.limit) || 10;
const skip = (page - 1) * limit;
async function beritaFindMany() {
try { try {
const data = await prisma.berita.findMany({ const [data, total] = await Promise.all([
prisma.berita.findMany({
where: { isActive: true }, where: { isActive: true },
include: { include: {
image: true, image: true,
kategoriBerita: true, kategoriBerita: true,
}, },
}); skip,
take: limit,
orderBy: { createdAt: 'desc' }, // opsional, kalau mau urut berdasarkan waktu
}),
prisma.berita.count({
where: { isActive: true }
})
]);
return { return {
success: true, success: true,
message: "Success fetch berita", message: "Success fetch berita with pagination",
data, data,
page,
totalPages: Math.ceil(total / limit),
total,
}; };
} catch (e) { } catch (e) {
console.error("Find many error:", e); console.error("Find many paginated error:", e);
return { return {
success: false, success: false,
message: "Failed fetch berita", message: "Failed fetch berita with pagination",
}; };
} }
} }
export default beritaFindMany; export default beritaFindManyPaginated;

View File

@@ -1,26 +1,48 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma"; import prisma from "@/lib/prisma";
import { Context } from "elysia";
// Di findMany.ts
export default async function pegawaiFindMany(context: Context) {
const page = Number(context.query.page) || 1;
const limit = Number(context.query.limit) || 10;
const skip = (page - 1) * limit;
export default async function pegawaiFindMany() {
try { try {
const pegawaiList = await prisma.pegawai.findMany({ const [data, total] = await Promise.all([
orderBy: { createdAt: "desc" }, prisma.pegawai.findMany({
where: { isActive: true },
include: { include: {
posisi: true, posisi: true,
image: true, image: true,
}, },
}); skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.pegawai.count({
where: { isActive: true }
})
]);
const totalPages = Math.ceil(total / limit);
return { return {
success: true, success: true,
data: pegawaiList, message: "Success fetch pegawai with pagination",
data,
page,
totalPages,
total,
}; };
} catch (error: any) { } catch (e) {
console.error("Error findMany pegawai:", error); console.error("Find many paginated error:", e);
return { return {
success: false, success: false,
message: "Gagal mengambil data pegawai", message: "Failed fetch pegawai with pagination",
error: error.message, data: [],
page: 1,
totalPages: 1,
total: 0,
}; };
} }
} }