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 <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -1,543 +1,99 @@
|
|||||||
|
import { Grid, Stack } from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActivityCard,
|
||||||
Box,
|
ArchiveCard,
|
||||||
Card,
|
DiscussionPanel,
|
||||||
Divider,
|
DivisionList,
|
||||||
Grid,
|
DocumentChart,
|
||||||
GridCol,
|
EventCard,
|
||||||
Group,
|
ProgressChart,
|
||||||
List,
|
} from ".";
|
||||||
Badge as MantineBadge,
|
|
||||||
Progress as MantineProgress,
|
// Data for program kegiatan (Section 1)
|
||||||
Skeleton,
|
const programKegiatanData = [
|
||||||
Stack,
|
{
|
||||||
Text,
|
title: "Rakor 2025",
|
||||||
ThemeIcon,
|
date: "3 Juli 2025",
|
||||||
Title,
|
progress: 90,
|
||||||
useMantineColorScheme,
|
status: "selesai" as const,
|
||||||
} from "@mantine/core";
|
},
|
||||||
import {
|
{
|
||||||
Bar,
|
title: "Pemutakhiran Indeks Desa",
|
||||||
BarChart,
|
date: "3 Juli 2025",
|
||||||
CartesianGrid,
|
progress: 85,
|
||||||
Cell,
|
status: "selesai" as const,
|
||||||
Pie,
|
},
|
||||||
PieChart,
|
{
|
||||||
ResponsiveContainer,
|
title: "Mengurus Akta Cerai Warga",
|
||||||
Tooltip,
|
date: "3 Juli 2025",
|
||||||
XAxis,
|
progress: 80,
|
||||||
YAxis,
|
status: "selesai" as const,
|
||||||
} from "recharts";
|
},
|
||||||
import { Button } from "@/components/ui/button";
|
{
|
||||||
|
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 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<string, string> = {
|
|
||||||
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 (
|
return (
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
{/* Grafik Progres Tugas per Divisi */}
|
{/* SECTION 1 — PROGRAM KEGIATAN */}
|
||||||
<Card
|
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#141D34" : "white"}
|
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
|
||||||
>
|
|
||||||
<Title order={4} mb="md" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
Grafik Progres Tugas per Divisi
|
|
||||||
</Title>
|
|
||||||
<ResponsiveContainer width="100%" height={300}>
|
|
||||||
<BarChart data={divisionProgressData}>
|
|
||||||
<CartesianGrid
|
|
||||||
strokeDasharray="3 3"
|
|
||||||
vertical={false}
|
|
||||||
stroke={dark ? "#141D34" : "white"}
|
|
||||||
/>
|
|
||||||
<XAxis
|
|
||||||
dataKey="name"
|
|
||||||
axisLine={false}
|
|
||||||
tickLine={false}
|
|
||||||
tick={{
|
|
||||||
fill: dark
|
|
||||||
? "var(--mantine-color-text)"
|
|
||||||
: "var(--mantine-color-text)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<YAxis
|
|
||||||
axisLine={false}
|
|
||||||
tickLine={false}
|
|
||||||
tick={{
|
|
||||||
fill: dark
|
|
||||||
? "var(--mantine-color-text)"
|
|
||||||
: "var(--mantine-color-text)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tooltip
|
|
||||||
contentStyle={
|
|
||||||
dark
|
|
||||||
? {
|
|
||||||
backgroundColor: "var(--mantine-color-dark-7)",
|
|
||||||
borderColor: "var(--mantine-color-dark-6)",
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="selesai"
|
|
||||||
stackId="a"
|
|
||||||
fill="#10B981"
|
|
||||||
name="Selesai"
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="berjalan"
|
|
||||||
stackId="a"
|
|
||||||
fill="#3B82F6"
|
|
||||||
name="Berjalan"
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="tertunda"
|
|
||||||
stackId="a"
|
|
||||||
fill="#EF4444"
|
|
||||||
name="Tertunda"
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Ringkasan Tugas per Divisi */}
|
|
||||||
<Grid gutter="md">
|
<Grid gutter="md">
|
||||||
{divisionTasks.map((division, index) => (
|
{programKegiatanData.map((kegiatan, index) => (
|
||||||
<GridCol key={index} span={{ base: 12, md: 6, lg: 3 }}>
|
<Grid.Col key={index} span={{ base: 12, md: 6, lg: 3 }}>
|
||||||
<Card
|
<ActivityCard
|
||||||
p="md"
|
title={kegiatan.title}
|
||||||
radius="md"
|
date={kegiatan.date}
|
||||||
withBorder
|
progress={kegiatan.progress}
|
||||||
bg={dark ? "#141D34" : "white"}
|
status={kegiatan.status}
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
/>
|
||||||
h="100%"
|
</Grid.Col>
|
||||||
>
|
|
||||||
<Title order={4} mb="sm" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
{division.name}
|
|
||||||
</Title>
|
|
||||||
<Stack gap="sm">
|
|
||||||
{division.tasks.map((task, taskIndex) => (
|
|
||||||
<Box key={taskIndex}>
|
|
||||||
<Group justify="space-between">
|
|
||||||
<Text size="sm" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
{task.title}
|
|
||||||
</Text>
|
|
||||||
<MantineBadge
|
|
||||||
color={STATUS_COLORS[task.status] || "gray"}
|
|
||||||
variant="light"
|
|
||||||
>
|
|
||||||
{task.status}
|
|
||||||
</MantineBadge>
|
|
||||||
</Group>
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Card>
|
|
||||||
</GridCol>
|
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* Arsip Digital Perangkat Desa */}
|
{/* SECTION 2 — GRID DASHBOARD (3 Columns) */}
|
||||||
<Card
|
<Grid gutter="lg">
|
||||||
p="md"
|
{/* Left Column - Division List */}
|
||||||
radius="md"
|
<Grid.Col span={{ base: 12, lg: 3 }}>
|
||||||
withBorder
|
<DivisionList />
|
||||||
bg={dark ? "#141D34" : "white"}
|
</Grid.Col>
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
|
||||||
>
|
|
||||||
<Title order={4} mb="md" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
Arsip Digital Perangkat Desa
|
|
||||||
</Title>
|
|
||||||
<Grid gutter="md">
|
|
||||||
{archiveItems.map((item, index) => (
|
|
||||||
<GridCol key={index} span={{ base: 12, md: 6, lg: 3 }}>
|
|
||||||
<Card
|
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#263852ff" : "#F1F5F9"}
|
|
||||||
style={{ borderColor: dark ? "#263852ff" : "#F1F5F9" }}
|
|
||||||
>
|
|
||||||
<Group justify="space-between">
|
|
||||||
<Text c={dark ? "white" : "darmasaba-navy"} fw={500}>
|
|
||||||
{item.name}
|
|
||||||
</Text>
|
|
||||||
<Text c={dark ? "white" : "darmasaba-navy"} fw={700}>
|
|
||||||
{item.count}
|
|
||||||
</Text>
|
|
||||||
</Group>
|
|
||||||
</Card>
|
|
||||||
</GridCol>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Kartu Progres Kegiatan */}
|
{/* Middle Column - Document Chart */}
|
||||||
<Card
|
<Grid.Col span={{ base: 12, lg: 5 }}>
|
||||||
p="md"
|
<DocumentChart />
|
||||||
radius="md"
|
</Grid.Col>
|
||||||
withBorder
|
|
||||||
bg={dark ? "#141D34" : "white"}
|
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
|
||||||
>
|
|
||||||
<Title order={4} mb="md" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
Progres Kegiatan / Program
|
|
||||||
</Title>
|
|
||||||
<Stack gap="md">
|
|
||||||
{activityProgress.map((activity, index) => (
|
|
||||||
<Card
|
|
||||||
key={index}
|
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#263852ff" : "#F1F5F9"}
|
|
||||||
style={{ borderColor: dark ? "#263852ff" : "#F1F5F9" }}
|
|
||||||
>
|
|
||||||
<Group justify="space-between" mb="sm">
|
|
||||||
<Text c={dark ? "white" : "darmasaba-navy"} fw={500}>
|
|
||||||
{activity.name}
|
|
||||||
</Text>
|
|
||||||
<MantineBadge
|
|
||||||
color={STATUS_COLORS[activity.status] || "gray"}
|
|
||||||
variant="light"
|
|
||||||
>
|
|
||||||
{activity.status}
|
|
||||||
</MantineBadge>
|
|
||||||
</Group>
|
|
||||||
<Group justify="space-between">
|
|
||||||
<MantineProgress
|
|
||||||
value={activity.progress}
|
|
||||||
size="sm"
|
|
||||||
radius="xl"
|
|
||||||
color={activity.progress === 100 ? "green" : "blue"}
|
|
||||||
w="calc(100% - 80px)"
|
|
||||||
/>
|
|
||||||
<Text size="sm" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
{activity.progress}%
|
|
||||||
</Text>
|
|
||||||
</Group>
|
|
||||||
<Text size="sm" c="dimmed" mt="sm">
|
|
||||||
{activity.date}
|
|
||||||
</Text>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Statistik Dokumen & Progres Kegiatan */}
|
{/* Right Column - Progress Chart */}
|
||||||
<Grid gutter="md">
|
<Grid.Col span={{ base: 12, lg: 4 }}>
|
||||||
<GridCol span={{ base: 12, lg: 6 }}>
|
<ProgressChart />
|
||||||
<Card
|
</Grid.Col>
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#141D34" : "white"}
|
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
|
||||||
>
|
|
||||||
<Title order={4} mb="md" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
Jumlah Dokumen
|
|
||||||
</Title>
|
|
||||||
<ResponsiveContainer width="100%" height={200}>
|
|
||||||
<BarChart data={documentStats}>
|
|
||||||
<CartesianGrid
|
|
||||||
strokeDasharray="3 3"
|
|
||||||
vertical={false}
|
|
||||||
stroke={dark ? "#141D34" : "white"}
|
|
||||||
/>
|
|
||||||
<XAxis
|
|
||||||
dataKey="name"
|
|
||||||
axisLine={false}
|
|
||||||
tickLine={false}
|
|
||||||
tick={{
|
|
||||||
fill: dark
|
|
||||||
? "var(--mantine-color-text)"
|
|
||||||
: "var(--mantine-color-text)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<YAxis
|
|
||||||
axisLine={false}
|
|
||||||
tickLine={false}
|
|
||||||
tick={{
|
|
||||||
fill: dark
|
|
||||||
? "var(--mantine-color-text)"
|
|
||||||
: "var(--mantine-color-text)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tooltip
|
|
||||||
contentStyle={
|
|
||||||
dark
|
|
||||||
? {
|
|
||||||
backgroundColor: "var(--mantine-color-dark-7)",
|
|
||||||
borderColor: "var(--mantine-color-dark-6)",
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="value"
|
|
||||||
fill={
|
|
||||||
dark
|
|
||||||
? "var(--mantine-color-blue-6)"
|
|
||||||
: "var(--mantine-color-blue-filled)"
|
|
||||||
}
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</Card>
|
|
||||||
</GridCol>
|
|
||||||
|
|
||||||
<GridCol span={{ base: 12, lg: 6 }}>
|
|
||||||
<Card
|
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#141D34" : "white"}
|
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
|
||||||
>
|
|
||||||
<Title order={4} mb="md" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
Progres Kegiatan
|
|
||||||
</Title>
|
|
||||||
<ResponsiveContainer width="100%" height={200}>
|
|
||||||
<PieChart>
|
|
||||||
<Pie
|
|
||||||
data={activityProgressStats}
|
|
||||||
cx="50%"
|
|
||||||
cy="50%"
|
|
||||||
labelLine={false}
|
|
||||||
outerRadius={80}
|
|
||||||
fill="#8884d8"
|
|
||||||
dataKey="value"
|
|
||||||
label={({ name, percent }) =>
|
|
||||||
`${name}: ${percent ? (percent * 100).toFixed(0) : "0"}%`
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{activityProgressStats.map((entry, index) => (
|
|
||||||
<Cell
|
|
||||||
key={`cell-${index}`}
|
|
||||||
fill={COLORS[index % COLORS.length]}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
<Tooltip
|
|
||||||
contentStyle={
|
|
||||||
dark
|
|
||||||
? {
|
|
||||||
backgroundColor: "var(--mantine-color-dark-7)",
|
|
||||||
borderColor: "var(--mantine-color-dark-6)",
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</PieChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</Card>
|
|
||||||
</GridCol>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* Diskusi Internal */}
|
{/* SECTION 3 — DISCUSSION PANEL */}
|
||||||
<Card
|
<DiscussionPanel />
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#141D34" : "white"}
|
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
|
||||||
>
|
|
||||||
<Title order={4} mb="md" c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
Diskusi Internal
|
|
||||||
</Title>
|
|
||||||
<Stack gap="sm">
|
|
||||||
{discussions.map((discussion, index) => (
|
|
||||||
<Card
|
|
||||||
key={index}
|
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#263852ff" : "#F1F5F9"}
|
|
||||||
style={{ borderColor: dark ? "#263852ff" : "#F1F5F9" }}
|
|
||||||
>
|
|
||||||
<Group justify="space-between">
|
|
||||||
<Text c={dark ? "white" : "darmasaba-navy"} fw={500}>
|
|
||||||
{discussion.title}
|
|
||||||
</Text>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{discussion.timestamp}
|
|
||||||
</Text>
|
|
||||||
</Group>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{discussion.sender}
|
|
||||||
</Text>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Agenda / Acara Hari Ini */}
|
{/* SECTION 4 — ACARA HARI INI */}
|
||||||
<Card
|
<EventCard />
|
||||||
p="md"
|
|
||||||
radius="md"
|
{/* SECTION 5 — ARSIP DIGITAL PERANGKAT DESA */}
|
||||||
withBorder
|
<Grid gutter="md">
|
||||||
bg={dark ? "#141D34" : "white"}
|
{archiveData.map((item, index) => (
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
<Grid.Col key={index} span={{ base: 12, md: 6 }}>
|
||||||
>
|
<ArchiveCard item={item} />
|
||||||
<Title order={4} mb="md" c={dark ? "white" : "darmasaba-navy"}>
|
</Grid.Col>
|
||||||
Agenda / Acara Hari Ini
|
))}
|
||||||
</Title>
|
</Grid>
|
||||||
{todayAgenda.length > 0 ? (
|
|
||||||
<Stack gap="sm">
|
|
||||||
{todayAgenda.map((agenda, index) => (
|
|
||||||
<Group key={index} align="flex-start">
|
|
||||||
<Box w={60}>
|
|
||||||
<Text c="dimmed">{agenda.time}</Text>
|
|
||||||
</Box>
|
|
||||||
<Divider orientation="vertical" mx="sm" />
|
|
||||||
<Text c={dark ? "white" : "darmasaba-navy"}>
|
|
||||||
{agenda.event}
|
|
||||||
</Text>
|
|
||||||
</Group>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
) : (
|
|
||||||
<Text c="dimmed" ta="center" py="md">
|
|
||||||
Tidak ada acara hari ini
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
95
src/components/kinerja-divisi/activity-card.tsx
Normal file
95
src/components/kinerja-divisi/activity-card.tsx
Normal file
@@ -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 (
|
||||||
|
<Card
|
||||||
|
p="md"
|
||||||
|
radius="xl"
|
||||||
|
withBorder
|
||||||
|
bg={dark ? "#1E293B" : "white"}
|
||||||
|
style={{
|
||||||
|
borderColor: dark ? "#334155" : "white",
|
||||||
|
boxShadow: dark
|
||||||
|
? "0 1px 3px 0 rgb(0 0 0 / 0.1)"
|
||||||
|
: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
borderLeft: `4px solid #3B82F6`,
|
||||||
|
paddingLeft: 12,
|
||||||
|
marginBottom: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "#1E3A5F"}>
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Group justify="space-between" mb="xs">
|
||||||
|
<Text size="xs" c="dimmed">
|
||||||
|
{date}
|
||||||
|
</Text>
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
backgroundColor: getStatusColor(status),
|
||||||
|
color: "white",
|
||||||
|
padding: "2px 8px",
|
||||||
|
borderRadius: 4,
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: 600,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{status.toUpperCase()}
|
||||||
|
</Box>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Progress
|
||||||
|
value={progress}
|
||||||
|
size="sm"
|
||||||
|
radius="xl"
|
||||||
|
color={progress === 100 ? "green" : "yellow"}
|
||||||
|
animated={progress < 100}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text size="xs" c="dimmed" mt="xs" ta="right">
|
||||||
|
{progress}%
|
||||||
|
</Text>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
41
src/components/kinerja-divisi/archive-card.tsx
Normal file
41
src/components/kinerja-divisi/archive-card.tsx
Normal file
@@ -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 (
|
||||||
|
<Card
|
||||||
|
p="md"
|
||||||
|
radius="xl"
|
||||||
|
withBorder
|
||||||
|
bg={dark ? "#1E293B" : "white"}
|
||||||
|
style={{
|
||||||
|
borderColor: dark ? "#334155" : "#e5e7eb",
|
||||||
|
boxShadow: dark
|
||||||
|
? "0 1px 3px 0 rgb(0 0 0 / 0.1)"
|
||||||
|
: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
||||||
|
cursor: "pointer",
|
||||||
|
transition: "transform 0.2s, box-shadow 0.2s",
|
||||||
|
}}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
<Group gap="md">
|
||||||
|
<FileText size={32} color={dark ? "#60A5FA" : "#3B82F6"} />
|
||||||
|
<Text size="sm" fw={500} c={dark ? "white" : "#1E3A5F"}>
|
||||||
|
{item.name}
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
92
src/components/kinerja-divisi/discussion-panel.tsx
Normal file
92
src/components/kinerja-divisi/discussion-panel.tsx
Normal file
@@ -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 (
|
||||||
|
<Card
|
||||||
|
p="md"
|
||||||
|
radius="xl"
|
||||||
|
withBorder
|
||||||
|
bg={dark ? "#1E293B" : "white"}
|
||||||
|
style={{
|
||||||
|
borderColor: dark ? "#334155" : "white",
|
||||||
|
boxShadow: dark
|
||||||
|
? "0 1px 3px 0 rgb(0 0 0 / 0.1)"
|
||||||
|
: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Group gap="xs" mb="md">
|
||||||
|
<MessageCircle size={20} color={dark ? "#E2E8F0" : "#1E3A5F"} />
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "#1E3A5F"}>
|
||||||
|
Diskusi
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
<Stack gap="sm">
|
||||||
|
{discussions.map((discussion, index) => (
|
||||||
|
<Card
|
||||||
|
key={index}
|
||||||
|
p="sm"
|
||||||
|
radius="md"
|
||||||
|
withBorder
|
||||||
|
bg={dark ? "#334155" : "#F1F5F9"}
|
||||||
|
style={{
|
||||||
|
borderColor: dark ? "#334155" : "#F1F5F9",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
size="sm"
|
||||||
|
c={dark ? "white" : "#1E3A5F"}
|
||||||
|
fw={500}
|
||||||
|
mb="xs"
|
||||||
|
lineClamp={2}
|
||||||
|
>
|
||||||
|
{discussion.message}
|
||||||
|
</Text>
|
||||||
|
<Group justify="space-between">
|
||||||
|
<Text size="xs" c="dimmed">
|
||||||
|
{discussion.sender}
|
||||||
|
</Text>
|
||||||
|
<Text size="xs" c="dimmed">
|
||||||
|
{discussion.date}
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
77
src/components/kinerja-divisi/division-list.tsx
Normal file
77
src/components/kinerja-divisi/division-list.tsx
Normal file
@@ -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 (
|
||||||
|
<Card
|
||||||
|
p="md"
|
||||||
|
radius="xl"
|
||||||
|
withBorder
|
||||||
|
bg={dark ? "#1E293B" : "white"}
|
||||||
|
style={{
|
||||||
|
borderColor: dark ? "#334155" : "white",
|
||||||
|
boxShadow: dark
|
||||||
|
? "0 1px 3px 0 rgb(0 0 0 / 0.1)"
|
||||||
|
: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
||||||
|
}}
|
||||||
|
h="100%"
|
||||||
|
>
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "#1E3A5F"} mb="md">
|
||||||
|
Divisi Teraktif
|
||||||
|
</Text>
|
||||||
|
<Stack gap="xs">
|
||||||
|
{divisionData.map((division, index) => (
|
||||||
|
<Group
|
||||||
|
key={index}
|
||||||
|
justify="space-between"
|
||||||
|
align="center"
|
||||||
|
style={{
|
||||||
|
padding: "8px 12px",
|
||||||
|
borderRadius: 8,
|
||||||
|
backgroundColor: dark ? "#334155" : "#F1F5F9",
|
||||||
|
transition: "background-color 0.2s",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text size="sm" c={dark ? "white" : "#1E3A5F"}>
|
||||||
|
{division.name}
|
||||||
|
</Text>
|
||||||
|
<Group gap="xs">
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "#1E3A5F"}>
|
||||||
|
{division.count}
|
||||||
|
</Text>
|
||||||
|
<ChevronRight size={16} color={dark ? "#94A3B8" : "#64748B"} />
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
69
src/components/kinerja-divisi/document-chart.tsx
Normal file
69
src/components/kinerja-divisi/document-chart.tsx
Normal file
@@ -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 (
|
||||||
|
<Card
|
||||||
|
p="md"
|
||||||
|
radius="xl"
|
||||||
|
withBorder
|
||||||
|
bg={dark ? "#1E293B" : "white"}
|
||||||
|
style={{
|
||||||
|
borderColor: dark ? "#334155" : "white",
|
||||||
|
boxShadow: dark
|
||||||
|
? "0 1px 3px 0 rgb(0 0 0 / 0.1)"
|
||||||
|
: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
||||||
|
}}
|
||||||
|
h="100%"
|
||||||
|
>
|
||||||
|
<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="value" fill="#3B82F6" radius={[4, 4, 0, 0]} />
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
65
src/components/kinerja-divisi/event-card.tsx
Normal file
65
src/components/kinerja-divisi/event-card.tsx
Normal file
@@ -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 (
|
||||||
|
<Card
|
||||||
|
p="md"
|
||||||
|
radius="xl"
|
||||||
|
withBorder
|
||||||
|
bg={dark ? "#1E293B" : "white"}
|
||||||
|
style={{
|
||||||
|
borderColor: dark ? "#334155" : "white",
|
||||||
|
boxShadow: dark
|
||||||
|
? "0 1px 3px 0 rgb(0 0 0 / 0.1)"
|
||||||
|
: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Group gap="xs" mb="md">
|
||||||
|
<Calendar size={20} color={dark ? "#E2E8F0" : "#1E3A5F"} />
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "#1E3A5F"}>
|
||||||
|
Acara Hari Ini
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
{agendas.length > 0 ? (
|
||||||
|
<Stack gap="sm">
|
||||||
|
{agendas.map((agenda, index) => (
|
||||||
|
<Group key={index} align="flex-start" gap="md">
|
||||||
|
<Box w={60}>
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "#1E3A5F"}>
|
||||||
|
{agenda.time}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Text size="sm" c={dark ? "white" : "#1E3A5F"}>
|
||||||
|
{agenda.event}
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
) : (
|
||||||
|
<Text c="dimmed" ta="center" py="md">
|
||||||
|
Tidak ada acara hari ini
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
src/components/kinerja-divisi/index.ts
Normal file
7
src/components/kinerja-divisi/index.ts
Normal file
@@ -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";
|
||||||
84
src/components/kinerja-divisi/progress-chart.tsx
Normal file
84
src/components/kinerja-divisi/progress-chart.tsx
Normal file
@@ -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 (
|
||||||
|
<Card
|
||||||
|
p="md"
|
||||||
|
radius="xl"
|
||||||
|
withBorder
|
||||||
|
bg={dark ? "#1E293B" : "white"}
|
||||||
|
style={{
|
||||||
|
borderColor: dark ? "#334155" : "white",
|
||||||
|
boxShadow: dark
|
||||||
|
? "0 1px 3px 0 rgb(0 0 0 / 0.1)"
|
||||||
|
: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
||||||
|
}}
|
||||||
|
h="100%"
|
||||||
|
>
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "#1E3A5F"} mb="md">
|
||||||
|
Progres Kegiatan
|
||||||
|
</Text>
|
||||||
|
<ResponsiveContainer width="100%" height={200}>
|
||||||
|
<PieChart>
|
||||||
|
<Pie
|
||||||
|
data={progressData}
|
||||||
|
cx="50%"
|
||||||
|
cy="50%"
|
||||||
|
innerRadius={60}
|
||||||
|
outerRadius={80}
|
||||||
|
paddingAngle={2}
|
||||||
|
dataKey="value"
|
||||||
|
>
|
||||||
|
{progressData.map((entry, index) => (
|
||||||
|
<Cell key={`cell-${index}`} fill={entry.color} />
|
||||||
|
))}
|
||||||
|
</Pie>
|
||||||
|
<Tooltip
|
||||||
|
contentStyle={{
|
||||||
|
backgroundColor: dark ? "#1E293B" : "white",
|
||||||
|
borderColor: dark ? "#334155" : "#e5e7eb",
|
||||||
|
borderRadius: "8px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</PieChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
<Stack gap="xs" mt="md">
|
||||||
|
{progressData.map((item, index) => (
|
||||||
|
<Group key={index} justify="space-between">
|
||||||
|
<Group gap="xs">
|
||||||
|
<Box
|
||||||
|
w={12}
|
||||||
|
h={12}
|
||||||
|
style={{ backgroundColor: item.color, borderRadius: 2 }}
|
||||||
|
/>
|
||||||
|
<Text size="sm" c={dark ? "white" : "gray.7"}>
|
||||||
|
{item.name}
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "gray.9"}>
|
||||||
|
{item.value.toFixed(2)}%
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user