upd: detail warga

Deskripsi:
- pagination pada list pengaduan dan list pengajuan surat
- search pada list pengaduan dan list pengajuan surat

No Issues
This commit is contained in:
2026-01-09 15:46:30 +08:00
parent 3d641d2035
commit c0471f47f3
2 changed files with 248 additions and 66 deletions

View File

@@ -1,62 +1,66 @@
import notification from "@/components/notificationGlobal";
import apiFetch from "@/lib/apiFetch"; import apiFetch from "@/lib/apiFetch";
import { import {
Avatar, Avatar,
Box, Box,
Button, Button,
Card, Card,
CloseButton,
Container, Container,
Divider, Divider,
Flex, Flex,
Grid, Grid,
Group, Group,
Input,
LoadingOverlay, LoadingOverlay,
Pagination,
Stack, Stack,
Table, Table,
Text, Text,
Title, Title,
} from "@mantine/core"; } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import { IconPhone } from "@tabler/icons-react"; import { IconPhone, IconSearch } from "@tabler/icons-react";
import _ from "lodash"; import _ from "lodash";
import { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import useSwr from "swr";
export default function DetailWargaPage() { export default function DetailWargaPage() {
const { search } = useLocation(); const { search } = useLocation();
const query = new URLSearchParams(search); const query = new URLSearchParams(search);
const id = query.get("id"); const id = query.get("id");
const { data, mutate, isLoading } = useSwr("/", () => // const { data, mutate, isLoading } = useSwr("/", () =>
apiFetch.api.warga.detail.get({ // apiFetch.api.warga.detail.get({
query: { // query: {
id: id!, // id: id!,
}, // },
}), // }),
); // );
useShallowEffect(() => { // useShallowEffect(() => {
mutate(); // mutate();
}, []); // }, []);
return ( return (
<> <>
<LoadingOverlay <LoadingOverlay
visible={isLoading} // visible={isLoading}
zIndex={1000} zIndex={1000}
overlayProps={{ radius: "sm", blur: 2 }} overlayProps={{ radius: "sm", blur: 2 }}
/> />
<Container size="xl" py="xl" w={"100%"}> <Container size="xl" py="xl" w={"100%"}>
<Grid> <Grid>
<Grid.Col span={4}> <Grid.Col span={4}>
<DetailWarga data={data?.data?.warga} /> <DetailWarga id={id!} />
</Grid.Col> </Grid.Col>
<Grid.Col span={8}> <Grid.Col span={8}>
<Stack gap={"xl"}> <Stack gap={"xl"}>
<DetailDataHistori <DetailDataHistori
data={data?.data?.pengaduan} id={id!}
kategori="pengaduan" kategori="pengaduan"
/> />
<DetailDataHistori <DetailDataHistori
data={data?.data?.pelayanan} id={id!}
kategori="pelayanan" kategori="pelayanan"
/> />
</Stack> </Stack>
@@ -68,13 +72,66 @@ export default function DetailWargaPage() {
} }
function DetailDataHistori({ function DetailDataHistori({
data, id,
kategori, kategori,
}: { }: {
data: any; id: string;
kategori: "pengaduan" | "pelayanan"; kategori: "pengaduan" | "pelayanan";
}) { }) {
const navigate = useNavigate(); const navigate = useNavigate();
const [data, setData] = useState<any>([]);
const [totalPages, setTotalPages] = useState(1);
const [totalRows, setTotalRows] = useState(0);
const [page, setPage] = useState(1);
const [search, setSearch] = useState("");
async function getData() {
try {
const res = await apiFetch.api.warga.detail.get({
query: {
id,
category: kategori,
page: String(page),
search
}
}) as { data: { success: boolean; data: any[]; totalPages: number, totalRows: number } };
if (res?.data?.success) {
setData(res.data.data)
setTotalPages(res?.data?.totalPages)
setTotalRows(res?.data?.totalRows)
} else {
setData([])
setTotalPages(1)
setTotalRows(0)
notification({
title: "Failed",
message: "Failed to get data",
type: "error",
});
}
} catch (error) {
console.error(error);
notification({
title: "Failed",
message: "Failed to get data",
type: "error",
});
}
}
useShallowEffect(() => {
getData()
}, [page])
useShallowEffect(() => {
setPage(1)
if (page == 1) {
getData()
}
}, [search]);
return ( return (
<Card <Card
@@ -93,6 +150,36 @@ function DetailDataHistori({
<Title order={4} c="gray.2"> <Title order={4} c="gray.2">
Histori {_.upperFirst(kategori)} Histori {_.upperFirst(kategori)}
</Title> </Title>
<Flex
gap="md"
justify="flex-start"
align="center"
direction="row"
>
<Input
value={search}
placeholder="Cari data..."
onChange={(event) => setSearch(event.currentTarget.value)}
leftSection={<IconSearch size={16} />}
rightSectionPointerEvents="all"
rightSection={
<CloseButton
aria-label="Clear input"
onClick={() => setSearch("")}
style={{ display: search ? undefined : "none" }}
/>
}
/>
<Text size="sm" c="gray.5" >
{`${5 * (page - 1) + 1} ${Math.min(totalRows, 5 * page)} of ${totalRows}`}
</Text>
<Pagination
total={totalPages}
value={page}
onChange={setPage}
withPages={false}
/>
</Flex>
</Flex> </Flex>
<Divider my={0} /> <Divider my={0} />
<Table> <Table>
@@ -110,7 +197,7 @@ function DetailDataHistori({
{data?.length > 0 ? ( {data?.length > 0 ? (
data?.map((item: any, index: number) => ( data?.map((item: any, index: number) => (
<Table.Tr key={index}> <Table.Tr key={index}>
<Table.Td>{item.noPengaduan}</Table.Td> <Table.Td w={"180"}>{item.noPengaduan}</Table.Td>
<Table.Td> <Table.Td>
{kategori == "pengaduan" ? item.title : item.category} {kategori == "pengaduan" ? item.title : item.category}
</Table.Td> </Table.Td>
@@ -147,7 +234,33 @@ function DetailDataHistori({
); );
} }
function DetailWarga({ data }: { data: any }) { function DetailWarga({ id }: { id: string }) {
const [data, setData] = useState<any>(null);
async function getWarga() {
try {
const res = await apiFetch.api.warga.detail.get({
query: {
id: id,
category: "warga",
page: "1",
search: "",
},
});
setData(res.data);
} catch (error) {
console.error(error);
notification({
title: "Failed",
message: "Failed to get data warga",
type: "error",
});
}
}
useShallowEffect(() => {
getWarga();
}, []);
return ( return (
<Card <Card
radius="md" radius="md"

View File

@@ -97,21 +97,50 @@ const WargaRoute = new Elysia({
} }
}) })
.get("/detail", async ({ query }) => { .get("/detail", async ({ query }) => {
const { id } = query const { id, category, search, page } = query
const skip = !page ? 0 : (Number(page) - 1) * 5
const dataWarga = await prisma.warga.findUnique({ const dataWarga = await prisma.warga.findUnique({
where: { where: {
id id
} }
}) })
if (!dataWarga)
return { success: false, message: "data warga tidak ditemukan", data: null, totalPages: 1, totalRows: 0 }
if (category == "warga") {
return dataWarga
} else if (category == "pengaduan") {
const where: any = {
isActive: true,
idWarga: id,
OR: [
{
title: {
contains: search ?? "",
mode: "insensitive"
},
},
{
noPengaduan: {
contains: search ?? "",
mode: "insensitive"
},
}
]
}
const totalData = await prisma.pengaduan.count({
where
});
const dataPengaduan = await prisma.pengaduan.findMany({ const dataPengaduan = await prisma.pengaduan.findMany({
skip,
take: 5,
orderBy: { orderBy: {
createdAt: "desc" createdAt: "desc"
}, },
where: { where,
isActive: true,
idWarga: id
},
select: { select: {
id: true, id: true,
status: true, status: true,
@@ -120,16 +149,48 @@ const WargaRoute = new Elysia({
} }
}) })
const dataReturn = {
success: true,
message: "data pengaduan berhasil diambil",
data: dataPengaduan,
totalRows: totalData,
totalPages: Math.ceil(totalData / 5)
}
return dataReturn
} else if (category == "pelayanan") {
const where: any = {
isActive: true,
idWarga: id,
OR: [
{
CategoryPelayanan: {
name: {
contains: search ?? "",
mode: "insensitive"
},
},
},
{
noPengajuan: {
contains: search ?? "",
mode: "insensitive"
},
},
]
}
const totalData = await prisma.pelayananAjuan.count({
where
});
const dataPelayanan = await prisma.pelayananAjuan.findMany({ const dataPelayanan = await prisma.pelayananAjuan.findMany({
skip,
take: 5,
orderBy: { orderBy: {
createdAt: "desc" createdAt: "desc"
}, },
where: { where,
isActive: true,
idWarga: id
},
select: { select: {
id: true, id: true,
noPengajuan: true, noPengajuan: true,
@@ -150,15 +211,23 @@ const WargaRoute = new Elysia({
category: v.CategoryPelayanan.name category: v.CategoryPelayanan.name
})) }))
return { const dataReturn = {
warga: dataWarga, success: true,
pengaduan: dataPengaduan, message: "data pelayanan berhasil diambil",
pelayanan: dataPelayanFix data: dataPelayanFix,
totalRows: totalData,
totalPages: Math.ceil(totalData / 5)
}
return dataReturn
} }
}, { }, {
query: t.Object({ query: t.Object({
id: t.String({ minLength: 1, error: "id harus diisi" }) id: t.String({ minLength: 1, error: "id harus diisi" }),
category: t.String({ minLength: 1, error: "kategori harus diisi" }),
page: t.String({ optional: true }),
search: t.String({ optional: true }),
}), }),
detail: { detail: {
summary: "Detail Warga", summary: "Detail Warga",