upd: dashboard
Deskripsi: - menu dashboard - tampilan pengaduan list No Issues
This commit is contained in:
@@ -1,27 +1,28 @@
|
||||
// ⚡ Auto-generated by generateRoutes.ts — DO NOT EDIT MANUALLY
|
||||
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||
import Login from "./pages/Login";
|
||||
import DarmasabaLayout from "./pages/darmasaba/darmasaba_layout";
|
||||
import FormSuratKeteranganUsaha from "./pages/darmasaba/form_surat_keterangan_usaha";
|
||||
import FormSuratKeteranganTidakMampu from "./pages/darmasaba/form_surat_keterangan_tidak_mampu";
|
||||
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
||||
import DarmasabaHome from "./pages/darmasaba/darmasaba_home";
|
||||
import FormKartuTandaPenduduk from "./pages/darmasaba/form_kartu_tanda_penduduk";
|
||||
import DarmasabaLayout from "./pages/darmasaba/darmasaba_layout";
|
||||
import FormKartuKeluarga from "./pages/darmasaba/form_kartu_keluarga";
|
||||
import FormLaporanSampah from "./pages/darmasaba/form_laporan_sampah";
|
||||
import FormSuratKeteranganPenghasilan from "./pages/darmasaba/form_surat_keterangan_penghasilan";
|
||||
import FormSuratKeteranganDomisiliOrganisasi from "./pages/darmasaba/form_surat_keterangan_domisili_organisasi";
|
||||
import FormSuratKeteranganBelumKawin from "./pages/darmasaba/form_surat_keterangan_belum_kawin";
|
||||
import FormKartuTandaPenduduk from "./pages/darmasaba/form_kartu_tanda_penduduk";
|
||||
import FormKeteranganKelahiran from "./pages/darmasaba/form_keterangan_kelahiran";
|
||||
import FormSuratKeteranganTempatUsaha from "./pages/darmasaba/form_surat_keterangan_tempat_usaha";
|
||||
import FormLaporanSampah from "./pages/darmasaba/form_laporan_sampah";
|
||||
import FormSuratKeteranganBelumKawin from "./pages/darmasaba/form_surat_keterangan_belum_kawin";
|
||||
import FormSuratKeteranganDomisiliOrganisasi from "./pages/darmasaba/form_surat_keterangan_domisili_organisasi";
|
||||
import FormSuratKeteranganKelakuanBaik from "./pages/darmasaba/form_surat_keterangan_kelakuan_baik";
|
||||
import FormSuratKeteranganPenghasilan from "./pages/darmasaba/form_surat_keterangan_penghasilan";
|
||||
import FormSuratKeteranganTempatUsaha from "./pages/darmasaba/form_surat_keterangan_tempat_usaha";
|
||||
import FormSuratKeteranganTidakMampu from "./pages/darmasaba/form_surat_keterangan_tidak_mampu";
|
||||
import FormSuratKeteranganUsaha from "./pages/darmasaba/form_surat_keterangan_usaha";
|
||||
import DirPage from "./pages/dir/dir_page";
|
||||
import Home from "./pages/Home";
|
||||
import Login from "./pages/Login";
|
||||
import NotFound from "./pages/NotFound";
|
||||
import ApikeyPage from "./pages/scr/dashboard/apikey/apikey_page";
|
||||
import CredentialPage from "./pages/scr/dashboard/credential/credential_page";
|
||||
import DashboardHome from "./pages/scr/dashboard/dashboard_home";
|
||||
import ApikeyPage from "./pages/scr/dashboard/apikey/apikey_page";
|
||||
import DashboardLayout from "./pages/scr/dashboard/dashboard_layout";
|
||||
import ListPage from "./pages/scr/dashboard/pengaduan/list_page";
|
||||
import ScrLayout from "./pages/scr/scr_layout";
|
||||
import DirPage from "./pages/dir/dir_page";
|
||||
import NotFound from "./pages/NotFound";
|
||||
|
||||
export default function AppRoutes() {
|
||||
return (
|
||||
@@ -92,6 +93,10 @@ export default function AppRoutes() {
|
||||
path="/scr/dashboard/dashboard-home"
|
||||
element={<DashboardHome />}
|
||||
/>
|
||||
<Route
|
||||
path="/scr/dashboard/pengaduan/list"
|
||||
element={<ListPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/scr/dashboard/apikey/apikey"
|
||||
element={<ApikeyPage />}
|
||||
|
||||
@@ -19,6 +19,7 @@ const clientRoutes = {
|
||||
"/scr/dashboard": "/scr/dashboard",
|
||||
"/scr/dashboard/credential/credential": "/scr/dashboard/credential/credential",
|
||||
"/scr/dashboard/dashboard-home": "/scr/dashboard/dashboard-home",
|
||||
"/scr/dashboard/pengaduan/list": "/scr/dashboard/pengaduan/list",
|
||||
"/scr/dashboard/apikey/apikey": "/scr/dashboard/apikey/apikey",
|
||||
"/dir/dir": "/dir/dir",
|
||||
"/*": "/*"
|
||||
|
||||
@@ -2,16 +2,16 @@ import { Tree } from "@mantine/core";
|
||||
|
||||
// ✅ Valid data, all values are unique
|
||||
const data = [
|
||||
{
|
||||
value: 'src',
|
||||
label: 'src',
|
||||
children: [
|
||||
{ value: 'src/components', label: 'components' },
|
||||
{ value: 'src/hooks', label: 'hooks' },
|
||||
],
|
||||
},
|
||||
{ value: 'package.json', label: 'package.json' },
|
||||
];
|
||||
{
|
||||
value: "src",
|
||||
label: "src",
|
||||
children: [
|
||||
{ value: "src/components", label: "components" },
|
||||
{ value: "src/hooks", label: "hooks" },
|
||||
],
|
||||
},
|
||||
{ value: "package.json", label: "package.json" },
|
||||
];
|
||||
|
||||
export default function DirPage() {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
default as clientRoute,
|
||||
default as clientRoutes,
|
||||
} from "@/clientRoutes";
|
||||
import apiFetch from "@/lib/apiFetch";
|
||||
import {
|
||||
ActionIcon,
|
||||
AppShell,
|
||||
@@ -22,17 +26,17 @@ import {
|
||||
IconChevronLeft,
|
||||
IconChevronRight,
|
||||
IconDashboard,
|
||||
IconFileCertificate,
|
||||
IconKey,
|
||||
IconLock,
|
||||
IconMessageReport,
|
||||
IconSettings,
|
||||
IconUser,
|
||||
IconUsersGroup,
|
||||
} from "@tabler/icons-react";
|
||||
import type { User } from "generated/prisma";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Outlet, useLocation, useNavigate } from "react-router-dom";
|
||||
import {
|
||||
default as clientRoute,
|
||||
default as clientRoutes,
|
||||
} from "@/clientRoutes";
|
||||
import apiFetch from "@/lib/apiFetch";
|
||||
|
||||
function Logout() {
|
||||
return (
|
||||
@@ -98,7 +102,7 @@ export default function DashboardLayout() {
|
||||
size="lg"
|
||||
style={{
|
||||
backgroundColor: "rgba(255,255,255,0.05)",
|
||||
boxShadow: "0 0 6px rgba(0,255,200,0.2)",
|
||||
boxShadow: "0 0 6px hsla(167, 100%, 50%, 0.20), 0.20)",
|
||||
}}
|
||||
>
|
||||
{opened ? <IconChevronLeft /> : <IconChevronRight />}
|
||||
@@ -186,7 +190,7 @@ function HostView() {
|
||||
{host.name}
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed">
|
||||
{host.email}
|
||||
{host.roleId}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Flex>
|
||||
@@ -219,6 +223,31 @@ function NavigationDashboard() {
|
||||
label: "Dashboard Overview",
|
||||
description: "Quick summary and insights",
|
||||
},
|
||||
{
|
||||
path: "/scr/dashboard/pengaduan/list",
|
||||
icon: <IconMessageReport size={20} />,
|
||||
label: "Pengaduan Warga",
|
||||
description: "Manage pengaduan warga",
|
||||
},
|
||||
{
|
||||
path: "/scr/dashboard/pelayanan",
|
||||
icon: <IconFileCertificate size={20} />,
|
||||
label: "Pelayanan Surat",
|
||||
description: "Manage pelayanan surat",
|
||||
},
|
||||
{
|
||||
path: "/scr/dashboard/user",
|
||||
icon: <IconUsersGroup size={20} />,
|
||||
label: "User",
|
||||
description: "Manage user",
|
||||
},
|
||||
{
|
||||
path: "/scr/dashboard/setting",
|
||||
icon: <IconSettings size={20} />,
|
||||
label: "Setting",
|
||||
description:
|
||||
"Manage setting (category pengaduan dan pelayanan surat, desa, etc)",
|
||||
},
|
||||
{
|
||||
path: "/scr/dashboard/apikey/apikey",
|
||||
icon: <IconKey size={20} />,
|
||||
|
||||
186
src/pages/scr/dashboard/pengaduan/list_page.tsx
Normal file
186
src/pages/scr/dashboard/pengaduan/list_page.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
import apiFetch from "@/lib/apiFetch";
|
||||
import {
|
||||
Badge,
|
||||
Card,
|
||||
Container,
|
||||
Divider,
|
||||
Flex,
|
||||
Group,
|
||||
Stack,
|
||||
Tabs,
|
||||
Text,
|
||||
Title
|
||||
} from "@mantine/core";
|
||||
import { useShallowEffect } from "@mantine/hooks";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
import { IconAlignJustified, IconClockHour3, IconMapPin } from "@tabler/icons-react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import useSwr from "swr";
|
||||
import { proxy, subscribe } from "valtio";
|
||||
|
||||
const state = proxy({ reload: "" });
|
||||
function reloadState() {
|
||||
state.reload = Math.random().toString();
|
||||
}
|
||||
|
||||
export default function PengaduanListPage() {
|
||||
const { search } = useLocation();
|
||||
const query = new URLSearchParams(search);
|
||||
|
||||
const status = query.get("status");
|
||||
console.log(status, "status");
|
||||
|
||||
return (
|
||||
<Container
|
||||
size="xl"
|
||||
py="xl"
|
||||
w={"100%"}
|
||||
>
|
||||
<Stack gap="xl">
|
||||
<TabListPengaduan status={status || "all"} />
|
||||
<ListPengaduan />
|
||||
</Stack>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
function TabListPengaduan({ status }: { status: string }) {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Tabs defaultValue={status || "all"} color="teal">
|
||||
<Tabs.List grow>
|
||||
<Tabs.Tab value="all" onClick={() => { navigate("?status=all") }}>Semua</Tabs.Tab>
|
||||
<Tabs.Tab value="antrian" onClick={() => { navigate("?status=antrian") }}>Antrian</Tabs.Tab>
|
||||
<Tabs.Tab value="diterima" onClick={() => { navigate("?status=diterima") }}>Diterima</Tabs.Tab>
|
||||
<Tabs.Tab value="dikerjakan" onClick={() => { navigate("?status=dikerjakan") }}>Dikerjakan</Tabs.Tab>
|
||||
<Tabs.Tab value="ditolak" onClick={() => { navigate("?status=ditolak") }}>Ditolak</Tabs.Tab>
|
||||
<Tabs.Tab value="selesai" onClick={() => { navigate("?status=selesai") }}>Selesai</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
function ListPengaduan() {
|
||||
const { data, mutate, isLoading } = useSwr("/", () =>
|
||||
apiFetch.api.credential.list.get(),
|
||||
);
|
||||
|
||||
useShallowEffect(() => {
|
||||
const unsubscribe = subscribe(state, () => mutate());
|
||||
return () => unsubscribe();
|
||||
}, []);
|
||||
|
||||
async function handleRemove(id: string) {
|
||||
try {
|
||||
await apiFetch.api.credential.rm.delete({ id });
|
||||
showNotification({
|
||||
color: "teal",
|
||||
title: "Credential Deleted",
|
||||
message: "The credential was successfully removed.",
|
||||
});
|
||||
reloadState();
|
||||
} catch {
|
||||
showNotification({
|
||||
color: "red",
|
||||
title: "Error",
|
||||
message: "Failed to delete credential. Please try again.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (isLoading)
|
||||
return (
|
||||
<Card
|
||||
radius="lg"
|
||||
p="xl"
|
||||
withBorder
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(145deg, rgba(25,25,25,0.95), rgba(45,45,45,0.85))",
|
||||
}}
|
||||
>
|
||||
<Text size="sm" c="dimmed">
|
||||
Loading credentials...
|
||||
</Text>
|
||||
</Card>
|
||||
);
|
||||
|
||||
const list = data?.data?.list || [];
|
||||
|
||||
return (
|
||||
<Card
|
||||
radius="lg"
|
||||
p="xl"
|
||||
withBorder
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(145deg, rgba(25,25,25,0.95), rgba(45,45,45,0.85))",
|
||||
borderColor: "rgba(100,100,100,0.2)",
|
||||
boxShadow: "0 0 20px rgba(0,255,200,0.08)",
|
||||
}}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Flex align="center" justify="space-between">
|
||||
<Flex direction={"column"}>
|
||||
<Title order={3} c="gray.2">
|
||||
Dompet Hilang
|
||||
</Title>
|
||||
<Group>
|
||||
<Title order={6} c="gray.5">
|
||||
#PGD-061125-001
|
||||
</Title>
|
||||
<Text size="sm" c="dimmed">
|
||||
updated 2 minutes ago
|
||||
</Text>
|
||||
</Group>
|
||||
</Flex>
|
||||
<Badge
|
||||
size="xl"
|
||||
variant="light"
|
||||
radius="sm"
|
||||
color="gray"
|
||||
style={{ textTransform: "none" }}
|
||||
>
|
||||
Antrian
|
||||
</Badge>
|
||||
</Flex>
|
||||
<Divider my={0} />
|
||||
<Stack gap="sm">
|
||||
<Flex direction={"column"} justify="flex-start">
|
||||
<Group gap="xs">
|
||||
<IconClockHour3 size={20} color="white" />
|
||||
<Text size="md" c="white">
|
||||
Tanggal Aduan
|
||||
</Text>
|
||||
</Group>
|
||||
<Text size="md">
|
||||
05 November 2025
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex direction={"column"} justify="flex-start">
|
||||
<Group gap="xs">
|
||||
<IconMapPin size={20} color="white" />
|
||||
<Text size="md" c="white">
|
||||
Lokasi
|
||||
</Text>
|
||||
</Group>
|
||||
<Text size="md">
|
||||
Jalan Darmasaba Raya no 77
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex direction={"column"} justify="flex-start">
|
||||
<Group gap="xs">
|
||||
<IconAlignJustified size={20} color="white" />
|
||||
<Text size="md" c="white">
|
||||
Detail
|
||||
</Text>
|
||||
</Group>
|
||||
<Text size="md">
|
||||
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quis, obcaecati. Sint natus culpa temporibus neque quasi expedita ratione, facere optio incidunt quibusdam suscipit nam nemo delectus beatae similique velit obcaecati?
|
||||
</Text>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user