feat: connect kinerja divisi components to live database

New API Endpoints (src/api/division.ts):
- GET /api/division/discussions - Fetch recent discussions with sender info
- GET /api/division/documents/stats - Fetch document counts by type
- GET /api/division/activities/stats - Fetch activity status breakdown with percentages

Components Connected to Database:
- discussion-panel.tsx: Now fetches from /api/division/discussions
- document-chart.tsx: Now fetches from /api/division/documents/stats
- progress-chart.tsx: Now fetches from /api/division/activities/stats

Features Added:
- Loading states with Loader component
- Empty states with friendly messages
- Date formatting using date-fns with Indonesian locale
- Real-time data from database instead of hardcoded values
- Proper TypeScript typing for API responses

Files changed:
- src/api/division.ts: Added 3 new API endpoints
- src/components/kinerja-divisi/discussion-panel.tsx
- src/components/kinerja-divisi/document-chart.tsx
- src/components/kinerja-divisi/progress-chart.tsx

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-03-27 15:43:58 +08:00
parent b77822f2dd
commit 75c7bc249e
4 changed files with 390 additions and 141 deletions

View File

@@ -1,4 +1,5 @@
import { Card, Text, useMantineColorScheme } from "@mantine/core";
import { Card, Group, Loader, Text, useMantineColorScheme } from "@mantine/core";
import { useEffect, useState } from "react";
import {
Bar,
BarChart,
@@ -9,16 +10,38 @@ import {
XAxis,
YAxis,
} from "recharts";
import { apiClient } from "@/utils/api-client";
const documentData = [
{ name: "Gambar", jumlah: 300, color: "#FACC15" },
{ name: "Dokumen", jumlah: 310, color: "#22C55E" },
];
interface DocumentData {
name: string;
jumlah: number;
color: string;
}
export function DocumentChart() {
const { colorScheme } = useMantineColorScheme();
const dark = colorScheme === "dark";
const [data, setData] = useState<DocumentData[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchDocumentStats() {
try {
const res = await apiClient.GET("/api/division/documents/stats");
if (res.data?.data) {
setData(res.data.data);
}
} catch (error) {
console.error("Failed to fetch document stats", error);
} finally {
setLoading(false);
}
}
fetchDocumentStats();
}, []);
return (
<Card
p="md"
@@ -36,39 +59,52 @@ export function DocumentChart() {
<Text size="sm" fw={600} c={dark ? "white" : "#1E3A5F"} mb="md">
Jumlah Dokumen
</Text>
<ResponsiveContainer width="100%" height={200}>
<BarChart data={documentData}>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke={dark ? "#334155" : "#e5e7eb"}
/>
<XAxis
dataKey="name"
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" }}
/>
<Bar dataKey="jumlah" radius={[4, 4, 0, 0]}>
{documentData.map((entry) => (
<Cell key={`cell-${entry.name}`} fill={entry.color} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
{loading ? (
<Group justify="center" py="xl">
<Loader />
</Group>
) : data.length > 0 ? (
<ResponsiveContainer width="100%" height={200}>
<BarChart data={data}>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke={dark ? "#334155" : "#e5e7eb"}
/>
<XAxis
dataKey="name"
axisLine={false}
tickLine={false}
tick={{ fill: dark ? "#E2E8F0" : "#374151" }}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fill: dark ? "#E2E8F0" : "#374151" }}
allowDecimals={false}
/>
<Tooltip
contentStyle={{
backgroundColor: dark ? "#1E293B" : "white",
borderColor: dark ? "#334155" : "#e5e7eb",
borderRadius: "8px",
}}
labelStyle={{ color: dark ? "#E2E8F0" : "#374151" }}
/>
<Bar dataKey="jumlah" radius={[4, 4, 0, 0]}>
{data.map((entry) => (
<Cell key={`cell-${entry.name}`} fill={entry.color} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
) : (
<Group justify="center" py="xl">
<Text size="sm" c="dimmed">
Tidak ada dokumen
</Text>
</Group>
)}
</Card>
);
}