- Convert Mantine-based components to TailwindCSS + Recharts - Add dark mode support for all dashboard pages - Update routing to allow public dashboard access - Components refactored: - kinreja-divisi.tsx: Village performance dashboard - pengaduan-layanan-publik.tsx: Public complaint management - jenna-analytic.tsx: Chatbot analytics dashboard - demografi-pekerjaan.tsx: Demographic analytics - keuangan-anggaran.tsx: APBDes financial dashboard - bumdes-page.tsx: UMKM sales monitoring - sosial-page.tsx: Village social monitoring - Remove landing page, redirect / to /dashboard - Update auth middleware for public dashboard access Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
357 lines
9.1 KiB
TypeScript
357 lines
9.1 KiB
TypeScript
import {
|
|
Bar,
|
|
BarChart,
|
|
CartesianGrid,
|
|
Cell,
|
|
Pie,
|
|
PieChart,
|
|
ResponsiveContainer,
|
|
Tooltip,
|
|
XAxis,
|
|
YAxis,
|
|
} from "recharts";
|
|
import { useMantineColorScheme } from "@mantine/core";
|
|
|
|
const KinerjaDivisi = () => {
|
|
const { colorScheme } = useMantineColorScheme();
|
|
const dark = colorScheme === "dark";
|
|
|
|
// Top row - 4 activity cards
|
|
const activities = [
|
|
{
|
|
title: "Rakor 2025",
|
|
progress: 100,
|
|
date: "15 Jan 2025",
|
|
},
|
|
{
|
|
title: "Pemutakhiran Indeks Desa",
|
|
progress: 100,
|
|
date: "20 Feb 2025",
|
|
},
|
|
{
|
|
title: "Mengurus akta cerai warga",
|
|
progress: 100,
|
|
date: "5 Mar 2025",
|
|
},
|
|
{
|
|
title: "Pasek 7 desa adat",
|
|
progress: 100,
|
|
date: "10 Mar 2025",
|
|
},
|
|
];
|
|
|
|
// Document statistics
|
|
const documentStats = [
|
|
{ name: "Gambar", value: 300, color: "#FAC858" },
|
|
{ name: "Dokumen", value: 310, color: "#92CC76" },
|
|
];
|
|
|
|
// Activity progress statistics
|
|
const activityProgressStats = [
|
|
{ name: "Selesai", value: 83.33, fill: "#92CC76" },
|
|
{ name: "Dikerjakan", value: 16.67, fill: "#FAC858" },
|
|
{ name: "Segera Dikerjakan", value: 0, fill: "#5470C6" },
|
|
{ name: "Dibatalkan", value: 0, fill: "#EE6767" },
|
|
];
|
|
|
|
// Discussion data
|
|
const discussions = [
|
|
{
|
|
title: "Pembahasan APBDes 2026",
|
|
sender: "Kepala Desa",
|
|
date: "10 Mar 2025",
|
|
},
|
|
{
|
|
title: "Kegiatan Posyandu",
|
|
sender: "Divisi Sosial",
|
|
date: "9 Mar 2025",
|
|
},
|
|
{
|
|
title: "Festival Budaya",
|
|
sender: "Divisi Humas",
|
|
date: "8 Mar 2025",
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div
|
|
className="min-h-screen"
|
|
style={{ backgroundColor: dark ? "#10192D" : "#F3F4F6" }}
|
|
>
|
|
{/* Top Row - 4 Activity Cards */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
|
|
{activities.map((activity, index) => (
|
|
<div
|
|
key={index}
|
|
className="rounded-xl shadow-sm p-5"
|
|
style={{
|
|
backgroundColor: dark ? "#141D34" : "white",
|
|
border: `1px solid ${dark ? "#141D34" : "white"}`,
|
|
}}
|
|
>
|
|
{/* Dark blue title bar */}
|
|
<div
|
|
className="text-white px-3 py-2 rounded-t-lg -mx-5 -mt-5 mb-4"
|
|
style={{ backgroundColor: "#1E3A5F" }}
|
|
>
|
|
<h3 className="text-sm font-semibold">{activity.title}</h3>
|
|
</div>
|
|
|
|
{/* Orange progress bar */}
|
|
<div
|
|
className="w-full rounded-full h-2 mb-3"
|
|
style={{ backgroundColor: dark ? "#2d3748" : "#E5E7EB" }}
|
|
>
|
|
<div
|
|
className="bg-orange-500 h-2 rounded-full"
|
|
style={{ width: `${activity.progress}%` }}
|
|
/>
|
|
</div>
|
|
|
|
{/* Date and badge */}
|
|
<div className="flex justify-between items-center">
|
|
<span
|
|
className="text-xs"
|
|
style={{ color: dark ? "#9CA3AF" : "#6B7280" }}
|
|
>
|
|
{activity.date}
|
|
</span>
|
|
<span className="text-xs bg-green-100 text-green-700 px-2 py-1 rounded-full font-medium">
|
|
Selesai
|
|
</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Second Row - Charts */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
|
{/* Left Card - Jumlah Dokumen (Bar Chart) */}
|
|
<div
|
|
className="rounded-xl shadow-sm p-5"
|
|
style={{
|
|
backgroundColor: dark ? "#141D34" : "white",
|
|
border: `1px solid ${dark ? "#141D34" : "white"}`,
|
|
}}
|
|
>
|
|
<h3
|
|
className="text-lg font-semibold mb-4"
|
|
style={{ color: dark ? "white" : "#1F2937" }}
|
|
>
|
|
Jumlah Dokumen
|
|
</h3>
|
|
<ResponsiveContainer width="100%" height={250}>
|
|
<BarChart data={documentStats}>
|
|
<CartesianGrid
|
|
strokeDasharray="3 3"
|
|
vertical={false}
|
|
stroke={dark ? "#2d3748" : "#E5E7EB"}
|
|
/>
|
|
<XAxis
|
|
dataKey="name"
|
|
axisLine={false}
|
|
tickLine={false}
|
|
tick={{ fill: dark ? "#9CA3AF" : "#6B7280" }}
|
|
/>
|
|
<YAxis
|
|
axisLine={false}
|
|
tickLine={false}
|
|
tick={{ fill: dark ? "#9CA3AF" : "#6B7280" }}
|
|
/>
|
|
<Tooltip
|
|
contentStyle={{
|
|
backgroundColor: dark ? "#1F2937" : "white",
|
|
border: `1px solid ${dark ? "#374151" : "#E5E7EB"}`,
|
|
borderRadius: "8px",
|
|
color: dark ? "white" : "#1F2937",
|
|
}}
|
|
/>
|
|
<Bar dataKey="value" radius={[4, 4, 0, 0]}>
|
|
{documentStats.map((entry, index) => (
|
|
<Cell key={`cell-${index}`} fill={entry.color} />
|
|
))}
|
|
</Bar>
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
|
|
{/* Right Card - Progres Kegiatan (Pie Chart) */}
|
|
<div
|
|
className="rounded-xl shadow-sm p-5"
|
|
style={{
|
|
backgroundColor: dark ? "#141D34" : "white",
|
|
border: `1px solid ${dark ? "#141D34" : "white"}`,
|
|
}}
|
|
>
|
|
<h3
|
|
className="text-lg font-semibold mb-4"
|
|
style={{ color: dark ? "white" : "#1F2937" }}
|
|
>
|
|
Progres Kegiatan
|
|
</h3>
|
|
<ResponsiveContainer width="100%" height={250}>
|
|
<PieChart>
|
|
<Pie
|
|
data={activityProgressStats.filter(item => item.value > 0)}
|
|
cx="50%"
|
|
cy="50%"
|
|
outerRadius={80}
|
|
dataKey="value"
|
|
label={({ name, percent }) =>
|
|
`${name}: ${percent ? (percent * 100).toFixed(0) : 0}%`
|
|
}
|
|
>
|
|
{activityProgressStats
|
|
.filter(item => item.value > 0)
|
|
.map((entry, index) => (
|
|
<Cell key={`cell-${index}`} fill={entry.fill} />
|
|
))}
|
|
</Pie>
|
|
<Tooltip
|
|
contentStyle={{
|
|
backgroundColor: dark ? "#1F2937" : "white",
|
|
border: `1px solid ${dark ? "#374151" : "#E5E7EB"}`,
|
|
borderRadius: "8px",
|
|
color: dark ? "white" : "#1F2937",
|
|
}}
|
|
/>
|
|
</PieChart>
|
|
</ResponsiveContainer>
|
|
|
|
{/* Legend */}
|
|
<div className="mt-4 space-y-2">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-3 h-3 rounded-full bg-blue-500"></div>
|
|
<span
|
|
className="text-sm"
|
|
style={{ color: dark ? "#9CA3AF" : "#4B5563" }}
|
|
>
|
|
Segera Dikerjakan
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-3 h-3 rounded-full bg-yellow-500"></div>
|
|
<span
|
|
className="text-sm"
|
|
style={{ color: dark ? "#9CA3AF" : "#4B5563" }}
|
|
>
|
|
Dikerjakan
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-3 h-3 rounded-full bg-green-500"></div>
|
|
<span
|
|
className="text-sm"
|
|
style={{ color: dark ? "#9CA3AF" : "#4B5563" }}
|
|
>
|
|
Selesai
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-3 h-3 rounded-full bg-red-500"></div>
|
|
<span
|
|
className="text-sm"
|
|
style={{ color: dark ? "#9CA3AF" : "#4B5563" }}
|
|
>
|
|
Dibatalkan
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bottom Row */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
{/* Left Card - Diskusi */}
|
|
<div
|
|
className="rounded-xl shadow-sm p-5"
|
|
style={{
|
|
backgroundColor: dark ? "#141D34" : "white",
|
|
border: `1px solid ${dark ? "#141D34" : "white"}`,
|
|
}}
|
|
>
|
|
<h3
|
|
className="text-lg font-semibold mb-4"
|
|
style={{ color: dark ? "white" : "#1F2937" }}
|
|
>
|
|
Diskusi
|
|
</h3>
|
|
<div className="space-y-3">
|
|
{discussions.map((discussion, index) => (
|
|
<div
|
|
key={index}
|
|
className="flex items-start gap-3 p-3 rounded-lg transition-colors"
|
|
style={{
|
|
backgroundColor: dark ? "#1F2937" : "#F9FAFB",
|
|
}}
|
|
>
|
|
<div className="flex-shrink-0">
|
|
<div
|
|
className="w-8 h-8 rounded-full flex items-center justify-center"
|
|
style={{ backgroundColor: "#DBEAFE" }}
|
|
>
|
|
<svg
|
|
className="w-4 h-4"
|
|
style={{ color: "#1E3A5F" }}
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div className="flex-1">
|
|
<h4
|
|
className="text-sm font-medium"
|
|
style={{ color: dark ? "white" : "#1F2937" }}
|
|
>
|
|
{discussion.title}
|
|
</h4>
|
|
<p
|
|
className="text-xs mt-1"
|
|
style={{ color: dark ? "#9CA3AF" : "#6B7280" }}
|
|
>
|
|
{discussion.sender} • {discussion.date}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right Card - Acara Hari Ini */}
|
|
<div
|
|
className="rounded-xl shadow-sm p-5"
|
|
style={{
|
|
backgroundColor: dark ? "#141D34" : "white",
|
|
border: `1px solid ${dark ? "#141D34" : "white"}`,
|
|
}}
|
|
>
|
|
<h3
|
|
className="text-lg font-semibold mb-4"
|
|
style={{ color: dark ? "white" : "#1F2937" }}
|
|
>
|
|
Acara Hari Ini
|
|
</h3>
|
|
<div className="flex items-center justify-center h-32">
|
|
<p
|
|
className="text-sm"
|
|
style={{ color: dark ? "#9CA3AF" : "#6B7280" }}
|
|
>
|
|
Tidak ada acara hari ini
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default KinerjaDivisi;
|