From 8c35d58b3802af18ae4becf3ae19492b6c5ad481 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 13 Mar 2026 16:47:19 +0800 Subject: [PATCH] refactor: modularize kinerja-divisi components per PromptDashboard.md - Create ActivityCard component for program kegiatan cards - Create DivisionList component for divisi teraktif with arrow icons - Create DocumentChart component for bar chart (jumlah dokumen) - Create ProgressChart component for pie chart (progres kegiatan) - Create DiscussionPanel component for diskusi internal - Create EventCard component for agenda hari ini - Create ArchiveCard component for arsip digital perangkat desa - Refactor main KinerjaDivisi component to use new modular components - Implement responsive 3-column grid layout - Add proper dark mode support with specified colors - Add hover effects and smooth animations New components structure: src/components/kinerja-divisi/ - activity-card.tsx - archive-card.tsx - discussion-panel.tsx - division-list.tsx - document-chart.tsx - event-card.tsx - progress-chart.tsx - index.ts (exports) Co-authored-by: Qwen-Coder --- src/components/kinerja-divisi.tsx | 610 +++--------------- .../kinerja-divisi/activity-card.tsx | 95 +++ .../kinerja-divisi/archive-card.tsx | 41 ++ .../kinerja-divisi/discussion-panel.tsx | 92 +++ .../kinerja-divisi/division-list.tsx | 77 +++ .../kinerja-divisi/document-chart.tsx | 69 ++ src/components/kinerja-divisi/event-card.tsx | 65 ++ src/components/kinerja-divisi/index.ts | 7 + .../kinerja-divisi/progress-chart.tsx | 84 +++ 9 files changed, 613 insertions(+), 527 deletions(-) create mode 100644 src/components/kinerja-divisi/activity-card.tsx create mode 100644 src/components/kinerja-divisi/archive-card.tsx create mode 100644 src/components/kinerja-divisi/discussion-panel.tsx create mode 100644 src/components/kinerja-divisi/division-list.tsx create mode 100644 src/components/kinerja-divisi/document-chart.tsx create mode 100644 src/components/kinerja-divisi/event-card.tsx create mode 100644 src/components/kinerja-divisi/index.ts create mode 100644 src/components/kinerja-divisi/progress-chart.tsx diff --git a/src/components/kinerja-divisi.tsx b/src/components/kinerja-divisi.tsx index e56e27d..96fd77e 100644 --- a/src/components/kinerja-divisi.tsx +++ b/src/components/kinerja-divisi.tsx @@ -1,545 +1,101 @@ +import { Grid, Stack } from "@mantine/core"; import { - ActionIcon, - Box, - Card, - Divider, - Grid, - GridCol, - Group, - List, - Badge as MantineBadge, - Progress as MantineProgress, - Skeleton, - Stack, - Text, - ThemeIcon, - Title, - useMantineColorScheme, -} from "@mantine/core"; -import { - Bar, - BarChart, - CartesianGrid, - Cell, - Pie, - PieChart, - ResponsiveContainer, - Tooltip, - XAxis, - YAxis, -} from "recharts"; -import { Button } from "@/components/ui/button"; + ActivityCard, + ArchiveCard, + DiscussionPanel, + DivisionList, + DocumentChart, + EventCard, + ProgressChart, +} from "."; + +// Data for program kegiatan (Section 1) +const programKegiatanData = [ + { + title: "Rakor 2025", + date: "3 Juli 2025", + progress: 90, + status: "selesai" as const, + }, + { + title: "Pemutakhiran Indeks Desa", + date: "3 Juli 2025", + progress: 85, + status: "selesai" as const, + }, + { + title: "Mengurus Akta Cerai Warga", + date: "3 Juli 2025", + progress: 80, + status: "selesai" as const, + }, + { + title: "Pasek 7 Desa Adat", + date: "3 Juli 2025", + progress: 92, + status: "selesai" as const, + }, +]; + +// Data for arsip digital (Section 5) +const archiveData = [ + { name: "Surat Keputusan" }, + { name: "Dokumentasi" }, + { name: "Laporan Keuangan" }, + { name: "Notulensi Rapat" }, +]; const KinerjaDivisi = () => { - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === "dark"; - - // Data for division progress chart - const divisionProgressData = [ - { name: "Sekretariat", selesai: 12, berjalan: 5, tertunda: 2 }, - { name: "Keuangan", selesai: 8, berjalan: 7, tertunda: 1 }, - { name: "Sosial", selesai: 10, berjalan: 3, tertunda: 4 }, - { name: "Humas", selesai: 6, berjalan: 9, tertunda: 3 }, - ]; - - // Division task summaries - const divisionTasks = [ - { - name: "Sekretariat", - tasks: [ - { title: "Laporan Bulanan", status: "selesai" }, - { title: "Arsip Dokumen", status: "berjalan" }, - { title: "Undangan Rapat", status: "tertunda" }, - ], - }, - { - name: "Keuangan", - tasks: [ - { title: "Laporan APBDes", status: "selesai" }, - { title: "Verifikasi Dana", status: "tertunda" }, - { title: "Pengeluaran Harian", status: "berjalan" }, - ], - }, - { - name: "Sosial", - tasks: [ - { title: "Program Bantuan", status: "selesai" }, - { title: "Kegiatan Posyandu", status: "berjalan" }, - { title: "Monitoring Stunting", status: "tertunda" }, - ], - }, - { - name: "Humas", - tasks: [ - { title: "Publikasi Kegiatan", status: "selesai" }, - { title: "Koordinasi Media", status: "berjalan" }, - { title: "Laporan Kegiatan", status: "tertunda" }, - ], - }, - ]; - - // Archive items - const archiveItems = [ - { name: "Surat Keputusan", count: 12 }, - { name: "Laporan Keuangan", count: 8 }, - { name: "Dokumentasi", count: 24 }, - { name: "Notulensi Rapat", count: 15 }, - ]; - - // Activity progress - const activityProgress = [ - { - name: "Pembangunan Jalan", - progress: 75, - date: "15 Feb 2026", - status: "berjalan", - }, - { - name: "Posyandu Bulanan", - progress: 100, - date: "10 Feb 2026", - status: "selesai", - }, - { - name: "Vaksinasi Massal", - progress: 45, - date: "20 Feb 2026", - status: "berjalan", - }, - { - name: "Festival Budaya", - progress: 20, - date: "5 Mar 2026", - status: "berjalan", - }, - ]; - - // Document statistics - const documentStats = [ - { name: "Gambar", value: 42 }, - { name: "Dokumen", value: 87 }, - ]; - - // Activity progress statistics - const activityProgressStats = [ - { name: "Selesai", value: 12 }, - { name: "Dikerjakan", value: 8 }, - { name: "Segera Dikerjakan", value: 5 }, - { name: "Dibatalkan", value: 2 }, - ]; - - const COLORS = ["#10B981", "#F59E0B", "#EF4444", "#6B7280"]; - const STATUS_COLORS: Record = { - selesai: "green", - berjalan: "blue", - tertunda: "red", - proses: "yellow", - }; - - // Discussion data - const discussions = [ - { - title: "Pembahasan APBDes 2026", - sender: "Kepala Desa", - timestamp: "2 jam yang lalu", - }, - { - title: "Kegiatan Posyandu", - sender: "Divisi Sosial", - timestamp: "5 jam yang lalu", - }, - { - title: "Festival Budaya", - sender: "Divisi Humas", - timestamp: "1 hari yang lalu", - }, - ]; - - // Today's agenda - const todayAgenda = [ - { time: "09:00", event: "Rapat Evaluasi Bulanan" }, - { time: "14:00", event: "Koordinasi Program Bantuan" }, - ]; - return ( - {/* Grafik Progres Tugas per Divisi */} - - - Grafik Progres Tugas per Divisi - - - - - - - - - - - - - - - {/* Ringkasan Tugas per Divisi */} + {/* SECTION 1 — PROGRAM KEGIATAN */} - {divisionTasks.map((division, index) => ( - - - - {division.name} - - - {division.tasks.map((task, taskIndex) => ( - - - - {task.title} - - - {task.status} - - - - ))} - - - + {programKegiatanData.map((kegiatan, index) => ( + + + ))} - {/* Arsip Digital Perangkat Desa */} - - - Arsip Digital Perangkat Desa - - - {archiveItems.map((item, index) => ( - - - - - {item.name} - - - {item.count} - - - - - ))} - - + {/* SECTION 2 — GRID DASHBOARD (3 Columns) */} + + {/* Left Column - Division List */} + + + - {/* Kartu Progres Kegiatan */} - - - Progres Kegiatan / Program - - - {activityProgress.map((activity, index) => ( - - - - {activity.name} - - - {activity.status} - - - - - - {activity.progress}% - - - - {activity.date} - - - ))} - - + {/* Middle Column - Document Chart */} + + + - {/* Statistik Dokumen & Progres Kegiatan */} - - - - - Jumlah Dokumen - - - - - - - - - - - - - - - - - Progres Kegiatan - - - - - `${name}: ${percent ? (percent * 100).toFixed(0) : "0"}%` - } - > - {activityProgressStats.map((entry, index) => ( - - ))} - - - - - - + {/* Right Column - Progress Chart */} + + + - {/* Diskusi Internal */} - - - Diskusi Internal - - - {discussions.map((discussion, index) => ( - - - - {discussion.title} - - - {discussion.timestamp} - - - - {discussion.sender} - - - ))} - - + {/* SECTION 3 — DISCUSSION PANEL */} + - {/* Agenda / Acara Hari Ini */} - - - Agenda / Acara Hari Ini - - {todayAgenda.length > 0 ? ( - - {todayAgenda.map((agenda, index) => ( - - - {agenda.time} - - - - {agenda.event} - - - ))} - - ) : ( - - Tidak ada acara hari ini - - )} - + {/* SECTION 4 — ACARA HARI INI */} + + + {/* SECTION 5 — ARSIP DIGITAL PERANGKAT DESA */} + + {archiveData.map((item, index) => ( + + + + ))} + ); }; -export default KinerjaDivisi; \ No newline at end of file +export default KinerjaDivisi; diff --git a/src/components/kinerja-divisi/activity-card.tsx b/src/components/kinerja-divisi/activity-card.tsx new file mode 100644 index 0000000..94d987a --- /dev/null +++ b/src/components/kinerja-divisi/activity-card.tsx @@ -0,0 +1,95 @@ +import { + Box, + Card, + Group, + Progress, + Text, + useMantineColorScheme, +} from "@mantine/core"; + +interface ActivityCardProps { + title: string; + date: string; + progress: number; + status: "selesai" | "berjalan" | "tertunda"; +} + +export function ActivityCard({ + title, + date, + progress, + status, +}: ActivityCardProps) { + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + + const getStatusColor = (s: string) => { + switch (s) { + case "selesai": + return "#22C55E"; + case "berjalan": + return "#3B82F6"; + case "tertunda": + return "#EF4444"; + default: + return "#9CA3AF"; + } + }; + + return ( + + + + {title} + + + + + + {date} + + + {status.toUpperCase()} + + + + + + + {progress}% + + + ); +} diff --git a/src/components/kinerja-divisi/archive-card.tsx b/src/components/kinerja-divisi/archive-card.tsx new file mode 100644 index 0000000..ca5f5bd --- /dev/null +++ b/src/components/kinerja-divisi/archive-card.tsx @@ -0,0 +1,41 @@ +import { Card, Group, Text, useMantineColorScheme } from "@mantine/core"; +import { FileText } from "lucide-react"; + +interface ArchiveItem { + name: string; +} + +interface ArchiveCardProps { + item: ArchiveItem; + onClick?: () => void; +} + +export function ArchiveCard({ item, onClick }: ArchiveCardProps) { + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + + return ( + + + + + {item.name} + + + + ); +} diff --git a/src/components/kinerja-divisi/discussion-panel.tsx b/src/components/kinerja-divisi/discussion-panel.tsx new file mode 100644 index 0000000..28b48b3 --- /dev/null +++ b/src/components/kinerja-divisi/discussion-panel.tsx @@ -0,0 +1,92 @@ +import { + Box, + Card, + Group, + Stack, + Text, + useMantineColorScheme, +} from "@mantine/core"; +import { MessageCircle } from "lucide-react"; + +interface DiscussionItem { + message: string; + sender: string; + date: string; +} + +const discussions: DiscussionItem[] = [ + { + message: "Kepada Pelayanan, mohon di cek...", + sender: "I.B Surya Prabhawa Manu", + date: "12 Apr 2025", + }, + { + message: "Kepada staf perencanaan @suar...", + sender: "Ni Nyoman Yuliani", + date: "14 Jun 2025", + }, + { + message: "ijin atau mohon kepada KBD sar...", + sender: "Ni Wayan Martini", + date: "12 Apr 2025", + }, +]; + +export function DiscussionPanel() { + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + + return ( + + + + + Diskusi + + + + {discussions.map((discussion, index) => ( + + + {discussion.message} + + + + {discussion.sender} + + + {discussion.date} + + + + ))} + + + ); +} diff --git a/src/components/kinerja-divisi/division-list.tsx b/src/components/kinerja-divisi/division-list.tsx new file mode 100644 index 0000000..eb6ca58 --- /dev/null +++ b/src/components/kinerja-divisi/division-list.tsx @@ -0,0 +1,77 @@ +import { + Box, + Card, + Group, + Stack, + Text, + useMantineColorScheme, +} from "@mantine/core"; +import { ChevronRight } from "lucide-react"; + +interface DivisionItem { + name: string; + count: number; +} + +const divisionData: DivisionItem[] = [ + { name: "Kesejahteraan", count: 37 }, + { name: "Pemerintahan", count: 26 }, + { name: "Keuangan", count: 17 }, + { name: "Sekretaris Desa", count: 15 }, + { name: "Tata Usaha TK", count: 14 }, + { name: "Perangkat Kewilayahan", count: 12 }, + { name: "Pelayanan", count: 10 }, + { name: "Perencanaan", count: 9 }, + { name: "Tata Usaha & Umum", count: 7 }, +]; + +export function DivisionList() { + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + + return ( + + + Divisi Teraktif + + + {divisionData.map((division, index) => ( + + + {division.name} + + + + {division.count} + + + + + ))} + + + ); +} diff --git a/src/components/kinerja-divisi/document-chart.tsx b/src/components/kinerja-divisi/document-chart.tsx new file mode 100644 index 0000000..fc83e9c --- /dev/null +++ b/src/components/kinerja-divisi/document-chart.tsx @@ -0,0 +1,69 @@ +import { Card, Text, useMantineColorScheme } from "@mantine/core"; +import { + Bar, + BarChart, + CartesianGrid, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; + +const documentData = [ + { name: "Gambar", value: 300 }, + { name: "Dokumen", value: 310 }, +]; + +export function DocumentChart() { + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + + return ( + + + Jumlah Dokumen + + + + + + + + + + + + ); +} diff --git a/src/components/kinerja-divisi/event-card.tsx b/src/components/kinerja-divisi/event-card.tsx new file mode 100644 index 0000000..dc771d2 --- /dev/null +++ b/src/components/kinerja-divisi/event-card.tsx @@ -0,0 +1,65 @@ +import { + Box, + Card, + Group, + Stack, + Text, + useMantineColorScheme, +} from "@mantine/core"; +import { Calendar } from "lucide-react"; + +interface AgendaItem { + time: string; + event: string; +} + +interface EventCardProps { + agendas?: AgendaItem[]; +} + +export function EventCard({ agendas = [] }: EventCardProps) { + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + + return ( + + + + + Acara Hari Ini + + + {agendas.length > 0 ? ( + + {agendas.map((agenda, index) => ( + + + + {agenda.time} + + + + {agenda.event} + + + ))} + + ) : ( + + Tidak ada acara hari ini + + )} + + ); +} diff --git a/src/components/kinerja-divisi/index.ts b/src/components/kinerja-divisi/index.ts new file mode 100644 index 0000000..ac49f14 --- /dev/null +++ b/src/components/kinerja-divisi/index.ts @@ -0,0 +1,7 @@ +export { ActivityCard } from "./activity-card"; +export { ArchiveCard } from "./archive-card"; +export { DiscussionPanel } from "./discussion-panel"; +export { DivisionList } from "./division-list"; +export { DocumentChart } from "./document-chart"; +export { EventCard } from "./event-card"; +export { ProgressChart } from "./progress-chart"; diff --git a/src/components/kinerja-divisi/progress-chart.tsx b/src/components/kinerja-divisi/progress-chart.tsx new file mode 100644 index 0000000..e014f6b --- /dev/null +++ b/src/components/kinerja-divisi/progress-chart.tsx @@ -0,0 +1,84 @@ +import { + Box, + Card, + Group, + Stack, + Text, + useMantineColorScheme, +} from "@mantine/core"; +import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from "recharts"; + +const progressData = [ + { name: "Selesai", value: 83.33, color: "#22C55E" }, + { name: "Dikerjakan", value: 16.67, color: "#FACC15" }, + { name: "Segera Dikerjakan", value: 0, color: "#3B82F6" }, + { name: "Dibatalkan", value: 0, color: "#EF4444" }, +]; + +export function ProgressChart() { + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + + return ( + + + Progres Kegiatan + + + + + {progressData.map((entry, index) => ( + + ))} + + + + + + {progressData.map((item, index) => ( + + + + + {item.name} + + + + {item.value.toFixed(2)}% + + + ))} + + + ); +}