feat: finalize kinerja divisi feature implementation
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
282
Dashboard-MD/JENNA_ANALYTHIC.md
Normal file
282
Dashboard-MD/JENNA_ANALYTHIC.md
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
# Jenna Analytic – Dashboard Design Specification
|
||||||
|
|
||||||
|
Dokumen ini menjelaskan desain halaman **Jenna Analytic** berdasarkan screenshot (11 Feb 2026). Dokumen ini menjadi acuan implementasi UI/UX, data, dan interaksi untuk halaman analitik chatbot desa.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Tujuan Halaman
|
||||||
|
|
||||||
|
Jenna Analytic berfungsi sebagai **dashboard analitik chatbot layanan desa**, berfokus pada:
|
||||||
|
|
||||||
|
* Volume interaksi warga
|
||||||
|
* Performa jawaban otomatis
|
||||||
|
* Respons manual & waktu respons
|
||||||
|
* Pola pertanyaan dan jam sibuk
|
||||||
|
|
||||||
|
Target user utama:
|
||||||
|
|
||||||
|
* Kepala Desa
|
||||||
|
* Admin pelayanan
|
||||||
|
* Operator chatbot
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Tata Letak Keseluruhan (Layout)
|
||||||
|
|
||||||
|
### 2.1 Struktur Global
|
||||||
|
|
||||||
|
```
|
||||||
|
+------------------------------------------------------+
|
||||||
|
| Topbar / Header |
|
||||||
|
+-------------+----------------------------------------+
|
||||||
|
| Sidebar | Main Content |
|
||||||
|
| | - KPI Cards (Row) |
|
||||||
|
| | - Bar Chart Interaksi |
|
||||||
|
| | - Topik Terbanyak + Jam Tersibuk |
|
||||||
|
+-------------+----------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
* Sidebar: fixed kiri
|
||||||
|
* Header: fixed atas
|
||||||
|
* Main content: scroll vertical
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Header (Topbar)
|
||||||
|
|
||||||
|
### Komponen
|
||||||
|
|
||||||
|
* Judul: `Desa Darmasaba`
|
||||||
|
* User Info:
|
||||||
|
|
||||||
|
* Nama: `I. B. Surya Prabhawa M.`
|
||||||
|
* Role: `Kepala Desa`
|
||||||
|
* Ikon:
|
||||||
|
|
||||||
|
* Notification (badge angka merah)
|
||||||
|
* Theme toggle / setting
|
||||||
|
* Avatar (lingkaran)
|
||||||
|
|
||||||
|
### Gaya
|
||||||
|
|
||||||
|
* Background: Navy / Biru Tua
|
||||||
|
* Text: Putih
|
||||||
|
* Tinggi: ±64px
|
||||||
|
* Shadow: subtle
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Sidebar Navigation
|
||||||
|
|
||||||
|
### Elemen
|
||||||
|
|
||||||
|
* Logo DESA+
|
||||||
|
* Search input: `cari apa saja`
|
||||||
|
* Menu:
|
||||||
|
|
||||||
|
* Beranda
|
||||||
|
* Kinerja Divisi
|
||||||
|
* Pengaduan & Layanan Publik
|
||||||
|
* **Jenna Analytic (active)**
|
||||||
|
* Demografi & Kependudukan
|
||||||
|
* Keuangan & Anggaran
|
||||||
|
* Bumdes & UMKM Desa
|
||||||
|
* Sosial
|
||||||
|
* Keamanan
|
||||||
|
* Bantuan
|
||||||
|
* Pengaturan
|
||||||
|
|
||||||
|
### Gaya
|
||||||
|
|
||||||
|
* Background: Putih
|
||||||
|
* Active state:
|
||||||
|
|
||||||
|
* Background biru muda
|
||||||
|
* Border kiri / highlight
|
||||||
|
* Spacing menu: 12–16px
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. KPI Cards (Ringkasan Atas)
|
||||||
|
|
||||||
|
### Daftar KPI
|
||||||
|
|
||||||
|
1. **Interaksi Hari Ini**
|
||||||
|
|
||||||
|
* Value: `61`
|
||||||
|
* Delta: `+15% dari kemarin`
|
||||||
|
|
||||||
|
2. **Jawaban Otomatis**
|
||||||
|
|
||||||
|
* Value: `87%`
|
||||||
|
* Sub: `53 dari 61 interaksi`
|
||||||
|
|
||||||
|
3. **Belum Ditindak**
|
||||||
|
|
||||||
|
* Value: `8`
|
||||||
|
* Sub: `Perlu respon manual`
|
||||||
|
|
||||||
|
4. **Waktu Respon**
|
||||||
|
|
||||||
|
* Value: `2.3 sec`
|
||||||
|
* Sub: `Rata-rata`
|
||||||
|
|
||||||
|
### Gaya
|
||||||
|
|
||||||
|
* Card putih
|
||||||
|
* Radius: 14–16px
|
||||||
|
* Icon di kanan
|
||||||
|
* Shadow lembut
|
||||||
|
* Grid 4 kolom (desktop)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Grafik Interaksi Chatbot
|
||||||
|
|
||||||
|
### Deskripsi
|
||||||
|
|
||||||
|
* Tipe: Bar Chart
|
||||||
|
* Judul: `Interaksi Chatbot`
|
||||||
|
* X-axis: Hari (Sen–Min)
|
||||||
|
* Y-axis: Jumlah interaksi
|
||||||
|
|
||||||
|
### Gaya
|
||||||
|
|
||||||
|
* Warna bar: Navy / Biru tua
|
||||||
|
* Grid minimal
|
||||||
|
* Tooltip saat hover
|
||||||
|
|
||||||
|
### Data Expectation
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
day: 'Sen' | 'Sel' | 'Rab' | 'Kam' | 'Jum' | 'Sab' | 'Min';
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Topik Pertanyaan Terbanyak
|
||||||
|
|
||||||
|
### Deskripsi
|
||||||
|
|
||||||
|
* Tipe: Ranked list
|
||||||
|
* Isi:
|
||||||
|
|
||||||
|
* Cara mengurus KTP – 89x
|
||||||
|
* Syarat Kartu Keluarga – 76x
|
||||||
|
* Jadwal Posyandu – 64x
|
||||||
|
* Pengaduan jalan rusak – 52x
|
||||||
|
* Info program bansos – 48x
|
||||||
|
|
||||||
|
### Gaya
|
||||||
|
|
||||||
|
* Card putih
|
||||||
|
* Item list rounded
|
||||||
|
* Count di kanan
|
||||||
|
|
||||||
|
### Data
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
topic: string;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Jam Tersibuk
|
||||||
|
|
||||||
|
### Deskripsi
|
||||||
|
|
||||||
|
* Menampilkan distribusi interaksi berdasarkan waktu
|
||||||
|
|
||||||
|
| Waktu | Persentase |
|
||||||
|
| ------------- | ---------- |
|
||||||
|
| Pagi (08–12) | 30% |
|
||||||
|
| Siang (12–16) | 40% |
|
||||||
|
| Sore (16–20) | 20% |
|
||||||
|
| Malam (20–08) | 10% |
|
||||||
|
|
||||||
|
### Gaya
|
||||||
|
|
||||||
|
* Horizontal bar / progress
|
||||||
|
* Label kiri, persentase kanan
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Warna & Tema
|
||||||
|
|
||||||
|
### Palette
|
||||||
|
|
||||||
|
* Primary (Navy): `#1E3A5F`
|
||||||
|
* Secondary: `#3B82F6`
|
||||||
|
* Success: `#22C55E`
|
||||||
|
* Warning: `#FACC15`
|
||||||
|
* Danger: `#EF4444`
|
||||||
|
* Background App: `#F5F8FB`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Tipografi
|
||||||
|
|
||||||
|
* Font: Inter / Poppins / system-ui
|
||||||
|
* Heading: Semi-bold
|
||||||
|
* Body: Regular
|
||||||
|
* KPI number: Bold, besar
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Spasi & Grid
|
||||||
|
|
||||||
|
* Padding card: 16–24px
|
||||||
|
* Gap grid: 20–24px
|
||||||
|
* Line-height body: 1.5
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Responsivitas
|
||||||
|
|
||||||
|
### Tablet
|
||||||
|
|
||||||
|
* KPI jadi 2 kolom
|
||||||
|
* Chart full width
|
||||||
|
|
||||||
|
### Mobile
|
||||||
|
|
||||||
|
* Sidebar jadi drawer
|
||||||
|
* KPI 1 kolom
|
||||||
|
* Chart & list stack vertical
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Interaksi & Perilaku
|
||||||
|
|
||||||
|
* Hover card: shadow meningkat
|
||||||
|
* Tooltip chart
|
||||||
|
* KPI clickable (future drill-down)
|
||||||
|
* Data async dari API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Catatan Implementasi Teknis
|
||||||
|
|
||||||
|
* Framework: React + Vite
|
||||||
|
* UI: Mantine / Shadcn / MUI
|
||||||
|
* Chart: Recharts / Chart.js
|
||||||
|
* State: TanStack Query / SWR
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Pengembangan Lanjutan
|
||||||
|
|
||||||
|
* Filter tanggal
|
||||||
|
* Export CSV
|
||||||
|
* Drill-down per topik
|
||||||
|
* Alert SLA respon
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> Dokumen ini bersifat **design & data contract** antara UI, frontend, dan backend.
|
||||||
112
QWEN.md
Normal file
112
QWEN.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# Darmasaba Dashboard Noc - Project Context
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
**Darmasaba Dashboard Noc** is a high-performance, full-stack React development template leveraging the **Bun** runtime. It features a unique "Single Port" architecture that combines a Bun/Elysia backend with a React frontend running on the same port (3000), eliminating CORS issues and proxy complexity.
|
||||||
|
|
||||||
|
### Key Technologies
|
||||||
|
- **Runtime**: Bun (Fast all-in-one JS runtime)
|
||||||
|
- **Backend**: ElysiaJS (Fast, type-safe web framework)
|
||||||
|
- **Frontend**: React 19 (UI Library)
|
||||||
|
- **Routing**: TanStack React Router (Type-safe routing)
|
||||||
|
- **UI Framework**: Mantine UI (Component library)
|
||||||
|
- **Authentication**: Better Auth (Complete auth solution)
|
||||||
|
- **Database**: Prisma ORM (Database toolkit)
|
||||||
|
- **Testing**: Bun Test & Playwright
|
||||||
|
|
||||||
|
### Architecture Highlights
|
||||||
|
- **Single Port Architecture**: Backend (Elysia) and Frontend (Vite Middleware) run on the same port (3000)
|
||||||
|
- **Contract-First API**: Strictly typed API using OpenAPI with automatic frontend type synchronization
|
||||||
|
- **PWA & TWA Support**: Ready for mobile with Service Workers, Web Manifest, and Android Trusted Web Activity verification
|
||||||
|
- **React Dev Inspector**: Alt/Option + Click to jump directly to source code in VS Code
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
├── __tests__/ # Consolidated test suite (API & E2E)
|
||||||
|
├── generated/ # Auto-generated API types and Prisma client
|
||||||
|
├── prisma/ # Database schema and migrations
|
||||||
|
├── scripts/ # Internal automation scripts
|
||||||
|
└── src/
|
||||||
|
├── api/ # Elysia backend route modules
|
||||||
|
├── middleware/ # Backend & Frontend middlewares
|
||||||
|
├── routes/ # TanStack file-based frontend routes
|
||||||
|
├── store/ # Global state (Valtio)
|
||||||
|
├── utils/ # Shared utilities (DB, Env, API Client)
|
||||||
|
├── frontend.tsx # React client entry point
|
||||||
|
└── index.ts # Unified server entry point
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building and Running
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
Install [Bun](https://bun.sh/) if you haven't already.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setup Environment
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# Fill in your DATABASE_URL and BETTER_AUTH_SECRET
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Initialization
|
||||||
|
```bash
|
||||||
|
bun x prisma migrate dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Start Development
|
||||||
|
```bash
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
- **App**: `http://localhost:3000`
|
||||||
|
- **API Docs**: `http://localhost:3000/api/docs` (Swagger)
|
||||||
|
|
||||||
|
## Testing Commands
|
||||||
|
|
||||||
|
- **Unit/Integration (API)**: `bun run test`
|
||||||
|
- **End-to-End (Browser)**: `bun run test:e2e`
|
||||||
|
- **Visual Dashboard**: `bun run test:ui`
|
||||||
|
|
||||||
|
## Development Guidelines
|
||||||
|
|
||||||
|
- **API Workflow**:
|
||||||
|
1. Define schema in `src/api/*.ts`.
|
||||||
|
2. Run `bun run gen:api` (or just start `dev` mode).
|
||||||
|
3. Use `apiClient` in the frontend with full type safety.
|
||||||
|
- **Styling**: Prefer Mantine components and Style Props.
|
||||||
|
- **Code Quality**: Code is automatically formatted on save if you have the Biome extension. Manual: `bun run check`.
|
||||||
|
|
||||||
|
## Key Configuration Files
|
||||||
|
|
||||||
|
- **biome.json**: Code formatting and linting rules (uses tabs, double quotes)
|
||||||
|
- **tailwind.config.js**: Tailwind CSS configuration with custom Darmasaba color palette
|
||||||
|
- **tsconfig.json**: TypeScript configuration with path aliases (`@/*` maps to `./src/*`)
|
||||||
|
- **package.json**: Contains all scripts and dependencies
|
||||||
|
- **playwright.config.ts**: End-to-end testing configuration
|
||||||
|
|
||||||
|
## Notable Features
|
||||||
|
|
||||||
|
1. **Hot Module Replacement**: The application supports HMR for rapid development
|
||||||
|
2. **Type Safety**: Full type safety between frontend and backend through contract-first API design
|
||||||
|
3. **Authentication**: Built-in authentication using Better Auth
|
||||||
|
4. **Dark/Light Theme**: Automatic theme switching with Mantine UI
|
||||||
|
5. **Responsive Design**: Mobile-first responsive design using Tailwind CSS and Mantine
|
||||||
|
6. **Performance Optimized**: Optimized for production with proper bundling and minification
|
||||||
|
|
||||||
|
## Development Scripts
|
||||||
|
|
||||||
|
- `dev`: Starts the development server with HMR
|
||||||
|
- `lint`: Runs Biome linter
|
||||||
|
- `check`: Runs Biome checker with auto-fix
|
||||||
|
- `format`: Formats code using Biome
|
||||||
|
- `gen:api`: Generates API types from schema
|
||||||
|
- `test`: Runs unit/integration tests
|
||||||
|
- `test:ui`: Runs tests with UI
|
||||||
|
- `test:e2e`: Runs end-to-end tests
|
||||||
|
- `build`: Builds the application for production
|
||||||
|
- `start`: Starts the production server
|
||||||
|
- `seed`: Seeds the database with initial data
|
||||||
@@ -164,9 +164,6 @@ export function DashboardContent() {
|
|||||||
<ThemeIcon variant="filled" size="xl" radius="xl" color={dark ? 'gray' : 'darmasaba-blue'}>
|
<ThemeIcon variant="filled" size="xl" radius="xl" color={dark ? 'gray' : 'darmasaba-blue'}>
|
||||||
<Users style={{ width: "70%", height: "70%" }} />
|
<Users style={{ width: "70%", height: "70%" }} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
<Badge variant="light" radius="xl" size="lg" color="gray" style={{ position: 'absolute', top: 10, right: 10 }}>
|
|
||||||
87%
|
|
||||||
</Badge>
|
|
||||||
</Group>
|
</Group>
|
||||||
</Card>
|
</Card>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
271
src/components/jenna-analytic.tsx
Normal file
271
src/components/jenna-analytic.tsx
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Badge,
|
||||||
|
Progress,
|
||||||
|
Title,
|
||||||
|
Text,
|
||||||
|
Group,
|
||||||
|
Stack,
|
||||||
|
Grid,
|
||||||
|
Table,
|
||||||
|
Box,
|
||||||
|
} from "@mantine/core";
|
||||||
|
|
||||||
|
// Sample Data
|
||||||
|
const kpiData = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "Interaksi Hari Ini",
|
||||||
|
value: "61",
|
||||||
|
delta: "+15% dari kemarin",
|
||||||
|
deltaType: "positive",
|
||||||
|
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="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,
|
||||||
|
title: "Jawaban Otomatis",
|
||||||
|
value: "87%",
|
||||||
|
sub: "53 dari 61 interaksi",
|
||||||
|
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="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,
|
||||||
|
title: "Belum Ditindak",
|
||||||
|
value: "8",
|
||||||
|
sub: "Perlu respon manual",
|
||||||
|
deltaType: "negative",
|
||||||
|
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,
|
||||||
|
title: "Waktu Respon",
|
||||||
|
value: "2.3 sec",
|
||||||
|
sub: "Rata-rata",
|
||||||
|
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 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const chartData = [
|
||||||
|
{ day: "Sen", total: 100 },
|
||||||
|
{ day: "Sel", total: 120 },
|
||||||
|
{ day: "Rab", total: 90 },
|
||||||
|
{ day: "Kam", total: 150 },
|
||||||
|
{ day: "Jum", total: 110 },
|
||||||
|
{ day: "Sab", total: 80 },
|
||||||
|
{ day: "Min", total: 130 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const topTopics = [
|
||||||
|
{ topic: "Cara mengurus KTP", count: 89 },
|
||||||
|
{ topic: "Syarat Kartu Keluarga", count: 76 },
|
||||||
|
{ topic: "Jadwal Posyandu", count: 64 },
|
||||||
|
{ topic: "Pengaduan jalan rusak", count: 52 },
|
||||||
|
{ topic: "Info program bansos", count: 48 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const busyHours = [
|
||||||
|
{ period: "Pagi (08–12)", percentage: 30 },
|
||||||
|
{ period: "Siang (12–16)", percentage: 40 },
|
||||||
|
{ period: "Sore (16–20)", percentage: 20 },
|
||||||
|
{ period: "Malam (20–08)", percentage: 10 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const JennaAnalytic = () => {
|
||||||
|
return (
|
||||||
|
<Box p="md">
|
||||||
|
<Stack gap="xl">
|
||||||
|
<Group justify="space-between" align="center">
|
||||||
|
<Title order={1} fw={700}>
|
||||||
|
Jenna Analytic
|
||||||
|
</Title>
|
||||||
|
<Button variant="filled">Export Data</Button>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{/* KPI Cards */}
|
||||||
|
<Grid gutter="lg">
|
||||||
|
{kpiData.map((kpi) => (
|
||||||
|
<Grid.Col key={kpi.id} span={{ base: 12, md: 6, lg: 3 }}>
|
||||||
|
<Card shadow="sm" padding="lg" radius="md" withBorder>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
{/* Charts and Lists Section */}
|
||||||
|
<Grid gutter="lg">
|
||||||
|
{/* Grafik Interaksi Chatbot (now Table) */}
|
||||||
|
<Grid.Col span={{ base: 12, lg: 6 }}>
|
||||||
|
<Card shadow="sm" padding="lg" radius="md" withBorder>
|
||||||
|
<Title order={3} fw={500} mb="md">
|
||||||
|
Interaksi Chatbot
|
||||||
|
</Title>
|
||||||
|
<Table striped highlightOnHover>
|
||||||
|
<Table.Thead>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th>Day</Table.Th>
|
||||||
|
<Table.Th>Total Interactions</Table.Th>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
<Table.Tbody>
|
||||||
|
{chartData.map((item, index) => (
|
||||||
|
<Table.Tr key={index}>
|
||||||
|
<Table.Td>{item.day}</Table.Td>
|
||||||
|
<Table.Td>{item.total}</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
|
</Grid.Col>
|
||||||
|
|
||||||
|
{/* Topik Pertanyaan Terbanyak & Jam Tersibuk */}
|
||||||
|
<Grid.Col span={{ base: 12, lg: 6 }}>
|
||||||
|
<Stack gap="lg">
|
||||||
|
{/* Topik Pertanyaan Terbanyak */}
|
||||||
|
<Card shadow="sm" padding="lg" radius="md" withBorder>
|
||||||
|
<Title order={3} fw={500} mb="md">
|
||||||
|
Topik Pertanyaan Terbanyak
|
||||||
|
</Title>
|
||||||
|
<Stack gap="xs">
|
||||||
|
{topTopics.map((item, index) => (
|
||||||
|
<Group
|
||||||
|
key={index}
|
||||||
|
justify="space-between"
|
||||||
|
align="center"
|
||||||
|
p="xs"
|
||||||
|
style={{ backgroundColor: 'var(--mantine-color-gray-0)', borderRadius: 'var(--mantine-radius-sm)' }}
|
||||||
|
>
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{item.topic}
|
||||||
|
</Text>
|
||||||
|
<Badge variant="light" color="gray">
|
||||||
|
{item.count}x
|
||||||
|
</Badge>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Jam Tersibuk */}
|
||||||
|
<Card shadow="sm" padding="lg" radius="md" withBorder>
|
||||||
|
<Title order={3} fw={500} mb="md">
|
||||||
|
Jam Tersibuk
|
||||||
|
</Title>
|
||||||
|
<Stack gap="sm">
|
||||||
|
{busyHours.map((item, index) => (
|
||||||
|
<Group key={index} align="center">
|
||||||
|
<Text w={80} size="sm">
|
||||||
|
{item.period}
|
||||||
|
</Text>
|
||||||
|
<Progress value={item.percentage} flex={1} />
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{item.percentage}%
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
</Stack>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
export default JennaAnalytic;
|
||||||
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
|
|
||||||
import { Badge } from "@/app/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/app/components/ui/button"; // Correct import for Button
|
import { Button } from "@/components/ui/button"; // Correct import for Button
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/app/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { Progress } from "@/app/components/ui/progress";
|
import { Progress } from "@/components/ui/progress";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/app/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
|
|
||||||
const KinerjaDivisi = () => {
|
const KinerjaDivisi = () => {
|
||||||
// Sample data for division performance
|
// Sample data for division performance
|
||||||
@@ -87,7 +87,7 @@ const KinerjaDivisi = () => {
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">Total Divisi</CardTitle>
|
<CardTitle className="text-sm font-medium dark:text-gray-100">Total Divisi</CardTitle>
|
||||||
<div className="h-6 w-6 text-muted-foreground">
|
<div className="h-6 w-6 text-muted-foreground">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -113,7 +113,7 @@ const KinerjaDivisi = () => {
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">
|
<CardTitle className="text-sm font-medium dark:text-gray-100">
|
||||||
Rata-rata Pencapaian
|
Rata-rata Pencapaian
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<div className="h-6 w-6 text-muted-foreground">
|
<div className="h-6 w-6 text-muted-foreground">
|
||||||
@@ -141,7 +141,7 @@ const KinerjaDivisi = () => {
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">
|
<CardTitle className="text-sm font-medium dark:text-gray-100">
|
||||||
Divisi Melebihi Target
|
Divisi Melebihi Target
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<div className="h-6 w-6 text-muted-foreground">
|
<div className="h-6 w-6 text-muted-foreground">
|
||||||
@@ -170,19 +170,19 @@ const KinerjaDivisi = () => {
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Detail Kinerja Divisi</CardTitle>
|
<CardTitle className="dark:text-gray-100">Detail Kinerja Divisi</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Nama Divisi</TableHead>
|
<TableHead className="dark:text-white">Nama Divisi</TableHead>
|
||||||
<TableHead>Target (%)</TableHead>
|
<TableHead className="dark:text-white">Target (%)</TableHead>
|
||||||
<TableHead>Pencapaian (%)</TableHead>
|
<TableHead className="dark:text-white">Pencapaian (%)</TableHead>
|
||||||
<TableHead>Status</TableHead>
|
<TableHead className="dark:text-white">Status</TableHead>
|
||||||
<TableHead>Proyek Aktif</TableHead>
|
<TableHead className="dark:text-white">Proyek Aktif</TableHead>
|
||||||
<TableHead>Anggaran</TableHead>
|
<TableHead className="dark:text-white">Anggaran</TableHead>
|
||||||
<TableHead>Terakhir Diperbarui</TableHead>
|
<TableHead className="dark:text-white">Terakhir Diperbarui</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
@@ -236,9 +236,8 @@ const KinerjaDivisi = () => {
|
|||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Grafik Pencapaian Divisi</CardTitle>
|
<CardTitle className="dark:text-gray-100">Grafik Pencapaian Divisi</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader> <CardContent>
|
||||||
<CardContent>
|
|
||||||
<div className="h-80 flex items-center justify-center bg-gray-50 dark:bg-gray-700 rounded-lg">
|
<div className="h-80 flex items-center justify-center bg-gray-50 dark:bg-gray-700 rounded-lg">
|
||||||
<p className="text-gray-500 dark:text-gray-300">
|
<p className="text-gray-500 dark:text-gray-300">
|
||||||
Grafik pencapaian akan ditampilkan di sini
|
Grafik pencapaian akan ditampilkan di sini
|
||||||
@@ -249,9 +248,8 @@ const KinerjaDivisi = () => {
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Distribusi Anggaran Divisi</CardTitle>
|
<CardTitle className="dark:text-gray-100">Distribusi Anggaran Divisi</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader> <CardContent>
|
||||||
<CardContent>
|
|
||||||
<div className="h-80 flex items-center justify-center bg-gray-50 dark:bg-gray-700 rounded-lg">
|
<div className="h-80 flex items-center justify-center bg-gray-50 dark:bg-gray-700 rounded-lg">
|
||||||
<p className="text-gray-500 dark:text-gray-300">
|
<p className="text-gray-500 dark:text-gray-300">
|
||||||
Diagram distribusi anggaran akan ditampilkan di sini
|
Diagram distribusi anggaran akan ditampilkan di sini
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Badge } from "@/app/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/app/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/app/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { Input } from "@/app/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Select } from "@/app/components/ui/select";
|
import { Select } from "@/components/ui/select";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@@ -17,8 +17,8 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/app/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { Textarea } from "@/app/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
|
||||||
const PengaduanLayananPublik = () => {
|
const PengaduanLayananPublik = () => {
|
||||||
const [activeTab, setActiveTab] = useState<"complaints" | "services">(
|
const [activeTab, setActiveTab] = useState<"complaints" | "services">(
|
||||||
@@ -23,7 +23,7 @@ export function Sidebar({ className }: SidebarProps) {
|
|||||||
{ name: "Beranda", path: "/dashboard" },
|
{ name: "Beranda", path: "/dashboard" },
|
||||||
{ name: "Kinerja Divisi", path: "/dashboard/kinerja-divisi" },
|
{ name: "Kinerja Divisi", path: "/dashboard/kinerja-divisi" },
|
||||||
{ name: "Pengaduan & Layanan Publik", path: "/dashboard/pengaduan-layanan-publik" },
|
{ name: "Pengaduan & Layanan Publik", path: "/dashboard/pengaduan-layanan-publik" },
|
||||||
{ name: "Jenna Analytic", path: "/dashboard/analytic" },
|
{ name: "Jenna Analytic", path: "/dashboard/jenna-analytic" },
|
||||||
{ name: "Demografi & Kependudukan", path: "/dashboard/demografi" },
|
{ name: "Demografi & Kependudukan", path: "/dashboard/demografi" },
|
||||||
{ name: "Keuangan & Anggaran", path: "/dashboard/keuangan" },
|
{ name: "Keuangan & Anggaran", path: "/dashboard/keuangan" },
|
||||||
{ name: "Bumdes & UMKM Desa", path: "/dashboard/bumdes" },
|
{ name: "Bumdes & UMKM Desa", path: "/dashboard/bumdes" },
|
||||||
@@ -22,6 +22,7 @@ import { Route as UsersIdRouteImport } from './routes/users/$id'
|
|||||||
import { Route as ProfileEditRouteImport } from './routes/profile/edit'
|
import { Route as ProfileEditRouteImport } from './routes/profile/edit'
|
||||||
import { Route as DashboardPengaduanLayananPublikRouteImport } from './routes/dashboard/pengaduan-layanan-publik'
|
import { Route as DashboardPengaduanLayananPublikRouteImport } from './routes/dashboard/pengaduan-layanan-publik'
|
||||||
import { Route as DashboardKinerjaDivisiRouteImport } from './routes/dashboard/kinerja-divisi'
|
import { Route as DashboardKinerjaDivisiRouteImport } from './routes/dashboard/kinerja-divisi'
|
||||||
|
import { Route as DashboardJennaAnalyticRouteImport } from './routes/dashboard/jenna-analytic'
|
||||||
import { Route as AdminUsersRouteImport } from './routes/admin/users'
|
import { Route as AdminUsersRouteImport } from './routes/admin/users'
|
||||||
import { Route as AdminSettingsRouteImport } from './routes/admin/settings'
|
import { Route as AdminSettingsRouteImport } from './routes/admin/settings'
|
||||||
import { Route as AdminApikeyRouteImport } from './routes/admin/apikey'
|
import { Route as AdminApikeyRouteImport } from './routes/admin/apikey'
|
||||||
@@ -92,6 +93,11 @@ const DashboardKinerjaDivisiRoute = DashboardKinerjaDivisiRouteImport.update({
|
|||||||
path: '/kinerja-divisi',
|
path: '/kinerja-divisi',
|
||||||
getParentRoute: () => DashboardRouteRoute,
|
getParentRoute: () => DashboardRouteRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const DashboardJennaAnalyticRoute = DashboardJennaAnalyticRouteImport.update({
|
||||||
|
id: '/jenna-analytic',
|
||||||
|
path: '/jenna-analytic',
|
||||||
|
getParentRoute: () => DashboardRouteRoute,
|
||||||
|
} as any)
|
||||||
const AdminUsersRoute = AdminUsersRouteImport.update({
|
const AdminUsersRoute = AdminUsersRouteImport.update({
|
||||||
id: '/users',
|
id: '/users',
|
||||||
path: '/users',
|
path: '/users',
|
||||||
@@ -117,6 +123,7 @@ export interface FileRoutesByFullPath {
|
|||||||
'/admin/apikey': typeof AdminApikeyRoute
|
'/admin/apikey': typeof AdminApikeyRoute
|
||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
|
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
||||||
'/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute
|
'/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute
|
||||||
'/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute
|
'/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute
|
||||||
'/profile/edit': typeof ProfileEditRoute
|
'/profile/edit': typeof ProfileEditRoute
|
||||||
@@ -133,6 +140,7 @@ export interface FileRoutesByTo {
|
|||||||
'/admin/apikey': typeof AdminApikeyRoute
|
'/admin/apikey': typeof AdminApikeyRoute
|
||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
|
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
||||||
'/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute
|
'/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute
|
||||||
'/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute
|
'/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute
|
||||||
'/profile/edit': typeof ProfileEditRoute
|
'/profile/edit': typeof ProfileEditRoute
|
||||||
@@ -152,6 +160,7 @@ export interface FileRoutesById {
|
|||||||
'/admin/apikey': typeof AdminApikeyRoute
|
'/admin/apikey': typeof AdminApikeyRoute
|
||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
|
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
||||||
'/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute
|
'/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute
|
||||||
'/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute
|
'/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute
|
||||||
'/profile/edit': typeof ProfileEditRoute
|
'/profile/edit': typeof ProfileEditRoute
|
||||||
@@ -172,6 +181,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/apikey'
|
| '/admin/apikey'
|
||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
|
| '/dashboard/jenna-analytic'
|
||||||
| '/dashboard/kinerja-divisi'
|
| '/dashboard/kinerja-divisi'
|
||||||
| '/dashboard/pengaduan-layanan-publik'
|
| '/dashboard/pengaduan-layanan-publik'
|
||||||
| '/profile/edit'
|
| '/profile/edit'
|
||||||
@@ -188,6 +198,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/apikey'
|
| '/admin/apikey'
|
||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
|
| '/dashboard/jenna-analytic'
|
||||||
| '/dashboard/kinerja-divisi'
|
| '/dashboard/kinerja-divisi'
|
||||||
| '/dashboard/pengaduan-layanan-publik'
|
| '/dashboard/pengaduan-layanan-publik'
|
||||||
| '/profile/edit'
|
| '/profile/edit'
|
||||||
@@ -206,6 +217,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/apikey'
|
| '/admin/apikey'
|
||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
|
| '/dashboard/jenna-analytic'
|
||||||
| '/dashboard/kinerja-divisi'
|
| '/dashboard/kinerja-divisi'
|
||||||
| '/dashboard/pengaduan-layanan-publik'
|
| '/dashboard/pengaduan-layanan-publik'
|
||||||
| '/profile/edit'
|
| '/profile/edit'
|
||||||
@@ -321,6 +333,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof DashboardKinerjaDivisiRouteImport
|
preLoaderRoute: typeof DashboardKinerjaDivisiRouteImport
|
||||||
parentRoute: typeof DashboardRouteRoute
|
parentRoute: typeof DashboardRouteRoute
|
||||||
}
|
}
|
||||||
|
'/dashboard/jenna-analytic': {
|
||||||
|
id: '/dashboard/jenna-analytic'
|
||||||
|
path: '/jenna-analytic'
|
||||||
|
fullPath: '/dashboard/jenna-analytic'
|
||||||
|
preLoaderRoute: typeof DashboardJennaAnalyticRouteImport
|
||||||
|
parentRoute: typeof DashboardRouteRoute
|
||||||
|
}
|
||||||
'/admin/users': {
|
'/admin/users': {
|
||||||
id: '/admin/users'
|
id: '/admin/users'
|
||||||
path: '/users'
|
path: '/users'
|
||||||
@@ -364,12 +383,14 @@ const AdminRouteRouteWithChildren = AdminRouteRoute._addFileChildren(
|
|||||||
)
|
)
|
||||||
|
|
||||||
interface DashboardRouteRouteChildren {
|
interface DashboardRouteRouteChildren {
|
||||||
|
DashboardJennaAnalyticRoute: typeof DashboardJennaAnalyticRoute
|
||||||
DashboardKinerjaDivisiRoute: typeof DashboardKinerjaDivisiRoute
|
DashboardKinerjaDivisiRoute: typeof DashboardKinerjaDivisiRoute
|
||||||
DashboardPengaduanLayananPublikRoute: typeof DashboardPengaduanLayananPublikRoute
|
DashboardPengaduanLayananPublikRoute: typeof DashboardPengaduanLayananPublikRoute
|
||||||
DashboardIndexRoute: typeof DashboardIndexRoute
|
DashboardIndexRoute: typeof DashboardIndexRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const DashboardRouteRouteChildren: DashboardRouteRouteChildren = {
|
const DashboardRouteRouteChildren: DashboardRouteRouteChildren = {
|
||||||
|
DashboardJennaAnalyticRoute: DashboardJennaAnalyticRoute,
|
||||||
DashboardKinerjaDivisiRoute: DashboardKinerjaDivisiRoute,
|
DashboardKinerjaDivisiRoute: DashboardKinerjaDivisiRoute,
|
||||||
DashboardPengaduanLayananPublikRoute: DashboardPengaduanLayananPublikRoute,
|
DashboardPengaduanLayananPublikRoute: DashboardPengaduanLayananPublikRoute,
|
||||||
DashboardIndexRoute: DashboardIndexRoute,
|
DashboardIndexRoute: DashboardIndexRoute,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
import { DashboardContent } from "../../app/components/dashboard-content";
|
import { DashboardContent } from "@/components/dashboard-content";
|
||||||
export const Route = createFileRoute("/dashboard/")({
|
export const Route = createFileRoute("/dashboard/")({
|
||||||
component: DashboardContent,
|
component: DashboardContent,
|
||||||
});
|
});
|
||||||
|
|||||||
6
src/routes/dashboard/jenna-analytic.ts
Normal file
6
src/routes/dashboard/jenna-analytic.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
import JennaAnalytic from '@/components/jenna-analytic'
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/dashboard/jenna-analytic')({
|
||||||
|
component: JennaAnalytic,
|
||||||
|
})
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
import KinerjaDivisi from "../../app/components/kinerja-divisi";
|
import KinerjaDivisi from "@/components/kinerja-divisi";
|
||||||
export const Route = createFileRoute("/dashboard/kinerja-divisi")({
|
export const Route = createFileRoute("/dashboard/kinerja-divisi")({
|
||||||
component: KinerjaDivisi,
|
component: KinerjaDivisi,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
import PengaduanLayananPublik from "../../app/components/pengaduan-layanan-publik";
|
import PengaduanLayananPublik from "@/components/pengaduan-layanan-publik";
|
||||||
export const Route = createFileRoute("/dashboard/pengaduan-layanan-publik")({
|
export const Route = createFileRoute("/dashboard/pengaduan-layanan-publik")({
|
||||||
component: PengaduanLayananPublik,
|
component: PengaduanLayananPublik,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createFileRoute, Outlet } from "@tanstack/react-router";
|
import { createFileRoute, Outlet } from "@tanstack/react-router";
|
||||||
import { Header } from "@/app/components/header";
|
import { Header } from "@/components/header";
|
||||||
import { Sidebar } from "@/app/components/sidebar";
|
import { Sidebar } from "@/components/sidebar";
|
||||||
import { AppShell, Burger, Group } from "@mantine/core";
|
import { AppShell, Burger, Group } from "@mantine/core";
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user