Merge pull request 'amalia/02-des-25' (#55) from amalia/02-des-25 into main

Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/55
This commit is contained in:
2025-12-02 11:51:54 +08:00
5 changed files with 130 additions and 65 deletions

View File

@@ -21,7 +21,7 @@ export default function DashboardCountData() {
label="Pengaduan Hari Ini"
value={String(data?.data?.pengaduan?.today)}
change={String(data?.data?.pengaduan?.kenaikan) + "%"}
color={(data?.data?.pengaduan?.kenaikan || 0) > 0 ? "teal" : "gray"}
color={"gray"}
/>
</Grid.Col>
<Grid.Col span={{ base: 12, sm: 6, md: 4 }}>
@@ -30,7 +30,7 @@ export default function DashboardCountData() {
label="Pengajuan Surat Hari Ini"
value={String(data?.data?.pelayanan?.today)}
change={String(data?.data?.pelayanan?.kenaikan) + "%"}
color={(data?.data?.pelayanan?.kenaikan || 0) > 0 ? "teal" : "gray"}
color="gray"
/>
</Grid.Col>
<Grid.Col span={{ base: 12, sm: 6, md: 4 }}>

View File

@@ -6,8 +6,10 @@ import {
Container,
Divider,
Flex,
Grid,
Group,
Input,
Pagination,
Stack,
Tabs,
Text,
@@ -113,22 +115,26 @@ type StatusKey =
function ListPelayananSurat({ status }: { status: StatusKey }) {
const [page, setPage] = useState(1);
const [value, setValue] = useState("");
const { data, mutate, isLoading } = useSwr("/", async () => {
const res = await apiFetch.api.pelayanan.list.get({
const { data, mutate, isLoading } = useSwr("/", async () =>
apiFetch.api.pelayanan.list.get({
query: {
status,
search: value,
take: "",
page: "",
page: page.toString(),
},
});
})
);
useShallowEffect(() => {
setPage(1);
mutate();
}, [status, value]);
return Array.isArray(res?.data) ? res.data : []; // ⬅ paksa return array
});
useShallowEffect(() => {
mutate();
}, [status, value]);
}, [page]);
useShallowEffect(() => {
@@ -155,26 +161,39 @@ function ListPelayananSurat({ status }: { status: StatusKey }) {
</Card>
);
const list = data || [];
const list = data?.data?.data || [];
const total = data?.data?.total || 0;
const totalPage = data?.data?.totalPages || 1;
const pageSize = data?.data?.pageSize || 10;
const pageNow = data?.data?.page || 1;
const toDate = (d: any) => new Date(d);
return (
<Stack gap="xl">
<Group grow>
<Input
value={value}
placeholder="Cari pengajuan..."
onChange={(event) => setValue(event.currentTarget.value)}
leftSection={<IconSearch size={16} />}
rightSectionPointerEvents="all"
rightSection={
<CloseButton
aria-label="Clear input"
onClick={() => setValue("")}
style={{ display: value ? undefined : "none" }}
/>
}
/>
</Group>
<Grid>
<Grid.Col span={10}>
<Input
value={value}
placeholder="Cari pengajuan..."
onChange={(event) => setValue(event.currentTarget.value)}
leftSection={<IconSearch size={16} />}
rightSectionPointerEvents="all"
rightSection={
<CloseButton
aria-label="Clear input"
onClick={() => setValue("")}
style={{ display: value ? undefined : "none" }}
/>
}
/>
</Grid.Col>
<Grid.Col span={2}>
<Group justify="space-between" grow>
<Text size="sm">{`${pageSize * (page - 1) + 1} ${Math.min(total, pageSize * page)} of ${total}`}</Text>
<Pagination total={totalPage} value={page} onChange={setPage} withPages={false} />
</Group>
</Grid.Col>
</Grid>
{Array.isArray(list) && list?.length === 0 ? (
<Flex justify="center" align="center" py={"xl"}>
<Stack gap={4} align="center">
@@ -214,7 +233,7 @@ function ListPelayananSurat({ status }: { status: StatusKey }) {
#{v.noPengajuan}
</Title>
<Text size="sm" c="dimmed">
{v.updatedAt}
{String(v.updatedAt)}
</Text>
</Group>
</Flex>
@@ -247,7 +266,7 @@ function ListPelayananSurat({ status }: { status: StatusKey }) {
Tanggal Ajuan
</Text>
</Group>
<Text size="md">{v.createdAt}</Text>
<Text size="md">{toDate(v.createdAt).toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" })}</Text>
</Flex>
<Flex direction={"column"} justify="flex-start">
<Group gap="xs">

View File

@@ -6,8 +6,10 @@ import {
Container,
Divider,
Flex,
Grid,
Group,
Input,
Pagination,
Stack,
Tabs,
Text,
@@ -124,22 +126,25 @@ function ListPengaduan({ status }: { status: StatusKey }) {
const navigate = useNavigate();
const [page, setPage] = useState(1);
const [value, setValue] = useState("");
const { data, mutate, isLoading } = useSwr("/", async () => {
const res = await apiFetch.api.pengaduan.list.get({
const { data, mutate, isLoading } = useSwr("/", async () =>
apiFetch.api.pengaduan.list.get({
query: {
status,
search: value,
take: "",
page: "",
page: page.toString(),
},
});
})
);
return Array.isArray(res?.data) ? res.data : []; // ⬅ paksa return array
});
useShallowEffect(() => {
setPage(1);
mutate();
}, [status, value]);
useShallowEffect(() => {
mutate();
}, [status, value]);
}, [page]);
useShallowEffect(() => {
const unsubscribe = subscribe(state, () => mutate());
@@ -163,31 +168,41 @@ function ListPengaduan({ status }: { status: StatusKey }) {
</Card>
);
const list = data || [];
const list = data?.data?.data || [];
const total = data?.data?.total || 0;
const totalPage = data?.data?.totalPages || 1;
const pageSize = data?.data?.pageSize || 10;
const pageNow = data?.data?.page || 1;
const toDate = (d: any) => new Date(d);
return (
<Stack gap="xl">
<Group grow>
<Input
value={value}
placeholder="Cari pengaduan..."
onChange={(event) => setValue(event.currentTarget.value)}
leftSection={<IconSearch size={16} />}
rightSectionPointerEvents="all"
rightSection={
<CloseButton
aria-label="Clear input"
onClick={() => setValue("")}
style={{ display: value ? undefined : "none" }}
/>
}
/>
{/* <Group justify="flex-end">
<Text size="sm">Menampilkan {Number(data?.data?.length) * (page - 1) + 1} {Math.min(10, Number(data?.data?.length) * page)} dari {Number(data?.data?.length)}</Text>
<Pagination total={Number(data?.data?.length)} value={page} onChange={setPage} withPages={false} />
</Group> */}
</Group>
{list.length === 0 ? (
<Grid>
<Grid.Col span={10}>
<Input
value={value}
placeholder="Cari pengaduan..."
onChange={(event) => setValue(event.currentTarget.value)}
leftSection={<IconSearch size={16} />}
rightSectionPointerEvents="all"
rightSection={
<CloseButton
aria-label="Clear input"
onClick={() => setValue("")}
style={{ display: value ? undefined : "none" }}
/>
}
/>
</Grid.Col>
<Grid.Col span={2}>
<Group justify="space-between" grow>
<Text size="sm">{`${pageSize * (page - 1) + 1} ${Math.min(total, pageSize * page)} of ${total}`}</Text>
<Pagination total={totalPage} value={page} onChange={setPage} withPages={false} />
</Group>
</Grid.Col>
</Grid>
{Array.isArray(list) && list.length === 0 ? (
<Flex justify="center" align="center" py={"xl"}>
<Stack gap={4} align="center">
<IconFileSad size={32} color="gray" />
@@ -224,7 +239,7 @@ function ListPengaduan({ status }: { status: StatusKey }) {
#{v.noPengaduan}
</Title>
<Text size="sm" c="dimmed">
{v.updatedAt}
{String(v.updatedAt)}
</Text>
</Group>
</Flex>
@@ -257,7 +272,7 @@ function ListPengaduan({ status }: { status: StatusKey }) {
Tanggal Aduan
</Text>
</Group>
<Text size="md">{v.createdAt}</Text>
<Text size="md">{toDate(v.createdAt).toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" })}</Text>
</Flex>
<Flex direction={"column"} justify="flex-start">
<Group gap="xs">

View File

@@ -581,6 +581,14 @@ const PelayananRoute = new Elysia({
mode: "insensitive"
},
},
},
{
Warga: {
name: {
contains: search ?? "",
mode: "insensitive"
},
},
}
]
}
@@ -592,6 +600,11 @@ const PelayananRoute = new Elysia({
}
}
const totalData = await prisma.pelayananAjuan.count({
where
});
const data = await prisma.pelayananAjuan.findMany({
skip,
take: !take ? 10 : Number(take),
@@ -625,12 +638,20 @@ const PelayananRoute = new Elysia({
category: item.CategoryPelayanan.name,
warga: item.Warga.name,
status: item.status,
createdAt: item.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }),
createdAt: item.createdAt.toISOString(),
updatedAt: 'terakhir diperbarui ' + getLastUpdated(item.updatedAt),
}
})
return dataFix
const dataReturn = {
data: dataFix,
total: totalData,
page: Number(page) || 1,
pageSize: !take ? 10 : Number(take),
totalPages: Math.ceil(totalData / (!take ? 10 : Number(take)))
}
return dataReturn
}, {
query: t.Object({
take: t.String({ optional: true }),

View File

@@ -646,6 +646,10 @@ const PengaduanRoute = new Elysia({
}
}
const totalData = await prisma.pengaduan.count({
where
});
const data = await prisma.pengaduan.findMany({
skip,
take: !take ? 10 : Number(take),
@@ -683,12 +687,20 @@ const PengaduanRoute = new Elysia({
detail: item.detail,
status: item.status,
location: item.location,
createdAt: item.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }),
createdAt: item.createdAt.toISOString(),
updatedAt: 'terakhir diperbarui ' + getLastUpdated(item.updatedAt),
}
})
return dataFix
const dataReturn = {
data: dataFix,
total: totalData,
page: Number(page) || 1,
pageSize: !take ? 10 : Number(take),
totalPages: Math.ceil(totalData / (!take ? 10 : Number(take)))
}
return dataReturn
}, {
query: t.Object({
take: t.String({ optional: true }),
@@ -790,8 +802,6 @@ const PengaduanRoute = new Elysia({
description: "Tool untuk delete file Seafile",
},
})
;
export default PengaduanRoute