Files
dashboard-noc-desa-darmasaba/src/components/pengaduan-layanan-publik.tsx
2026-03-25 00:09:38 +08:00

432 lines
9.5 KiB
TypeScript

import {
Badge,
Button,
Card,
Grid,
Group,
Stack,
Text,
ThemeIcon,
Title,
useMantineColorScheme,
} from "@mantine/core";
import { CheckCircle, Clock, FileText, MessageCircle } from "lucide-react";
import {
Bar,
BarChart,
CartesianGrid,
Line,
LineChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
// Summary data
const summaryData = [
{
title: "Total Pengaduan",
value: 42,
subtitle: "Bulan ini",
icon: MessageCircle,
color: "#1E3A5F",
},
{
title: "Baru",
value: 14,
subtitle: "Belum diproses",
icon: FileText,
color: "#1E3A5F",
},
{
title: "Diproses",
value: 14,
subtitle: "Sedang ditangani",
icon: Clock,
color: "#1E3A5F",
},
{
title: "Selesai",
value: 14,
subtitle: "Terselesaikan",
icon: CheckCircle,
color: "#1E3A5F",
},
];
// Tren pengaduan data
const trenData = [
{ bulan: "Apr", jumlah: 35 },
{ bulan: "Mei", jumlah: 48 },
{ bulan: "Jun", jumlah: 42 },
{ bulan: "Jul", jumlah: 55 },
{ bulan: "Agu", jumlah: 50 },
{ bulan: "Sep", jumlah: 58 },
{ bulan: "Okt", jumlah: 52 },
];
// Surat terbanyak data
const suratData = [
{ jenis: "KTP", jumlah: 24 },
{ jenis: "KK", jumlah: 18 },
{ jenis: "Domisili", jumlah: 15 },
{ jenis: "Usaha", jumlah: 12 },
{ jenis: "Lainnya", jumlah: 8 },
];
// Pengajuan terbaru data
const pengajuanTerbaru = [
{
nama: "Budi Santoso",
jenis: "Ketertiban Umum",
waktu: "2 jam yang lalu",
status: "baru",
},
{
nama: "Siti Rahayu",
jenis: "Pelayanan Kesehatan",
waktu: "5 jam yang lalu",
status: "proses",
},
{
nama: "Ahmad Fauzi",
jenis: "Infrastruktur",
waktu: "1 hari yang lalu",
status: "selesai",
},
{
nama: "Dewi Lestari",
jenis: "Administrasi",
waktu: "1 hari yang lalu",
status: "baru",
},
{
nama: "Joko Widodo",
jenis: "Keamanan",
waktu: "2 hari yang lalu",
status: "proses",
},
];
// Ide inovatif data
const ideInovatif = [
{
nama: "Andi Prasetyo",
judul: "Penerapan Smart Village",
waktu: "3 hari yang lalu",
kategori: "Teknologi",
},
{
nama: "Rina Kusuma",
judul: "Program Ekowisata Desa",
waktu: "5 hari yang lalu",
kategori: "Ekonomi",
},
{
nama: "Bambang Suryono",
judul: "Peningkatan Sanitasi",
waktu: "1 minggu yang lalu",
kategori: "Kesehatan",
},
{
nama: "Lina Marlina",
judul: "Pusat Kreatif Anak Muda",
waktu: "2 minggu yang lalu",
kategori: "Pendidikan",
},
];
const getStatusColor = (status: string) => {
switch (status) {
case "baru":
return "red";
case "proses":
return "blue";
case "selesai":
return "green";
default:
return "gray";
}
};
const PengaduanLayananPublik = () => {
const { colorScheme } = useMantineColorScheme();
const dark = colorScheme === "dark";
return (
<Stack gap="lg">
{/* TOP SECTION - 4 STAT CARDS */}
<Grid gutter="md">
{summaryData.map((item, index) => (
<Grid.Col key={index} span={{ base: 12, sm: 6, lg: 3 }}>
<Card
p="md"
radius="xl"
withBorder
bg={dark ? "#1E293B" : "white"}
style={{
borderColor: dark ? "#334155" : "white",
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
transition: "transform 0.15s ease, box-shadow 0.15s ease",
}}
h="100%"
>
<Group justify="space-between" align="center" w="100%">
<Stack gap={2}>
<Text size="sm" c="dimmed">
{item.title}
</Text>
<Text size="xl" fw={700} c={dark ? "white" : "gray.9"}>
{item.value}
</Text>
<Text size="xs" c="dimmed">
{item.subtitle}
</Text>
</Stack>
<ThemeIcon
color={item.color}
variant="filled"
size="lg"
radius="xl"
style={{
transition: "transform 0.15s ease",
}}
>
<item.icon style={{ width: "60%", height: "60%" }} />
</ThemeIcon>
</Group>
</Card>
</Grid.Col>
))}
</Grid>
{/* MAIN CHART - TREN PENGADUAN */}
<Card
p="md"
radius="xl"
withBorder
bg={dark ? "#1E293B" : "white"}
style={{
borderColor: dark ? "#334155" : "white",
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
}}
>
<Group justify="space-between" mb="md">
<Title order={4} c={dark ? "white" : "gray.9"}>
Tren Pengaduan
</Title>
</Group>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={trenData}>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke={dark ? "#334155" : "#e5e7eb"}
/>
<XAxis
dataKey="bulan"
axisLine={false}
tickLine={false}
tick={{ fill: dark ? "#E2E8F0" : "#374151" }}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fill: dark ? "#E2E8F0" : "#374151" }}
/>
<Tooltip
contentStyle={{
backgroundColor: dark ? "#1E293B" : "white",
borderColor: dark ? "#334155" : "#e5e7eb",
borderRadius: "8px",
}}
labelStyle={{ color: dark ? "#E2E8F0" : "#374151" }}
/>
<Line
type="monotone"
dataKey="jumlah"
stroke="#1E3A5F"
strokeWidth={2}
dot={{
fill: "#1E3A5F",
strokeWidth: 2,
r: 4,
}}
activeDot={{ r: 6 }}
/>
</LineChart>
</ResponsiveContainer>
</Card>
{/* BOTTOM SECTION - 3 COLUMNS */}
<Grid gutter="md">
{/* LEFT: SURAT TERBANYAK */}
<Grid.Col span={{ base: 12, lg: 4 }}>
<Card
p="md"
radius="xl"
withBorder
bg={dark ? "#1E293B" : "white"}
style={{
borderColor: dark ? "#334155" : "white",
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
}}
h="100%"
>
<Title order={4} c={dark ? "white" : "gray.9"} mb="md">
Surat Terbanyak
</Title>
<ResponsiveContainer width="100%" height={250}>
<BarChart data={suratData} layout="vertical">
<CartesianGrid
strokeDasharray="3 3"
horizontal={false}
stroke={dark ? "#334155" : "#e5e7eb"}
/>
<XAxis
type="number"
axisLine={false}
tickLine={false}
tick={{ fill: dark ? "#E2E8F0" : "#374151" }}
/>
<YAxis
type="category"
dataKey="jenis"
axisLine={false}
tickLine={false}
tick={{ fill: dark ? "#E2E8F0" : "#374151" }}
width={80}
/>
<Tooltip
contentStyle={{
backgroundColor: dark ? "#1E293B" : "white",
borderColor: dark ? "#334155" : "#e5e7eb",
borderRadius: "8px",
}}
/>
<Bar dataKey="jumlah" fill="#1E3A5F" radius={[0, 4, 4, 0]} />
</BarChart>
</ResponsiveContainer>
</Card>
</Grid.Col>
{/* CENTER: PENGAJUAN TERBARU */}
<Grid.Col span={{ base: 12, lg: 4 }}>
<Card
p="md"
radius="xl"
withBorder
bg={dark ? "#1E293B" : "white"}
style={{
borderColor: dark ? "#334155" : "white",
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
}}
h="100%"
>
<Title order={4} c={dark ? "white" : "gray.9"} mb="md">
Pengajuan Terbaru
</Title>
<Stack gap="sm">
{pengajuanTerbaru.map((item, index) => (
<Card
key={index}
p="sm"
radius="md"
withBorder
bg={dark ? "#334155" : "#F1F5F9"}
style={{
borderColor: "transparent",
transition: "background-color 0.15s ease",
}}
>
<Group justify="space-between">
<Stack gap={0}>
<Text fw={600} c={dark ? "white" : "gray.9"}>
{item.nama}
</Text>
<Text size="sm" c="dimmed">
{item.jenis}
</Text>
</Stack>
<Stack gap={0} align="flex-end">
<Badge
color={getStatusColor(item.status)}
variant="light"
radius="sm"
>
{item.status}
</Badge>
<Text size="xs" c="dimmed">
{item.waktu}
</Text>
</Stack>
</Group>
</Card>
))}
</Stack>
</Card>
</Grid.Col>
{/* RIGHT: AJUAN IDE INOVATIF */}
<Grid.Col span={{ base: 12, lg: 4 }}>
<Card
p="md"
radius="xl"
withBorder
bg={dark ? "#1E293B" : "white"}
style={{
borderColor: dark ? "#334155" : "white",
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
}}
h="100%"
>
<Title order={4} c={dark ? "white" : "gray.9"} mb="md">
Ajuan Ide Inovatif
</Title>
<Stack gap="sm">
{ideInovatif.map((item, index) => (
<Card
key={index}
p="sm"
radius="md"
withBorder
bg={dark ? "#334155" : "#F1F5F9"}
style={{
borderColor: "transparent",
transition: "background-color 0.15s ease",
}}
>
<Group justify="space-between">
<Stack gap={0}>
<Text fw={600} c={dark ? "white" : "gray.9"}>
{item.judul}
</Text>
<Text size="sm" c="dimmed">
{item.nama}
</Text>
<Text size="xs" c="dimmed">
{item.waktu}
</Text>
</Stack>
<Button
size="xs"
variant="light"
color="darmasaba-blue"
radius="md"
>
Detail
</Button>
</Group>
</Card>
))}
</Stack>
</Card>
</Grid.Col>
</Grid>
</Stack>
);
};
export default PengaduanLayananPublik;