Fix New UI Pengaduan
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -37,6 +37,9 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
|||||||
# Dashboard-MD
|
# Dashboard-MD
|
||||||
Dashboard-MD
|
Dashboard-MD
|
||||||
|
|
||||||
|
# md
|
||||||
|
*.md
|
||||||
|
|
||||||
# Playwright artifacts
|
# Playwright artifacts
|
||||||
test-results/
|
test-results/
|
||||||
playwright-report/
|
playwright-report/
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
Create a modern admin dashboard UI for a village management system using React 19 + Vite + TailwindCSS + Mantine components + Recharts.
|
|
||||||
|
|
||||||
Design style:
|
|
||||||
- Clean, soft UI with rounded corners (2xl)
|
|
||||||
- Light gray background (#f5f6f8)
|
|
||||||
- Card-based layout with subtle shadow
|
|
||||||
- Smooth spacing and consistent padding
|
|
||||||
- Professional government-style but still modern
|
|
||||||
- Use Inter or system font
|
|
||||||
- Primary color: dark blue
|
|
||||||
- Accent color: orange for progress
|
|
||||||
- Success color: green
|
|
||||||
- Use Mantine components where possible
|
|
||||||
|
|
||||||
Layout:
|
|
||||||
- Responsive grid layout (desktop-first)
|
|
||||||
- 4 summary cards on top (horizontal)
|
|
||||||
- 2 columns main content below
|
|
||||||
- Left sidebar for division list
|
|
||||||
- Right content for charts and activity
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔹 TOP CARDS (4 ITEMS)
|
|
||||||
Each card contains:
|
|
||||||
- Title (e.g: "Rakor 2025")
|
|
||||||
- Progress bar (orange)
|
|
||||||
- Date (small text)
|
|
||||||
- Status badge "Selesai" (green)
|
|
||||||
|
|
||||||
Use:
|
|
||||||
- Mantine Card
|
|
||||||
- Mantine Progress
|
|
||||||
- Mantine Badge
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔹 LEFT PANEL - "Divisi teraktif"
|
|
||||||
Vertical list of divisions:
|
|
||||||
- Each item is clickable
|
|
||||||
- Show division name + number of activities
|
|
||||||
- Rounded container with hover effect
|
|
||||||
- Chevron icon on right
|
|
||||||
|
|
||||||
Example items:
|
|
||||||
- Kesejahteraan (37 kegiatan)
|
|
||||||
- Pemerintahan (26 kegiatan)
|
|
||||||
- Keuangan (17 kegiatan)
|
|
||||||
- etc
|
|
||||||
|
|
||||||
Use:
|
|
||||||
- Scrollable container
|
|
||||||
- Soft border + hover highlight
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔹 CENTER - BAR CHART (Jumlah Dokumen)
|
|
||||||
- Use Recharts
|
|
||||||
- Two bars:
|
|
||||||
- Gambar
|
|
||||||
- Dokumen
|
|
||||||
- Color:
|
|
||||||
- Yellow/orange
|
|
||||||
- Green
|
|
||||||
- Show Y axis scale (0–400)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔹 RIGHT - PIE CHART (Progres Kegiatan)
|
|
||||||
- Use Recharts PieChart
|
|
||||||
- Segments:
|
|
||||||
- Selesai (green ~83%)
|
|
||||||
- Dikerjakan (orange ~16%)
|
|
||||||
- Segera dikerjakan (blue)
|
|
||||||
- Dibatalkan (red)
|
|
||||||
- Include legend below
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔹 BOTTOM LEFT - Diskusi Panel
|
|
||||||
- List of discussion messages
|
|
||||||
- Each item:
|
|
||||||
- Title
|
|
||||||
- Sender name
|
|
||||||
- Date
|
|
||||||
- Styled like notification cards
|
|
||||||
- Compact and clean
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔹 BOTTOM RIGHT - "Acara Hari Ini"
|
|
||||||
- Empty state
|
|
||||||
- Show text: "Tidak ada acara hari ini"
|
|
||||||
- Centered, muted text
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚙️ TECH REQUIREMENTS
|
|
||||||
|
|
||||||
- Use React functional components
|
|
||||||
- Use TanStack Router (file-based or route config)
|
|
||||||
- Use Mantine for UI components
|
|
||||||
- Use Tailwind for layout and spacing
|
|
||||||
- Use Recharts for charts
|
|
||||||
- State management: Valtio (simple global state)
|
|
||||||
- Date formatting: dayjs
|
|
||||||
- Icons: lucide-react
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 COMPONENT STRUCTURE
|
|
||||||
|
|
||||||
- components/
|
|
||||||
- DashboardCard.tsx
|
|
||||||
- DivisionList.tsx
|
|
||||||
- BarChartCard.tsx
|
|
||||||
- PieChartCard.tsx
|
|
||||||
- DiscussionList.tsx
|
|
||||||
- EmptyState.tsx
|
|
||||||
|
|
||||||
- routes/
|
|
||||||
- dashboard.tsx
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✨ EXTRA (IMPORTANT FOR VIBE CODING)
|
|
||||||
|
|
||||||
- Add subtle hover animations (scale 1.02)
|
|
||||||
- Smooth transitions (150–200ms)
|
|
||||||
- Keep spacing consistent (gap-4 / gap-6)
|
|
||||||
- Avoid clutter, prioritize readability
|
|
||||||
- Make it feel "calm and productive"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Output:
|
|
||||||
- Full React component code (modular, not monolithic)
|
|
||||||
- Clean, readable, production-ready
|
|
||||||
- No unnecessary comments
|
|
||||||
@@ -1,302 +0,0 @@
|
|||||||
Buat halaman dashboard admin modern untuk sistem pemerintahan desa bernama **Darmasaba Dashboard NOC**.
|
|
||||||
|
|
||||||
Gunakan stack berikut:
|
|
||||||
|
|
||||||
Frontend:
|
|
||||||
|
|
||||||
* React 19
|
|
||||||
* Bun runtime
|
|
||||||
* Vite
|
|
||||||
* TailwindCSS
|
|
||||||
* Mantine UI
|
|
||||||
* Mantine Charts atau Recharts
|
|
||||||
* Tabler Icons
|
|
||||||
* TanStack Router
|
|
||||||
* Dayjs
|
|
||||||
|
|
||||||
UI harus modular dengan reusable components.
|
|
||||||
|
|
||||||
Gunakan **TailwindCSS sebagai styling utama** dengan warna dari konfigurasi berikut:
|
|
||||||
|
|
||||||
Primary:
|
|
||||||
darmasaba-navy (#1E3A5F)
|
|
||||||
|
|
||||||
Secondary:
|
|
||||||
darmasaba-blue (#3B82F6)
|
|
||||||
|
|
||||||
Success:
|
|
||||||
#22C55E
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
#FACC15
|
|
||||||
|
|
||||||
Danger:
|
|
||||||
#EF4444
|
|
||||||
|
|
||||||
Background:
|
|
||||||
#F5F8FB
|
|
||||||
|
|
||||||
Dashboard harus memiliki **Light Mode dan Dark Mode**.
|
|
||||||
|
|
||||||
Dark Mode Color Rules:
|
|
||||||
background: #0F172A
|
|
||||||
card: #1E293B
|
|
||||||
border: #334155
|
|
||||||
text: #E2E8F0
|
|
||||||
|
|
||||||
Card style:
|
|
||||||
|
|
||||||
* rounded-xl
|
|
||||||
* soft shadow
|
|
||||||
* padding besar
|
|
||||||
* border subtle
|
|
||||||
* smooth hover animation
|
|
||||||
|
|
||||||
Gunakan grid layout responsive.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
SECTION 1 — PROGRAM KEGIATAN
|
|
||||||
|
|
||||||
Buat 4 card horizontal di bagian atas yang menampilkan kegiatan desa.
|
|
||||||
|
|
||||||
Setiap card memiliki:
|
|
||||||
|
|
||||||
* header biru
|
|
||||||
* progress bar kegiatan
|
|
||||||
* tanggal kegiatan
|
|
||||||
* badge status
|
|
||||||
|
|
||||||
Data card:
|
|
||||||
|
|
||||||
1.
|
|
||||||
|
|
||||||
Judul: Rakor 2025
|
|
||||||
Tanggal: 3 Juli 2025
|
|
||||||
Progress: 90%
|
|
||||||
Status: selesai
|
|
||||||
|
|
||||||
2.
|
|
||||||
|
|
||||||
Judul: Pemutakhiran Indeks Desa
|
|
||||||
Tanggal: 3 Juli 2025
|
|
||||||
Progress: 85%
|
|
||||||
Status: selesai
|
|
||||||
|
|
||||||
3.
|
|
||||||
|
|
||||||
Judul: Mengurus Akta Cerai Warga
|
|
||||||
Tanggal: 3 Juli 2025
|
|
||||||
Progress: 80%
|
|
||||||
Status: selesai
|
|
||||||
|
|
||||||
4.
|
|
||||||
|
|
||||||
Judul: Pasek 7 Desa Adat
|
|
||||||
Tanggal: 3 Juli 2025
|
|
||||||
Progress: 92%
|
|
||||||
Status: selesai
|
|
||||||
|
|
||||||
Progress bar:
|
|
||||||
|
|
||||||
* rounded
|
|
||||||
* warna warning
|
|
||||||
* animasi smooth
|
|
||||||
|
|
||||||
Status badge:
|
|
||||||
|
|
||||||
* success color
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
SECTION 2 — GRID DASHBOARD
|
|
||||||
|
|
||||||
Layout:
|
|
||||||
|
|
||||||
3 column grid.
|
|
||||||
|
|
||||||
Left column (sidebar style):
|
|
||||||
Divisi Teraktif
|
|
||||||
|
|
||||||
List item card dengan arrow icon.
|
|
||||||
|
|
||||||
Data:
|
|
||||||
|
|
||||||
Kesejahteraan — 37 kegiatan
|
|
||||||
Pemerintahan — 26 kegiatan
|
|
||||||
Keuangan — 17 kegiatan
|
|
||||||
Sekretaris Desa — 15 kegiatan
|
|
||||||
Tata Usaha TK — 14 kegiatan
|
|
||||||
Perangkat Kewilayahan — 12 kegiatan
|
|
||||||
Pelayanan — 10 kegiatan
|
|
||||||
Perencanaan — 9 kegiatan
|
|
||||||
Tata Usaha & Umum — 7 kegiatan
|
|
||||||
|
|
||||||
Setiap item:
|
|
||||||
|
|
||||||
* rounded
|
|
||||||
* hover effect
|
|
||||||
* arrow icon kanan
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Middle column:
|
|
||||||
|
|
||||||
Jumlah Dokumen
|
|
||||||
|
|
||||||
Gunakan **Bar Chart**.
|
|
||||||
|
|
||||||
Kategori:
|
|
||||||
|
|
||||||
* Gambar
|
|
||||||
* Dokumen
|
|
||||||
|
|
||||||
Nilai:
|
|
||||||
|
|
||||||
* Gambar: 300
|
|
||||||
* Dokumen: 310
|
|
||||||
|
|
||||||
Gunakan:
|
|
||||||
Recharts atau Mantine Charts.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Right column:
|
|
||||||
|
|
||||||
Progres Kegiatan
|
|
||||||
|
|
||||||
Gunakan **Pie Chart**.
|
|
||||||
|
|
||||||
Data:
|
|
||||||
|
|
||||||
Selesai — 83.33%
|
|
||||||
Dikerjakan — 16.67%
|
|
||||||
Segera Dikerjakan — 0%
|
|
||||||
Dibatalkan — 0%
|
|
||||||
|
|
||||||
Legend harus berwarna.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
SECTION 3 — DISCUSSION PANEL
|
|
||||||
|
|
||||||
Judul: Diskusi
|
|
||||||
|
|
||||||
Tampilkan list diskusi internal staf.
|
|
||||||
|
|
||||||
Item card memiliki:
|
|
||||||
|
|
||||||
* icon chat
|
|
||||||
* judul pesan
|
|
||||||
* nama pengirim
|
|
||||||
* tanggal
|
|
||||||
|
|
||||||
Contoh data:
|
|
||||||
|
|
||||||
"Kepada Pelayanan, mohon di cek..."
|
|
||||||
Pengirim: I.B Surya Prabhawa Manu
|
|
||||||
Tanggal: 12 Apr 2025
|
|
||||||
|
|
||||||
"Kepada staf perencanaan @suar..."
|
|
||||||
Pengirim: Ni Nyoman Yuliani
|
|
||||||
Tanggal: 14 Jun 2025
|
|
||||||
|
|
||||||
"ijin atau mohon kepada KBD sar..."
|
|
||||||
Pengirim: Ni Wayan Martini
|
|
||||||
Tanggal: 12 Apr 2025
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
SECTION 4 — ACARA HARI INI
|
|
||||||
|
|
||||||
Card sederhana.
|
|
||||||
|
|
||||||
Jika tidak ada acara tampilkan:
|
|
||||||
|
|
||||||
"Tidak ada acara hari ini"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
SECTION 5 — ARSIP DIGITAL PERANGKAT DESA
|
|
||||||
|
|
||||||
Grid 2 column.
|
|
||||||
|
|
||||||
Menu arsip:
|
|
||||||
|
|
||||||
Surat Keputusan
|
|
||||||
Dokumentasi
|
|
||||||
Laporan Keuangan
|
|
||||||
Notulensi Rapat
|
|
||||||
|
|
||||||
Setiap item berupa card clickable dengan:
|
|
||||||
|
|
||||||
* icon dokumen
|
|
||||||
* border
|
|
||||||
* hover effect
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
DESIGN STYLE
|
|
||||||
|
|
||||||
Gunakan gaya:
|
|
||||||
|
|
||||||
Modern Government Dashboard
|
|
||||||
Clean UI
|
|
||||||
Soft shadow
|
|
||||||
Rounded-xl
|
|
||||||
Spacing besar
|
|
||||||
Minimalistic
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
RESPONSIVE RULES
|
|
||||||
|
|
||||||
Desktop:
|
|
||||||
12 column grid
|
|
||||||
|
|
||||||
Tablet:
|
|
||||||
6 column grid
|
|
||||||
|
|
||||||
Mobile:
|
|
||||||
single column stack
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
COMPONENT STRUCTURE
|
|
||||||
|
|
||||||
src/components/dashboard
|
|
||||||
|
|
||||||
activity-card.tsx
|
|
||||||
division-list.tsx
|
|
||||||
document-chart.tsx
|
|
||||||
progress-chart.tsx
|
|
||||||
discussion-panel.tsx
|
|
||||||
event-card.tsx
|
|
||||||
archive-card.tsx
|
|
||||||
|
|
||||||
src/pages
|
|
||||||
|
|
||||||
dashboard.tsx
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
CODE QUALITY
|
|
||||||
|
|
||||||
Gunakan:
|
|
||||||
|
|
||||||
* React hooks
|
|
||||||
* reusable components
|
|
||||||
* Mantine components jika perlu
|
|
||||||
* Tailwind utility classes
|
|
||||||
* dark mode support
|
|
||||||
* responsive layout
|
|
||||||
* clean TypeScript
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
* Halaman dashboard lengkap
|
|
||||||
* Semua komponen reusable
|
|
||||||
* Chart sudah bekerja
|
|
||||||
* Layout identik dengan desain dashboard modern pemerintahan
|
|
||||||
BIN
public/light-mode.png
Normal file
BIN
public/light-mode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
BIN
public/white.png
Normal file
BIN
public/white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
@@ -1,123 +1,79 @@
|
|||||||
import { BarChart } from "@mantine/charts";
|
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Box,
|
Box,
|
||||||
Button,
|
|
||||||
Card,
|
Card,
|
||||||
Grid,
|
Grid,
|
||||||
|
GridCol,
|
||||||
Group,
|
Group,
|
||||||
Progress,
|
Progress,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
|
ThemeIcon,
|
||||||
Title,
|
Title,
|
||||||
useMantineColorScheme,
|
useMantineColorScheme,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import React from "react";
|
import {
|
||||||
|
MessageCircle,
|
||||||
|
CheckCircle,
|
||||||
|
AlertTriangle,
|
||||||
|
Clock,
|
||||||
|
TrendingUp,
|
||||||
|
} from "lucide-react";
|
||||||
|
import {
|
||||||
|
Bar,
|
||||||
|
BarChart,
|
||||||
|
CartesianGrid,
|
||||||
|
ResponsiveContainer,
|
||||||
|
Tooltip,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
} from "recharts";
|
||||||
|
|
||||||
// Sample Data
|
// KPI Data
|
||||||
const kpiData = [
|
const kpiData = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
title: "Interaksi Hari Ini",
|
title: "Interaksi Hari Ini",
|
||||||
value: "61",
|
value: "61",
|
||||||
delta: "+15% dari kemarin",
|
subtitle: "+15% dari kemarin",
|
||||||
deltaType: "positive",
|
trend: "positive",
|
||||||
icon: (
|
icon: MessageCircle,
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth={1.5}
|
|
||||||
stroke="currentColor"
|
|
||||||
className="h-6 w-6 text-muted-foreground"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M8.625 12a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H8.25m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H12m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H16.5m-13.5 3h15a2.25 2.25 0 0 0 2.25-2.25V6.75A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25v10.5A2.25 2.25 0 0 0 4.5 19.5Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
title: "Jawaban Otomatis",
|
title: "Jawaban Otomatis",
|
||||||
value: "87%",
|
value: "87%",
|
||||||
sub: "53 dari 61 interaksi",
|
subtitle: "53 dari 61 interaksi",
|
||||||
icon: (
|
icon: CheckCircle,
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth={1.5}
|
|
||||||
stroke="currentColor"
|
|
||||||
className="h-6 w-6 text-muted-foreground"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M9 12.75 11.25 15 15 9.75M21 12c0 1.268-.63 2.473-1.688 3.342-.48.485-.926.97-1.378 1.44c-1.472 1.58-2.306 2.787-2.91 3.514-.15.18-.207.33-.207.33A.75.75 0 0 1 15 21h-3c-1.104 0-2.08-.542-2.657-1.455-.139-.201-.264-.406-.38-.614l-.014-.025C8.85 18.067 8.156 17.2 7.5 16.325.728 12.56.728 7.44 7.5 3.675c3.04-.482 5.584.47 7.042 1.956.674.672 1.228 1.462 1.696 2.307.426.786.793 1.582 1.113 2.392h.001Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
title: "Belum Ditindak",
|
title: "Belum Ditindak",
|
||||||
value: "8",
|
value: "8",
|
||||||
sub: "Perlu respon manual",
|
subtitle: "Perlu respon manual",
|
||||||
deltaType: "negative",
|
icon: AlertTriangle,
|
||||||
icon: (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth={1.5}
|
|
||||||
stroke="currentColor"
|
|
||||||
className="h-6 w-6 text-muted-foreground"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
title: "Waktu Respon",
|
title: "Waktu Respon",
|
||||||
value: "2.3 sec",
|
value: "2.3 sec",
|
||||||
sub: "Rata-rata",
|
subtitle: "Rata-rata",
|
||||||
icon: (
|
icon: Clock,
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth={1.5}
|
|
||||||
stroke="currentColor"
|
|
||||||
className="h-6 w-6 text-muted-foreground"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Chart Data
|
||||||
const chartData = [
|
const chartData = [
|
||||||
{ day: "Sen", total: 100 },
|
{ day: "Sen", total: 45 },
|
||||||
{ day: "Sel", total: 120 },
|
{ day: "Sel", total: 62 },
|
||||||
{ day: "Rab", total: 90 },
|
{ day: "Rab", total: 38 },
|
||||||
{ day: "Kam", total: 150 },
|
{ day: "Kam", total: 75 },
|
||||||
{ day: "Jum", total: 110 },
|
{ day: "Jum", total: 58 },
|
||||||
{ day: "Sab", total: 80 },
|
{ day: "Sab", total: 32 },
|
||||||
{ day: "Min", total: 130 },
|
{ day: "Min", total: 51 },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Top Topics Data
|
||||||
const topTopics = [
|
const topTopics = [
|
||||||
{ topic: "Cara mengurus KTP", count: 89 },
|
{ topic: "Cara mengurus KTP", count: 89 },
|
||||||
{ topic: "Syarat Kartu Keluarga", count: 76 },
|
{ topic: "Syarat Kartu Keluarga", count: 76 },
|
||||||
@@ -126,6 +82,7 @@ const topTopics = [
|
|||||||
{ topic: "Info program bansos", count: 48 },
|
{ topic: "Info program bansos", count: 48 },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Busy Hours Data
|
||||||
const busyHours = [
|
const busyHours = [
|
||||||
{ period: "Pagi (08–12)", percentage: 30 },
|
{ period: "Pagi (08–12)", percentage: 30 },
|
||||||
{ period: "Siang (12–16)", percentage: 40 },
|
{ period: "Siang (12–16)", percentage: 40 },
|
||||||
@@ -138,146 +95,206 @@ const JennaAnalytic = () => {
|
|||||||
const dark = colorScheme === "dark";
|
const dark = colorScheme === "dark";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className="space-y-6">
|
<Stack gap="lg">
|
||||||
<Stack gap="xl">
|
{/* TOP SECTION - 4 STAT CARDS */}
|
||||||
{/* KPI Cards */}
|
<Grid gutter="md">
|
||||||
<Grid gutter="lg">
|
{kpiData.map((item) => (
|
||||||
{kpiData.map((kpi) => (
|
<Grid.Col key={item.id} span={{ base: 12, sm: 6, lg: 3 }}>
|
||||||
<Grid.Col key={kpi.id} span={{ base: 12, md: 6, lg: 3 }}>
|
|
||||||
<Card
|
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#141D34" : "white"}
|
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
|
||||||
>
|
|
||||||
<Group justify="space-between" align="flex-start" mb="xs">
|
|
||||||
<Text size="sm" fw={500} c="dimmed">
|
|
||||||
{kpi.title}
|
|
||||||
</Text>
|
|
||||||
{React.cloneElement(kpi.icon, {
|
|
||||||
className: "h-6 w-6", // Keeping classes for now, can be replaced by Mantine Icon component if available or styled with sx prop
|
|
||||||
color: "var(--mantine-color-dimmed)", // Set color via prop
|
|
||||||
})}
|
|
||||||
</Group>
|
|
||||||
<Title order={3} fw={700} mt="xs">
|
|
||||||
{kpi.value}
|
|
||||||
</Title>
|
|
||||||
{kpi.delta && (
|
|
||||||
<Text
|
|
||||||
size="xs"
|
|
||||||
c={
|
|
||||||
kpi.deltaType === "positive"
|
|
||||||
? "green"
|
|
||||||
: kpi.deltaType === "negative"
|
|
||||||
? "red"
|
|
||||||
: "dimmed"
|
|
||||||
}
|
|
||||||
mt={4}
|
|
||||||
>
|
|
||||||
{kpi.delta}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{kpi.sub && (
|
|
||||||
<Text size="xs" c="dimmed" mt={2}>
|
|
||||||
{kpi.sub}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</Grid.Col>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Card
|
|
||||||
p="md"
|
|
||||||
radius="md"
|
|
||||||
withBorder
|
|
||||||
bg={dark ? "#141D34" : "white"}
|
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
|
||||||
>
|
|
||||||
<Title order={3} fw={500} mb="md">
|
|
||||||
Interaksi Chatbot
|
|
||||||
</Title>
|
|
||||||
<BarChart
|
|
||||||
h={300}
|
|
||||||
data={chartData}
|
|
||||||
dataKey="day"
|
|
||||||
series={[{ name: "total", color: "blue" }]}
|
|
||||||
withLegend
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Charts and Lists Section */}
|
|
||||||
<Grid gutter="lg">
|
|
||||||
{/* Grafik Interaksi Chatbot (now Bar Chart) */}
|
|
||||||
<Grid.Col span={{ base: 12, lg: 6 }}>
|
|
||||||
<Card
|
<Card
|
||||||
p="md"
|
p="md"
|
||||||
radius="md"
|
radius="xl"
|
||||||
withBorder
|
withBorder
|
||||||
bg={dark ? "#141D34" : "white"}
|
bg={dark ? "#1E293B" : "white"}
|
||||||
style={{ borderColor: dark ? "#141D34" : "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%"
|
h="100%"
|
||||||
>
|
>
|
||||||
<Title order={3} fw={500} mb="md">
|
<Group justify="space-between" align="flex-start" w="100%">
|
||||||
Jam Tersibuk
|
<Stack gap={2}>
|
||||||
</Title>
|
<Text size="sm" c="dimmed">
|
||||||
<Stack gap="sm">
|
{item.title}
|
||||||
{busyHours.map((item, index) => (
|
</Text>
|
||||||
<Box key={index}>
|
<Text size="xl" fw={700} c={dark ? "white" : "gray.9"}>
|
||||||
<Text size="sm">{item.period}</Text>
|
{item.value}
|
||||||
<Group align="center">
|
</Text>
|
||||||
<Progress value={item.percentage} flex={1} />
|
<Group gap={4} align="flex-start">
|
||||||
<Text size="sm" fw={500}>
|
{item.trend === "positive" && (
|
||||||
{item.percentage}%
|
<TrendingUp size={14} color="#22C55E" />
|
||||||
</Text>
|
)}
|
||||||
</Group>
|
<Text
|
||||||
</Box>
|
size="xs"
|
||||||
))}
|
c={
|
||||||
</Stack>
|
item.trend === "positive"
|
||||||
|
? "green"
|
||||||
|
: dark
|
||||||
|
? "gray.4"
|
||||||
|
: "gray.5"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{item.subtitle}
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
<ThemeIcon
|
||||||
|
color="#1E3A5F"
|
||||||
|
variant="filled"
|
||||||
|
size="lg"
|
||||||
|
radius="xl"
|
||||||
|
>
|
||||||
|
<item.icon style={{ width: "60%", height: "60%" }} />
|
||||||
|
</ThemeIcon>
|
||||||
|
</Group>
|
||||||
</Card>
|
</Card>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
{/* Topik Pertanyaan Terbanyak & Jam Tersibuk */}
|
{/* MAIN CHART - INTERAKSI CHATBOT */}
|
||||||
<Grid.Col span={{ base: 12, lg: 6 }}>
|
<Card
|
||||||
<Stack gap="lg">
|
p="md"
|
||||||
{/* Topik Pertanyaan Terbanyak */}
|
radius="xl"
|
||||||
<Card
|
withBorder
|
||||||
p="md"
|
bg={dark ? "#1E293B" : "white"}
|
||||||
radius="md"
|
style={{
|
||||||
withBorder
|
borderColor: dark ? "#334155" : "white",
|
||||||
bg={dark ? "#141D34" : "white"}
|
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
||||||
style={{ borderColor: dark ? "#141D34" : "white" }}
|
}}
|
||||||
h="100%"
|
>
|
||||||
>
|
<Group justify="space-between" mb="md">
|
||||||
<Title order={3} fw={500} mb="md">
|
<Title order={4} c={dark ? "white" : "gray.9"}>
|
||||||
Topik Pertanyaan Terbanyak
|
Interaksi Chatbot
|
||||||
</Title>
|
</Title>
|
||||||
<Stack gap="xs">
|
</Group>
|
||||||
{topTopics.map((item, index) => (
|
<ResponsiveContainer width="100%" height={300}>
|
||||||
<Group
|
<BarChart data={chartData}>
|
||||||
key={index}
|
<CartesianGrid
|
||||||
justify="space-between"
|
strokeDasharray="3 3"
|
||||||
align="center"
|
vertical={false}
|
||||||
p="xs"
|
stroke={dark ? "#334155" : "#e5e7eb"}
|
||||||
|
/>
|
||||||
|
<XAxis
|
||||||
|
dataKey="day"
|
||||||
|
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" }}
|
||||||
|
cursor={{ fill: dark ? "#334155" : "#f3f4f6" }}
|
||||||
|
/>
|
||||||
|
<Bar
|
||||||
|
dataKey="total"
|
||||||
|
fill="#1E3A5F"
|
||||||
|
radius={[8, 8, 0, 0]}
|
||||||
|
maxBarSize={60}
|
||||||
|
/>
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* BOTTOM SECTION - 2 COLUMNS */}
|
||||||
|
<Grid gutter="lg">
|
||||||
|
{/* LEFT: TOPIK PERTANYAAN TERBANYAK */}
|
||||||
|
<Grid.Col span={{ base: 12, lg: 6 }}>
|
||||||
|
<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">
|
||||||
|
Topik Pertanyaan Terbanyak
|
||||||
|
</Title>
|
||||||
|
<Stack gap="xs">
|
||||||
|
{topTopics.map((item, index) => (
|
||||||
|
<Box
|
||||||
|
key={index}
|
||||||
|
p="sm"
|
||||||
|
bg={dark ? "#334155" : "#F1F5F9"}
|
||||||
|
style={{
|
||||||
|
transition: "background-color 0.15s ease",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Group justify="space-between">
|
||||||
|
<Text size="sm" fw={500} c={dark ? "white" : "gray.9"}>
|
||||||
|
{item.topic}
|
||||||
|
</Text>
|
||||||
|
<Badge
|
||||||
|
variant="light"
|
||||||
|
color="darmasaba-blue"
|
||||||
|
radius="sm"
|
||||||
|
fw={600}
|
||||||
>
|
>
|
||||||
<Text size="sm" fw={500}>
|
{item.count}x
|
||||||
{item.topic}
|
</Badge>
|
||||||
</Text>
|
</Group>
|
||||||
<Badge variant="light" color="gray">
|
</Box>
|
||||||
{item.count}x
|
))}
|
||||||
</Badge>
|
|
||||||
</Group>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Jam Tersibuk */}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid.Col>
|
</Card>
|
||||||
</Grid>
|
</Grid.Col>
|
||||||
</Stack>
|
|
||||||
</Box>
|
{/* RIGHT: JAM TERSIBUK */}
|
||||||
|
<Grid.Col span={{ base: 12, lg: 6 }}>
|
||||||
|
<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">
|
||||||
|
Jam Tersibuk
|
||||||
|
</Title>
|
||||||
|
<Stack gap="md">
|
||||||
|
{busyHours.map((item, index) => (
|
||||||
|
<Box key={index}>
|
||||||
|
<Group justify="space-between" mb={5}>
|
||||||
|
<Text size="sm" fw={500} c={dark ? "white" : "gray.9"}>
|
||||||
|
{item.period}
|
||||||
|
</Text>
|
||||||
|
<Text size="sm" fw={600} c={dark ? "white" : "gray.9"}>
|
||||||
|
{item.percentage}%
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
<Progress
|
||||||
|
value={item.percentage}
|
||||||
|
size="lg"
|
||||||
|
radius="xl"
|
||||||
|
color="#1E3A5F"
|
||||||
|
animated
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default JennaAnalytic;
|
export default JennaAnalytic;
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ export function Sidebar({ className }: SidebarProps) {
|
|||||||
return (
|
return (
|
||||||
<Box className={className}>
|
<Box className={className}>
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<Image src="/logo-desa-plus.png" alt="Logo" />
|
<Image
|
||||||
|
src={dark ? "/white.png" : "/light-mode.png"}
|
||||||
|
alt="Logo"
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Search */}
|
{/* Search */}
|
||||||
<Box p="md">
|
<Box p="md">
|
||||||
|
|||||||
@@ -1,9 +1,51 @@
|
|||||||
|
import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core";
|
||||||
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
import { Header } from "@/components/header";
|
||||||
|
import JennaAnalytic from "@/components/jenna-analytic";
|
||||||
|
import { Sidebar } from "@/components/sidebar";
|
||||||
|
|
||||||
export const Route = createFileRoute("/jenna-analytic")({
|
export const Route = createFileRoute("/jenna-analytic")({
|
||||||
component: RouteComponent,
|
component: JennaAnalyticPage,
|
||||||
});
|
});
|
||||||
|
|
||||||
function RouteComponent() {
|
function JennaAnalyticPage() {
|
||||||
return <div>Hello "/jenna-analytic"!</div>;
|
const [opened, { toggle }] = useDisclosure();
|
||||||
|
const { colorScheme } = useMantineColorScheme();
|
||||||
|
const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E";
|
||||||
|
const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white";
|
||||||
|
const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppShell
|
||||||
|
header={{ height: 60 }}
|
||||||
|
navbar={{
|
||||||
|
width: 300,
|
||||||
|
breakpoint: "sm",
|
||||||
|
collapsed: { mobile: !opened },
|
||||||
|
}}
|
||||||
|
padding="md"
|
||||||
|
>
|
||||||
|
<AppShell.Header bg={headerBgColor}>
|
||||||
|
<Group h="100%" px="md">
|
||||||
|
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
|
||||||
|
<Header />
|
||||||
|
</Group>
|
||||||
|
</AppShell.Header>
|
||||||
|
|
||||||
|
<AppShell.Navbar
|
||||||
|
p="md"
|
||||||
|
bg={navbarBgColor}
|
||||||
|
style={{ display: "flex", flexDirection: "column" }}
|
||||||
|
>
|
||||||
|
<div style={{ flex: 1, overflowY: "auto" }}>
|
||||||
|
<Sidebar />
|
||||||
|
</div>
|
||||||
|
</AppShell.Navbar>
|
||||||
|
|
||||||
|
<AppShell.Main bg={mainBgColor}>
|
||||||
|
<JennaAnalytic />
|
||||||
|
</AppShell.Main>
|
||||||
|
</AppShell>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user