From 89c8ca83a8c0d4feeb51569789a0b489266f894a Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 13 Mar 2026 12:05:46 +0800 Subject: [PATCH] fix: make dashboard public and remove admin-only restriction from main pages - Make homepage (/) accessible without authentication - Allow all authenticated users (user & admin) to access main pages: - /kinerja-divisi, /pengaduan, /jenna, /demografi - /keuangan, /bumdes, /sosial, /keamanan - /bantuan, /pengaturan - Reserve admin-only access for /admin/* routes - Update auth middleware to handle public routes properly Co-authored-by: Qwen-Coder --- src/components/bumdes-page.tsx | 661 ++++++++------ src/components/dashboard-card.tsx | 4 +- src/components/dashboard-content.tsx | 177 +++- src/components/demografi-pekerjaan.tsx | 172 +++- src/components/header.tsx | 45 +- src/components/help-page.tsx | 631 +++++++++----- src/components/jenna-analytic.tsx | 69 +- src/components/keamanan-page.tsx | 526 ++++++----- src/components/keuangan-anggaran.tsx | 114 ++- src/components/kinerja-divisi.tsx | 368 ++++++-- src/components/pengaduan-layanan-publik.tsx | 404 ++++++--- src/components/pengaturan/akses-dan-tim.tsx | 287 ++++--- src/components/pengaturan/keamanan.tsx | 119 ++- src/components/pengaturan/notifikasi.tsx | 115 ++- src/components/pengaturan/umum.tsx | 122 ++- src/components/sidebar.tsx | 95 +- src/components/sosial-page.tsx | 714 +++++++++------ src/components/ui/card.tsx | 1 - src/components/ui/help-card.tsx | 156 ++-- src/frontend.tsx | 5 +- src/index.css | 2 +- src/middleware/authMiddleware.tsx | 34 +- src/routeTree.gen.ts | 625 ++++++-------- src/routes/__root.tsx | 16 +- src/routes/admin/route.tsx | 1 - src/routes/bantuan.tsx | 51 ++ src/routes/bumdes.tsx | 9 + src/routes/dashboard/bantuan.ts | 7 - src/routes/dashboard/bumdes.ts | 7 - src/routes/dashboard/demografi-pekerjaan.ts | 7 - src/routes/dashboard/index.ts | 5 - src/routes/dashboard/jenna-analytic.ts | 6 - src/routes/dashboard/keamanan.ts | 7 - src/routes/dashboard/keuangan-anggaran.ts | 6 - src/routes/dashboard/kinerja-divisi.ts | 5 - .../dashboard/pengaduan-layanan-publik.ts | 5 - .../dashboard/pengaturan/akses-dan-tim.ts | 6 - src/routes/dashboard/pengaturan/keamanan.ts | 7 - src/routes/dashboard/pengaturan/notifikasi.ts | 6 - src/routes/dashboard/pengaturan/route.tsx | 9 - src/routes/dashboard/pengaturan/umum.ts | 7 - src/routes/dashboard/sosial.ts | 8 - src/routes/demografi-pekerjaan.tsx | 51 ++ src/routes/index.tsx | 813 +----------------- src/routes/jenna-analytic.tsx | 9 + src/routes/keamanan.tsx | 9 + src/routes/keuangan-anggaran.tsx | 51 ++ src/routes/kinerja-divisi.tsx | 51 ++ src/routes/pengaduan-layanan-publik.tsx | 51 ++ src/routes/pengaturan/akses-dan-tim.tsx | 9 + src/routes/pengaturan/keamanan.tsx | 9 + src/routes/pengaturan/notifikasi.tsx | 9 + .../{dashboard => pengaturan}/route.tsx | 29 +- src/routes/pengaturan/umum.tsx | 6 + src/routes/sosial.tsx | 9 + 55 files changed, 3810 insertions(+), 2917 deletions(-) create mode 100644 src/routes/bantuan.tsx create mode 100644 src/routes/bumdes.tsx delete mode 100644 src/routes/dashboard/bantuan.ts delete mode 100644 src/routes/dashboard/bumdes.ts delete mode 100644 src/routes/dashboard/demografi-pekerjaan.ts delete mode 100644 src/routes/dashboard/index.ts delete mode 100644 src/routes/dashboard/jenna-analytic.ts delete mode 100644 src/routes/dashboard/keamanan.ts delete mode 100644 src/routes/dashboard/keuangan-anggaran.ts delete mode 100644 src/routes/dashboard/kinerja-divisi.ts delete mode 100644 src/routes/dashboard/pengaduan-layanan-publik.ts delete mode 100644 src/routes/dashboard/pengaturan/akses-dan-tim.ts delete mode 100644 src/routes/dashboard/pengaturan/keamanan.ts delete mode 100644 src/routes/dashboard/pengaturan/notifikasi.ts delete mode 100644 src/routes/dashboard/pengaturan/route.tsx delete mode 100644 src/routes/dashboard/pengaturan/umum.ts delete mode 100644 src/routes/dashboard/sosial.ts create mode 100644 src/routes/demografi-pekerjaan.tsx create mode 100644 src/routes/jenna-analytic.tsx create mode 100644 src/routes/keamanan.tsx create mode 100644 src/routes/keuangan-anggaran.tsx create mode 100644 src/routes/kinerja-divisi.tsx create mode 100644 src/routes/pengaduan-layanan-publik.tsx create mode 100644 src/routes/pengaturan/akses-dan-tim.tsx create mode 100644 src/routes/pengaturan/keamanan.tsx create mode 100644 src/routes/pengaturan/notifikasi.tsx rename src/routes/{dashboard => pengaturan}/route.tsx (63%) create mode 100644 src/routes/pengaturan/umum.tsx create mode 100644 src/routes/sosial.tsx diff --git a/src/components/bumdes-page.tsx b/src/components/bumdes-page.tsx index 647bfc0..4b7e1b2 100644 --- a/src/components/bumdes-page.tsx +++ b/src/components/bumdes-page.tsx @@ -1,296 +1,389 @@ -import { useState } from "react"; -import { - Card, - Grid, - GridCol, - Group, - Text, - Title, - Button, - Badge, - Table, - Stack, - Select, - useMantineColorScheme +import { + Badge, + Button, + Card, + Grid, + GridCol, + Group, + Select, + Stack, + Table, + Text, + Title, + useMantineColorScheme, } from "@mantine/core"; -import { IconBuildingStore, IconCategory, IconCurrency, IconUsers } from "@tabler/icons-react"; +import { + IconBuildingStore, + IconCategory, + IconCurrency, + IconUsers, +} from "@tabler/icons-react"; +import { useState } from "react"; const BumdesPage = () => { - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; - - const [timeFilter, setTimeFilter] = useState("bulan"); - - // Sample data for KPI cards - const kpiData = [ - { - title: "UMKM Aktif", - value: 45, - icon: , - color: "darmasaba-blue", - }, - { - title: "UMKM Terdaftar", - value: 68, - icon: , - color: "darmasaba-success", - }, - { - title: "Omzet", - value: "Rp 48.000.000", - icon: , - color: "darmasaba-warning", - }, - { - title: "Kategori UMKM", - value: 34, - icon: , - color: "darmasaba-danger", - }, - ]; + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; - // Sample data for top products - const topProducts = [ - { - rank: 1, - name: "Beras Premium Organik", - umkmOwner: "Warung Pak Joko", - growth: "+12%", - }, - { - rank: 2, - name: "Keripik Singkong", - umkmOwner: "Ibu Sari Snack", - growth: "+8%", - }, - { - rank: 3, - name: "Madu Alami", - umkmOwner: "Peternakan Lebah", - growth: "+5%", - }, - ]; + const [timeFilter, setTimeFilter] = useState("bulan"); - // Sample data for product sales - const productSales = [ - { - produk: "Beras Premium Organik", - penjualanBulanIni: "Rp 8.500.000", - bulanLalu: "Rp 8.500.000", - trend: 10, - volume: "650 Kg", - stok: "850 Kg", - }, - { - produk: "Keripik Singkong", - penjualanBulanIni: "Rp 4.200.000", - bulanLalu: "Rp 3.800.000", - trend: 10, - volume: "320 Kg", - stok: "120 Kg", - }, - { - produk: "Madu Alami", - penjualanBulanIni: "Rp 3.750.000", - bulanLalu: "Rp 4.100.000", - trend: -8, - volume: "150 Liter", - stok: "45 Liter", - }, - { - produk: "Kecap Tradisional", - penjualanBulanIni: "Rp 2.800.000", - bulanLalu: "Rp 2.500.000", - trend: 12, - volume: "280 Botol", - stok: "95 Botol", - }, - ]; + // Sample data for KPI cards + const kpiData = [ + { + title: "UMKM Aktif", + value: 45, + icon: , + color: "darmasaba-blue", + }, + { + title: "UMKM Terdaftar", + value: 68, + icon: , + color: "darmasaba-success", + }, + { + title: "Omzet", + value: "Rp 48.000.000", + icon: , + color: "darmasaba-warning", + }, + { + title: "Kategori UMKM", + value: 34, + icon: , + color: "darmasaba-danger", + }, + ]; - return ( - - {/* KPI Cards */} - - {kpiData.map((kpi, index) => ( - - - - - - {kpi.title} - - - {typeof kpi.value === 'number' ? kpi.value.toLocaleString() : kpi.value} - - - - {kpi.icon} - - - - - ))} - + // Sample data for top products + const topProducts = [ + { + rank: 1, + name: "Beras Premium Organik", + umkmOwner: "Warung Pak Joko", + growth: "+12%", + }, + { + rank: 2, + name: "Keripik Singkong", + umkmOwner: "Ibu Sari Snack", + growth: "+8%", + }, + { + rank: 3, + name: "Madu Alami", + umkmOwner: "Peternakan Lebah", + growth: "+5%", + }, + ]; - {/* Update Penjualan Produk Header */} - - - - Update Penjualan Produk - - - - - - - + // Sample data for product sales + const productSales = [ + { + produk: "Beras Premium Organik", + penjualanBulanIni: "Rp 8.500.000", + bulanLalu: "Rp 8.500.000", + trend: 10, + volume: "650 Kg", + stok: "850 Kg", + }, + { + produk: "Keripik Singkong", + penjualanBulanIni: "Rp 4.200.000", + bulanLalu: "Rp 3.800.000", + trend: 10, + volume: "320 Kg", + stok: "120 Kg", + }, + { + produk: "Madu Alami", + penjualanBulanIni: "Rp 3.750.000", + bulanLalu: "Rp 4.100.000", + trend: -8, + volume: "150 Liter", + stok: "45 Liter", + }, + { + produk: "Kecap Tradisional", + penjualanBulanIni: "Rp 2.800.000", + bulanLalu: "Rp 2.500.000", + trend: 12, + volume: "280 Botol", + stok: "95 Botol", + }, + ]; - - {/* Produk Unggulan (Left Column) */} - - - {/* Total Penjualan, Produk Aktif, Total Transaksi */} - - - - Total Penjualan - Rp 28.500.000 - - - Produk Aktif - 124 Produk - - - Total Transaksi - 1.240 Transaksi - - - + return ( + + {/* KPI Cards */} + + {kpiData.map((kpi, index) => ( + + + + + + {kpi.title} + + + {typeof kpi.value === "number" + ? kpi.value.toLocaleString() + : kpi.value} + + + + {kpi.icon} + + + + + ))} + - {/* Top 3 Produk Terlaris */} - - Top 3 Produk Terlaris - - {topProducts.map((product) => ( - - - - {product.rank} - - - {product.name} - {product.umkmOwner} - - - - {product.growth} - - - ))} - - - - + {/* Update Penjualan Produk Header */} + + + + Update Penjualan Produk + + + + + + + - {/* Detail Penjualan Produk (Right Column) */} - - - - Detail Penjualan Produk - + + + + + + + Produk + + + + Penjualan Bulan Ini + + + + Bulan Lalu + + + Trend + + + Volume + + + Stok + + + Aksi + + + + + {productSales.map((product, index) => ( + + + + {product.produk} + + + + + {product.penjualanBulanIni} + + + + + {product.bulanLalu} + + + + + = 0 ? "green" : "red"}> + {product.trend >= 0 ? "↑" : "↓"}{" "} + {Math.abs(product.trend)}% + + + + + + {product.volume} + + + + 200 ? "green" : "yellow" + } + > + {product.stok} + + + + + + + ))} + +
+
+
+
+
+ ); }; -export default BumdesPage; \ No newline at end of file +export default BumdesPage; diff --git a/src/components/dashboard-card.tsx b/src/components/dashboard-card.tsx index 9eaed80..44cbcbd 100644 --- a/src/components/dashboard-card.tsx +++ b/src/components/dashboard-card.tsx @@ -1,6 +1,6 @@ -import type { ReactNode } from "react"; // Import Mantine components directly -import { Group, Text, ThemeIcon, Badge } from "@mantine/core"; +import { Badge, Group, Text, ThemeIcon } from "@mantine/core"; +import type { ReactNode } from "react"; // Import custom Card and its sub-components import { Card } from "./ui/card"; diff --git a/src/components/dashboard-content.tsx b/src/components/dashboard-content.tsx index 0f70818..f45ccdf 100644 --- a/src/components/dashboard-content.tsx +++ b/src/components/dashboard-content.tsx @@ -13,25 +13,25 @@ import { Pie, PieChart, ResponsiveContainer, + Tooltip, // Added Tooltip import XAxis, YAxis, - Tooltip, // Added Tooltip import } from "recharts"; // Import Mantine components import { - Grid, - Stack, - Group, - Text, - Title, ActionIcon, - Progress, - Box, Badge, - ThemeIcon, + Box, Card, // Added for icon containers + Grid, + Group, + Progress, + Stack, + Text, + ThemeIcon, + Title, useMantineColorScheme, // Add this import } from "@mantine/core"; @@ -68,13 +68,20 @@ const eventData = [ export function DashboardContent() { const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; + const dark = colorScheme === "dark"; return ( {/* Stats Cards */} - + @@ -92,14 +99,26 @@ export function DashboardContent() { 12% dari minggu lalu ↗ +12% - + - + @@ -114,14 +133,26 @@ export function DashboardContent() { 14 baru, 14 diproses - + - + @@ -139,14 +170,26 @@ export function DashboardContent() { +8% - + - + @@ -161,7 +204,12 @@ export function DashboardContent() { dari 482 responden - + @@ -171,7 +219,13 @@ export function DashboardContent() { {/* Bar Chart */} - + @@ -232,7 +286,13 @@ export function DashboardContent() { {/* Pie Chart */} <Grid.Col span={{ base: 12, lg: 6 }}> - <Card p="md" style={{borderColor: dark ? "#141D34" : "white"}} radius="md" withBorder bg={dark ? "#141D34" : "white"}> + <Card + p="md" + style={{ borderColor: dark ? "#141D34" : "white" }} + radius="md" + withBorder + bg={dark ? "#141D34" : "white"} + > <Title order={4} mb={5}> Tingkat Kepuasan @@ -259,19 +319,35 @@ export function DashboardContent() { - + Sangat puas (0%) - + Puas (0%) - + Cukup (0%) - + Kurang (0%) @@ -283,7 +359,13 @@ export function DashboardContent() { {/* Divisi Teraktif */} - + {/* Original SVG icon */} @@ -355,7 +437,13 @@ export function DashboardContent() { {/* Kalender */} - + Kalender & Kegiatan Mendatang @@ -364,7 +452,10 @@ export function DashboardContent() { {eventData.map((event, index) => ( {event.date} @@ -378,7 +469,13 @@ export function DashboardContent() { {/* APBDes Chart */} - + Grafik APBDes @@ -387,19 +484,37 @@ export function DashboardContent() { Belanja - + Pendapatan - + Pembangunan - + diff --git a/src/components/demografi-pekerjaan.tsx b/src/components/demografi-pekerjaan.tsx index 99240af..cf189d2 100644 --- a/src/components/demografi-pekerjaan.tsx +++ b/src/components/demografi-pekerjaan.tsx @@ -1,17 +1,22 @@ -import React from "react"; +import { BarChart, PieChart } from "@mantine/charts"; import { + Box, Card, - Title, - Text, + Grid, Group, Stack, - Grid, - Box, Table, + Text, + Title, useMantineColorScheme, } from "@mantine/core"; -import { IconBabyCarriage, IconSkull, IconArrowUp, IconArrowDown } from "@tabler/icons-react"; -import { BarChart, PieChart } from "@mantine/charts"; +import { + IconArrowDown, + IconArrowUp, + IconBabyCarriage, + IconSkull, +} from "@tabler/icons-react"; +import React from "react"; // Sample Data const kpiData = [ @@ -71,7 +76,11 @@ const kpiData = [ value: "23", sub: "Tahun ini", icon: ( - + ), }, { @@ -136,10 +145,30 @@ const banjarData = [ ]; const dynamicStats = [ - { title: "Kelahiran", value: "23", icon: , color: "green" }, - { title: "Kematian", value: "12", icon: , color: "red" }, - { title: "Pindah Masuk", value: "45", icon: , color: "blue" }, - { title: "Pindah Keluar", value: "32", icon: , color: "orange" }, + { + title: "Kelahiran", + value: "23", + icon: , + color: "green", + }, + { + title: "Kematian", + value: "12", + icon: , + color: "red", + }, + { + title: "Pindah Masuk", + value: "45", + icon: , + color: "blue", + }, + { + title: "Pindah Keluar", + value: "32", + icon: , + color: "orange", + }, ]; const DemografiPekerjaan = () => { @@ -152,14 +181,22 @@ const DemografiPekerjaan = () => { {kpiData.map((kpi) => ( - + {kpi.title} {React.cloneElement(kpi.icon, { className: "h-6 w-6", - color: dark ? "var(--mantine-color-dark-3)" : "var(--mantine-color-dimmed)", + color: dark + ? "var(--mantine-color-dark-3)" + : "var(--mantine-color-dimmed)", })} @@ -173,7 +210,9 @@ const DemografiPekerjaan = () => { ? "green" : kpi.deltaType === "negative" ? "red" - : dark ? "dark.3" : "dimmed" + : dark + ? "dark.3" + : "dimmed" } mt={4} > @@ -194,7 +233,13 @@ const DemografiPekerjaan = () => { <Grid gutter="lg"> {/* Grafik Pengelompokan Umur */} <Grid.Col span={{ base: 12, lg: 6 }}> - <Card p="md" radius="md" withBorder bg={dark ? "#141D34" : "white"} style={{ borderColor: dark ? "#141D34" : "white" }}> + <Card + p="md" + radius="md" + withBorder + bg={dark ? "#141D34" : "white"} + style={{ borderColor: dark ? "#141D34" : "white" }} + > <Title order={3} fw={500} mb="md"> Grafik Pengelompokan Umur @@ -202,7 +247,7 @@ const DemografiPekerjaan = () => { h={300} data={ageDistributionData} dataKey="ageRange" - series={[{ name: 'total', color: 'darmasaba-navy' }]} + series={[{ name: "total", color: "darmasaba-navy" }]} withLegend /> @@ -210,7 +255,13 @@ const DemografiPekerjaan = () => { {/* Demografi Pekerjaan */} - + Demografi Pekerjaan @@ -218,7 +269,7 @@ const DemografiPekerjaan = () => { h={300} data={jobDistributionData} dataKey="job" - series={[{ name: 'total', color: 'darmasaba-navy' }]} + series={[{ name: "total", color: "darmasaba-navy" }]} withLegend /> @@ -229,16 +280,22 @@ const DemografiPekerjaan = () => { {/* Distribusi Agama */} - + Distribusi Agama ({ + data={religionData.map((item) => ({ name: item.religion, value: item.total, - color: item.color + color: item.color, }))} withLabels withLabelsLine @@ -250,27 +307,53 @@ const DemografiPekerjaan = () => { {/* Data per Banjar */} - + Data per Banjar - Banjar - Penduduk - KK - Miskin + + Banjar + + + Penduduk + + + KK + + + Miskin + {banjarData.map((item, index) => ( - {item.banjar} - {item.population.toLocaleString()} - {item.kk.toLocaleString()} - {item.poor.toLocaleString()} + {item.banjar} + + + + {item.population.toLocaleString()} + + + + + {item.kk.toLocaleString()} + + + + + {item.poor.toLocaleString()} + ))} @@ -281,14 +364,29 @@ const DemografiPekerjaan = () => { {/* Statistik Dinamika Penduduk */} - + Statistik Dinamika Penduduk {dynamicStats.map((stat, index) => ( - - + + @@ -298,9 +396,7 @@ const DemografiPekerjaan = () => { {stat.value} - - {stat.icon} - + {stat.icon} @@ -312,4 +408,4 @@ const DemografiPekerjaan = () => { ); }; -export default DemografiPekerjaan; \ No newline at end of file +export default DemografiPekerjaan; diff --git a/src/components/header.tsx b/src/components/header.tsx index ad1eb73..cea0dd9 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -1,46 +1,52 @@ -import { useLocation } from "@tanstack/react-router"; -import { Bell, Moon, Sun, User as UserIcon } from "lucide-react"; // Renamed User to UserIcon to avoid conflict with Mantine's User component if it exists - import { + ActionIcon, + Avatar, + Badge, + Box, + Divider, Group, Text, Title, - ActionIcon, - Divider, - Avatar, - Box, - Badge, useMantineColorScheme, } from "@mantine/core"; +import { IconUserShield } from "@tabler/icons-react"; +import { useLocation, useNavigate } from "@tanstack/react-router"; +import { Bell, Moon, Sun, User as UserIcon } from "lucide-react"; // Renamed User to UserIcon to avoid conflict with Mantine's User component if it exists export function Header() { const location = useLocation(); const { colorScheme, toggleColorScheme } = useMantineColorScheme(); const dark = colorScheme === "dark"; + const navigate = useNavigate(); // Define page titles based on route const getPageTitle = () => { switch (location.pathname) { case "/": - return "Desa Darmasaba"; + return "Beranda"; case "/kinerja-divisi": return "Kinerja Divisi"; - case "/pengaduan": + case "/pengaduan-layanan-publik": return "Pengaduan & Layanan Publik"; - case "/analytic": + case "/jenna-analytic": return "Jenna Analytic"; - case "/demografi": + case "/demografi-pekerjaan": return "Demografi & Kependudukan"; - case "/keuangan": + case "/keuangan-anggaran": return "Keuangan & Anggaran"; case "/bumdes": return "Bumdes & UMKM Desa"; case "/sosial": + return "Sosial"; case "/keamanan": return "Keamanan"; case "/bantuan": return "Bantuan"; case "/pengaturan": + case "/pengaturan/umum": + case "/pengaturan/notifikasi": + case "/pengaturan/keamanan": + case "/pengaturan/akses-dan-tim": return "Pengaturan"; default: return "Desa Darmasaba"; @@ -50,12 +56,12 @@ export function Header() { return ( {/* Title */} - {getPageTitle()} + + {getPageTitle()} + {/* Right Section */} - - {/* User Info */} @@ -101,6 +107,13 @@ export function Header() { 10 + + navigate({ to: "/signin" })} + /> + diff --git a/src/components/help-page.tsx b/src/components/help-page.tsx index d43a0c3..1450a18 100644 --- a/src/components/help-page.tsx +++ b/src/components/help-page.tsx @@ -1,248 +1,435 @@ -import { Container, Grid, Title, Text, SimpleGrid, Box, Accordion, Stack, useMantineColorScheme } from '@mantine/core'; -import { HelpCard } from '@/components/ui/help-card'; -import { IconBook, IconVideo, IconHelpCircle, IconMessage, IconFileText, IconHeadphones } from '@tabler/icons-react'; -import { useState } from 'react'; +import { + Accordion, + Box, + Container, + Grid, + SimpleGrid, + Stack, + Text, + Title, + useMantineColorScheme, +} from "@mantine/core"; +import { + IconBook, + IconFileText, + IconHeadphones, + IconHelpCircle, + IconMessage, + IconVideo, +} from "@tabler/icons-react"; +import { useState } from "react"; +import { HelpCard } from "@/components/ui/help-card"; const HelpPage = () => { - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === "dark"; - // Sample data for sections - const guideItems = [ - { title: 'Cara Login', description: 'Langkah-langkah untuk login ke dashboard' }, - { title: 'Navigasi Dashboard', description: 'Penjelasan tentang tata letak dan navigasi' }, - { title: 'Fitur Dasar', description: 'Panduan penggunaan fitur-fitur utama' }, - { title: 'Tips & Trik', description: 'Tips untuk meningkatkan produktivitas' }, - ]; + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + // Sample data for sections + const guideItems = [ + { + title: "Cara Login", + description: "Langkah-langkah untuk login ke dashboard", + }, + { + title: "Navigasi Dashboard", + description: "Penjelasan tentang tata letak dan navigasi", + }, + { + title: "Fitur Dasar", + description: "Panduan penggunaan fitur-fitur utama", + }, + { + title: "Tips & Trik", + description: "Tips untuk meningkatkan produktivitas", + }, + ]; - const videoItems = [ - { title: 'Dashboard Overview', duration: '5:23' }, - { title: 'Analisis Data', duration: '8:45' }, - { title: 'Membuat Laporan', duration: '6:12' }, - { title: 'Export Data', duration: '4:30' }, - ]; + const videoItems = [ + { title: "Dashboard Overview", duration: "5:23" }, + { title: "Analisis Data", duration: "8:45" }, + { title: "Membuat Laporan", duration: "6:12" }, + { title: "Export Data", duration: "4:30" }, + ]; - const faqItems = [ - { question: 'Bagaimana cara reset password?', answer: 'Anda dapat mereset password melalui halaman login dengan klik "Lupa Password"' }, - { question: 'Apakah saya bisa mengakses data offline?', answer: 'Saat ini aplikasi hanya dapat diakses secara online' }, - { question: 'Berapa lama waktu respon support?', answer: 'Tim support kami biasanya merespon dalam waktu kurang dari 24 jam' }, - { question: 'Bagaimana cara menambahkan pengguna baru?', answer: 'Fitur penambahan pengguna dapat ditemukan di menu Pengaturan > Manajemen Pengguna' }, - ]; + const faqItems = [ + { + question: "Bagaimana cara reset password?", + answer: + 'Anda dapat mereset password melalui halaman login dengan klik "Lupa Password"', + }, + { + question: "Apakah saya bisa mengakses data offline?", + answer: "Saat ini aplikasi hanya dapat diakses secara online", + }, + { + question: "Berapa lama waktu respon support?", + answer: + "Tim support kami biasanya merespon dalam waktu kurang dari 24 jam", + }, + { + question: "Bagaimana cara menambahkan pengguna baru?", + answer: + "Fitur penambahan pengguna dapat ditemukan di menu Pengaturan > Manajemen Pengguna", + }, + ]; - const documentationItems = [ - { title: 'API Reference', description: 'Dokumentasi lengkap untuk integrasi API' }, - { title: 'Integrasi Sistem', description: 'Cara mengintegrasikan dengan sistem eksternal' }, - { title: 'Format Data', description: 'Spesifikasi format data yang didukung' }, - { title: 'Best Practices', description: 'Praktik terbaik dalam penggunaan platform' }, - ]; + const documentationItems = [ + { + title: "API Reference", + description: "Dokumentasi lengkap untuk integrasi API", + }, + { + title: "Integrasi Sistem", + description: "Cara mengintegrasikan dengan sistem eksternal", + }, + { + title: "Format Data", + description: "Spesifikasi format data yang didukung", + }, + { + title: "Best Practices", + description: "Praktik terbaik dalam penggunaan platform", + }, + ]; - const stats = [ - { value: '150+', label: 'Artikel Panduan' }, - { value: '50+', label: 'Video Tutorial' }, - { value: '24/7', label: 'Support Aktif' }, - ]; + const stats = [ + { value: "150+", label: "Artikel Panduan" }, + { value: "50+", label: "Video Tutorial" }, + { value: "24/7", label: "Support Aktif" }, + ]; - // State for chat functionality - const [messages, setMessages] = useState([ - { id: 1, text: 'Halo! Saya Jenna, asisten virtual Anda. Bagaimana saya bisa membantu hari ini?', sender: 'jenna' } - ]); - const [inputValue, setInputValue] = useState(''); - const [isLoading, setIsLoading] = useState(false); + // State for chat functionality + const [messages, setMessages] = useState([ + { + id: 1, + text: "Halo! Saya Jenna, asisten virtual Anda. Bagaimana saya bisa membantu hari ini?", + sender: "jenna", + }, + ]); + const [inputValue, setInputValue] = useState(""); + const [isLoading, setIsLoading] = useState(false); - const handleSendMessage = () => { - if (inputValue.trim() === '') return; + const handleSendMessage = () => { + if (inputValue.trim() === "") return; - // Add user message - const newUserMessage = { - id: messages.length + 1, - text: inputValue, - sender: 'user' - }; + // Add user message + const newUserMessage = { + id: messages.length + 1, + text: inputValue, + sender: "user", + }; - setMessages(prev => [...prev, newUserMessage]); - setInputValue(''); - setIsLoading(true); + setMessages((prev) => [...prev, newUserMessage]); + setInputValue(""); + setIsLoading(true); - // Simulate Jenna's response after delay - setTimeout(() => { - const jennaResponse = { - id: messages.length + 2, - text: 'Terima kasih atas pertanyaan Anda. Saat ini saya adalah versi awal dari asisten virtual. Tim kami sedang mengembangkan kemampuan saya lebih lanjut.', - sender: 'jenna' - }; - setMessages(prev => [...prev, jennaResponse]); - setIsLoading(false); - }, 1000); - }; + // Simulate Jenna's response after delay + setTimeout(() => { + const jennaResponse = { + id: messages.length + 2, + text: "Terima kasih atas pertanyaan Anda. Saat ini saya adalah versi awal dari asisten virtual. Tim kami sedang mengembangkan kemampuan saya lebih lanjut.", + sender: "jenna", + }; + setMessages((prev) => [...prev, jennaResponse]); + setIsLoading(false); + }, 1000); + }; - const handleKeyPress = (e: React.KeyboardEvent) => { - if (e.key === 'Enter' && !e.shiftKey) { - e.preventDefault(); - handleSendMessage(); - } - }; + const handleKeyPress = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + handleSendMessage(); + } + }; - return ( - - Pusat Bantuan - - Temukan jawaban untuk pertanyaan Anda atau hubungi tim support kami - + return ( + + + Pusat Bantuan + + + Temukan jawaban untuk pertanyaan Anda atau hubungi tim support kami + - {/* Statistics Section */} - - {stats.map((stat, index) => ( - - {stat.value} - {stat.label} - - ))} - + {/* Statistics Section */} + + {stats.map((stat, index) => ( + + + {stat.value} + + + {stat.label} + + + ))} + - - - - {/* Panduan Memulai */} - - } title="Panduan Memulai" h="100%"> - - {guideItems.map((item, index) => ( - alert(`Navigasi ke ${item.title}`)}> - {item.title} - {item.description} - - ))} - - - + + + + {/* Panduan Memulai */} + + } + title="Panduan Memulai" + h="100%" + > + + {guideItems.map((item, index) => ( + alert(`Navigasi ke ${item.title}`)} + > + {item.title} + + {item.description} + + + ))} + + + - {/* Video Tutorial */} - - } title="Video Tutorial" h="100%"> - - {videoItems.map((item, index) => ( - alert(`Buka video: ${item.title}`)}> - {item.title} - {item.duration} - - ))} - - - + {/* Video Tutorial */} + + } + title="Video Tutorial" + h="100%" + > + + {videoItems.map((item, index) => ( + alert(`Buka video: ${item.title}`)} + > + {item.title} + + {item.duration} + + + ))} + + + - {/* FAQ */} - - } title="FAQ" h="100%"> - - {faqItems.map((item, index) => ( - - {item.question} - - {item.answer} - - - ))} - - - - - + {/* FAQ */} + + } + title="FAQ" + h="100%" + > + + {faqItems.map((item, index) => ( + + {item.question} + + {item.answer} + + + ))} + + + + + - - - {/* Hubungi Support */} - - } title="Hubungi Support" h="100%"> - - Email - support@example.com + + + {/* Hubungi Support */} + + } + title="Hubungi Support" + h="100%" + > + + Email + + support@example.com + - WhatsApp - +62 123 456 7890 + WhatsApp + + +62 123 456 7890 + - Jam Kerja - Senin - Jumat, 09:00 - 17:00 WIB + Jam Kerja + + Senin - Jumat, 09:00 - 17:00 WIB + - Waktu Respon - Rata-rata 2-4 jam kerja - - - + + Waktu Respon + + + Rata-rata 2-4 jam kerja + + + + - {/* Dokumentasi */} - - } title="Dokumentasi" h="100%"> - - {documentationItems.map((item, index) => ( - alert(`Navigasi ke dokumentasi: ${item.title}`)}> - {item.title} - {item.description} - - ))} - - - + {/* Dokumentasi */} + + } + title="Dokumentasi" + h="100%" + > + + {documentationItems.map((item, index) => ( + + alert(`Navigasi ke dokumentasi: ${item.title}`) + } + > + {item.title} + + {item.description} + + + ))} + + + - {/* Jenna - Virtual Assistant */} - - } title="Jenna - Virtual Assistant" h="100%"> - - - {messages.map((msg) => ( - - {msg.text} - - ))} - + {/* Jenna - Virtual Assistant */} + + } + title="Jenna - Virtual Assistant" + h="100%" + > + + + {messages.map((msg) => ( + + {msg.text} + + ))} + - - setInputValue(e.target.value)} - onKeyPress={handleKeyPress} - placeholder="Ketik pesan Anda..." - style={{ - flex: 1, - padding: '8px 12px', - borderRadius: '20px', - border: '1px solid #ccc', - }} - disabled={isLoading} - /> - - - - - - - - - - ); + + setInputValue(e.target.value)} + onKeyPress={handleKeyPress} + placeholder="Ketik pesan Anda..." + style={{ + flex: 1, + padding: "8px 12px", + borderRadius: "20px", + border: "1px solid #ccc", + }} + disabled={isLoading} + /> + + + + + + + + + + ); }; -export default HelpPage; \ No newline at end of file +export default HelpPage; diff --git a/src/components/jenna-analytic.tsx b/src/components/jenna-analytic.tsx index 251b873..063a56c 100644 --- a/src/components/jenna-analytic.tsx +++ b/src/components/jenna-analytic.tsx @@ -1,18 +1,18 @@ -import React from "react"; +import { BarChart } from "@mantine/charts"; import { + Badge, + Box, Button, Card, - Badge, - Progress, - Title, - Text, - Group, - Stack, Grid, - Box, + Group, + Progress, + Stack, + Text, + Title, useMantineColorScheme, } from "@mantine/core"; -import { BarChart } from "@mantine/charts"; +import React from "react"; // Sample Data const kpiData = [ @@ -144,7 +144,13 @@ const JennaAnalytic = () => { {kpiData.map((kpi) => ( - + {kpi.title} @@ -182,7 +188,13 @@ const JennaAnalytic = () => { ))} - + Interaksi Chatbot @@ -190,7 +202,7 @@ const JennaAnalytic = () => { h={300} data={chartData} dataKey="day" - series={[{ name: 'total', color: 'blue' }]} + series={[{ name: "total", color: "blue" }]} withLegend /> @@ -199,16 +211,21 @@ const JennaAnalytic = () => { {/* Grafik Interaksi Chatbot (now Bar Chart) */} - + Jam Tersibuk {busyHours.map((item, index) => ( - - {item.period} - + {item.period} @@ -225,7 +242,14 @@ const JennaAnalytic = () => { {/* Topik Pertanyaan Terbanyak */} - + Topik Pertanyaan Terbanyak @@ -251,12 +275,9 @@ const JennaAnalytic = () => { {/* Jam Tersibuk */} - - - - + + + ); - -} +}; export default JennaAnalytic; - diff --git a/src/components/keamanan-page.tsx b/src/components/keamanan-page.tsx index 18e3599..b1dd262 100644 --- a/src/components/keamanan-page.tsx +++ b/src/components/keamanan-page.tsx @@ -1,225 +1,325 @@ -import { useState } from "react"; -import { - Card, - Grid, - GridCol, - Group, - Text, - Title, - Stack, - useMantineColorScheme, - Badge, - List, - ThemeIcon, - Box +import { + Badge, + Box, + Card, + Grid, + GridCol, + Group, + List, + Stack, + Text, + ThemeIcon, + Title, + useMantineColorScheme, } from "@mantine/core"; -import { - IconCamera, - IconAlertTriangle, - IconMapPin, - IconClock, - IconEye, - IconShieldLock +import { + IconAlertTriangle, + IconCamera, + IconClock, + IconEye, + IconMapPin, + IconShieldLock, } from "@tabler/icons-react"; +import { useState } from "react"; const KeamananPage = () => { - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; - - // Sample data for KPI cards - const kpiData = [ - { - title: "CCTV Aktif", - value: 20, - subtitle: "Kamera Online", - icon: , - color: "darmasaba-success", - }, - { - title: "Laporan Keamanan", - value: 15, - subtitle: "Minggu ini", - icon: , - color: "darmasaba-danger", - }, - ]; + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; - // Sample data for CCTV locations - const cctvLocations = [ - { id: "CCTV-01", lat: -8.5, lng: 115.2, status: "active", lastSeen: "2 jam yang lalu", location: "Balai Desa" }, - { id: "CCTV-02", lat: -8.6, lng: 115.3, status: "active", lastSeen: "1 jam yang lalu", location: "Pintu Masuk Desa" }, - { id: "CCTV-03", lat: -8.4, lng: 115.1, status: "offline", lastSeen: "1 hari yang lalu", location: "Taman Desa" }, - { id: "CCTV-04", lat: -8.7, lng: 115.4, status: "active", lastSeen: "30 menit yang lalu", location: "Pasar Desa" }, - ]; + // Sample data for KPI cards + const kpiData = [ + { + title: "CCTV Aktif", + value: 20, + subtitle: "Kamera Online", + icon: , + color: "darmasaba-success", + }, + { + title: "Laporan Keamanan", + value: 15, + subtitle: "Minggu ini", + icon: , + color: "darmasaba-danger", + }, + ]; - // Sample data for security reports - const securityReports = [ - { - id: "REP-001", - title: "Pencurian Motor", - reportedAt: "2 jam yang lalu", - date: "12 Feb 2026, 14:30", - location: "Jl. Kecubung 20", - status: "baru", - }, - { - id: "REP-002", - title: "Kerusuhan Antar Warga", - reportedAt: "4 jam yang lalu", - date: "12 Feb 2026, 12:15", - location: "RT 05 RW 02", - status: "baru", - }, - { - id: "REP-003", - title: "Kebakaran Rumah", - reportedAt: "1 hari yang lalu", - date: "11 Feb 2026, 08:45", - location: "Jl. Flamboyan 15", - status: "diproses", - }, - { - id: "REP-004", - title: "Kehilangan Barang", - reportedAt: "2 hari yang lalu", - date: "10 Feb 2026, 16:20", - location: "Taman Desa", - status: "selesai", - }, - ]; + // Sample data for CCTV locations + const cctvLocations = [ + { + id: "CCTV-01", + lat: -8.5, + lng: 115.2, + status: "active", + lastSeen: "2 jam yang lalu", + location: "Balai Desa", + }, + { + id: "CCTV-02", + lat: -8.6, + lng: 115.3, + status: "active", + lastSeen: "1 jam yang lalu", + location: "Pintu Masuk Desa", + }, + { + id: "CCTV-03", + lat: -8.4, + lng: 115.1, + status: "offline", + lastSeen: "1 hari yang lalu", + location: "Taman Desa", + }, + { + id: "CCTV-04", + lat: -8.7, + lng: 115.4, + status: "active", + lastSeen: "30 menit yang lalu", + location: "Pasar Desa", + }, + ]; - return ( - - {/* Page Header */} - - - Keamanan Lingkungan Desa - - + // Sample data for security reports + const securityReports = [ + { + id: "REP-001", + title: "Pencurian Motor", + reportedAt: "2 jam yang lalu", + date: "12 Feb 2026, 14:30", + location: "Jl. Kecubung 20", + status: "baru", + }, + { + id: "REP-002", + title: "Kerusuhan Antar Warga", + reportedAt: "4 jam yang lalu", + date: "12 Feb 2026, 12:15", + location: "RT 05 RW 02", + status: "baru", + }, + { + id: "REP-003", + title: "Kebakaran Rumah", + reportedAt: "1 hari yang lalu", + date: "11 Feb 2026, 08:45", + location: "Jl. Flamboyan 15", + status: "diproses", + }, + { + id: "REP-004", + title: "Kehilangan Barang", + reportedAt: "2 hari yang lalu", + date: "10 Feb 2026, 16:20", + location: "Taman Desa", + status: "selesai", + }, + ]; - {/* KPI Cards */} - - {kpiData.map((kpi, index) => ( - - - - - - {kpi.subtitle} - - - - {kpi.value} - - - {kpi.title} - - - - - {kpi.icon} - - - - - ))} - + return ( + + {/* Page Header */} + + + Keamanan Lingkungan Desa + + - - {/* Peta Keamanan CCTV */} - - - Peta Keamanan CCTV - Titik Lokasi CCTV - - {/* Placeholder for map */} - - - - Peta Lokasi CCTV - Integrasi dengan Google Maps atau Mapbox akan ditampilkan di sini - - - - {/* CCTV Locations List */} - - Daftar CCTV - {cctvLocations.map((cctv, index) => ( - - - - - {cctv.id} - - {cctv.status === "active" ? "Online" : "Offline"} - - - {cctv.location} - - - - {cctv.lastSeen} - - - - ))} - - - + {/* KPI Cards */} + + {kpiData.map((kpi, index) => ( + + + + + + {kpi.subtitle} + + + + {kpi.value} + + + {kpi.title} + + + + + {kpi.icon} + + + + + ))} + - {/* Daftar Laporan Keamanan */} - - - Laporan Keamanan Lingkungan - - - {securityReports.map((report, index) => ( - - - {report.title} - - {report.status} - - - - - - - {report.location} - - - - {report.reportedAt} - - - - {report.date} - - ))} - - - - - - ); + + {/* Peta Keamanan CCTV */} + + + + Peta Keamanan CCTV + + + Titik Lokasi CCTV + + + {/* Placeholder for map */} + + + + Peta Lokasi CCTV + + Integrasi dengan Google Maps atau Mapbox akan ditampilkan di + sini + + + + + {/* CCTV Locations List */} + + + Daftar CCTV + + {cctvLocations.map((cctv, index) => ( + + + + + + {cctv.id} + + + {cctv.status === "active" ? "Online" : "Offline"} + + + + {cctv.location} + + + + + + {cctv.lastSeen} + + + + + ))} + + + + + {/* Daftar Laporan Keamanan */} + + + + Laporan Keamanan Lingkungan + + + + {securityReports.map((report, index) => ( + + + + {report.title} + + + {report.status} + + + + + + + + {report.location} + + + + + + {report.reportedAt} + + + + + + {report.date} + + + ))} + + + + + + ); }; -export default KeamananPage; \ No newline at end of file +export default KeamananPage; diff --git a/src/components/keuangan-anggaran.tsx b/src/components/keuangan-anggaran.tsx index 1a6f0cb..47ef4db 100644 --- a/src/components/keuangan-anggaran.tsx +++ b/src/components/keuangan-anggaran.tsx @@ -1,19 +1,23 @@ -import React from "react"; +import { BarChart } from "@mantine/charts"; import { + Badge, + Box, Button, Card, - Badge, - Title, - Text, - Group, - Stack, Grid, - Box, + Group, Progress, + Stack, + Text, + Title, useMantineColorScheme, } from "@mantine/core"; -import { IconTrendingUp, IconTrendingDown, IconCurrency } from "@tabler/icons-react"; -import { BarChart } from "@mantine/charts"; +import { + IconCurrency, + IconTrendingDown, + IconTrendingUp, +} from "@tabler/icons-react"; +import React from "react"; // Sample Data const kpiData = [ @@ -22,9 +26,7 @@ const kpiData = [ title: "Total APBDes", value: "Rp 5.2M", sub: "Tahun 2025", - icon: ( - - ), + icon: , }, { id: 2, @@ -55,18 +57,14 @@ const kpiData = [ sub: "Bulan ini", delta: "+8%", deltaType: "positive", - icon: ( - - ), + icon: , }, { id: 4, title: "Pengeluaran", value: "Rp 520jt", sub: "Bulan ini", - icon: ( - - ), + icon: , }, ]; @@ -125,7 +123,14 @@ const KeuanganAnggaran = () => { {kpiData.map((kpi) => ( - + {kpi.title} @@ -167,7 +172,13 @@ const KeuanganAnggaran = () => { {/* Grafik Pemasukan vs Pengeluaran */} - + Pemasukan vs Pengeluaran @@ -176,8 +187,8 @@ const KeuanganAnggaran = () => { data={incomeExpenseData} dataKey="month" series={[ - { name: 'income', color: 'green', label: 'Pemasukan' }, - { name: 'expense', color: 'red', label: 'Pengeluaran' }, + { name: "income", color: "green", label: "Pemasukan" }, + { name: "expense", color: "red", label: "Pengeluaran" }, ]} withLegend /> @@ -186,7 +197,13 @@ const KeuanganAnggaran = () => { {/* Alokasi Anggaran Per Sektor */} - + Alokasi Anggaran Per Sektor @@ -194,7 +211,9 @@ const KeuanganAnggaran = () => { h={300} data={allocationData} dataKey="sector" - series={[{ name: 'amount', color: 'darmasaba-navy', label: 'Jumlah' }]} + series={[ + { name: "amount", color: "darmasaba-navy", label: "Jumlah" }, + ]} withLegend orientation="horizontal" /> @@ -205,7 +224,13 @@ const KeuanganAnggaran = () => { {/* Dana Bantuan & Hibah */} - + Dana Bantuan & Hibah @@ -243,13 +268,21 @@ const KeuanganAnggaran = () => { {/* Laporan APBDes */} - + Laporan APBDes - Pendapatan + + Pendapatan + {apbdReport.income.map((item, index) => ( @@ -269,7 +302,9 @@ const KeuanganAnggaran = () => { - Belanja + + Belanja + {apbdReport.expenses.map((item, index) => ( @@ -288,11 +323,26 @@ const KeuanganAnggaran = () => { - + Saldo: - apbdReport.totalExpenses ? "green" : "red"}> - Rp {(apbdReport.totalIncome - apbdReport.totalExpenses).toLocaleString()}jt + apbdReport.totalExpenses + ? "green" + : "red" + } + > + Rp{" "} + {( + apbdReport.totalIncome - apbdReport.totalExpenses + ).toLocaleString()} + jt @@ -304,4 +354,4 @@ const KeuanganAnggaran = () => { ); }; -export default KeuanganAnggaran; \ No newline at end of file +export default KeuanganAnggaran; diff --git a/src/components/kinerja-divisi.tsx b/src/components/kinerja-divisi.tsx index f947352..efd504f 100644 --- a/src/components/kinerja-divisi.tsx +++ b/src/components/kinerja-divisi.tsx @@ -1,27 +1,38 @@ import { - Stack, + ActionIcon, + Box, + Card, + Divider, Grid, GridCol, Group, - Text, - Title, - ActionIcon, - Progress as MantineProgress, - Box, - Badge as MantineBadge, - Card, - useMantineColorScheme, - ThemeIcon, List, - Divider, - Skeleton + Badge as MantineBadge, + Progress as MantineProgress, + Skeleton, + Stack, + Text, + ThemeIcon, + Title, + useMantineColorScheme, } from "@mantine/core"; +import { + Bar, + BarChart, + CartesianGrid, + Cell, + Pie, + PieChart, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; import { Button } from "@/components/ui/button"; -import { Bar, BarChart, CartesianGrid, XAxis, YAxis, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from "recharts"; const KinerjaDivisi = () => { const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; + const dark = colorScheme === "dark"; // Data for division progress chart const divisionProgressData = [ @@ -39,7 +50,7 @@ const KinerjaDivisi = () => { { title: "Laporan Bulanan", status: "selesai" }, { title: "Arsip Dokumen", status: "berjalan" }, { title: "Undangan Rapat", status: "tertunda" }, - ] + ], }, { name: "Keuangan", @@ -47,7 +58,7 @@ const KinerjaDivisi = () => { { title: "Laporan APBDes", status: "selesai" }, { title: "Verifikasi Dana", status: "tertunda" }, { title: "Pengeluaran Harian", status: "berjalan" }, - ] + ], }, { name: "Sosial", @@ -55,7 +66,7 @@ const KinerjaDivisi = () => { { title: "Program Bantuan", status: "selesai" }, { title: "Kegiatan Posyandu", status: "berjalan" }, { title: "Monitoring Stunting", status: "tertunda" }, - ] + ], }, { name: "Humas", @@ -63,7 +74,7 @@ const KinerjaDivisi = () => { { title: "Publikasi Kegiatan", status: "selesai" }, { title: "Koordinasi Media", status: "berjalan" }, { title: "Laporan Kegiatan", status: "tertunda" }, - ] + ], }, ]; @@ -77,10 +88,30 @@ const KinerjaDivisi = () => { // 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" }, + { + 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 @@ -97,19 +128,31 @@ const KinerjaDivisi = () => { { name: "Dibatalkan", value: 2 }, ]; - const COLORS = ['#10B981', '#F59E0B', '#EF4444', '#6B7280']; + const COLORS = ["#10B981", "#F59E0B", "#EF4444", "#6B7280"]; const STATUS_COLORS: Record = { - selesai: 'green', - berjalan: 'blue', - tertunda: 'red', - proses: 'yellow' + 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" }, + { + 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 @@ -121,32 +164,73 @@ const KinerjaDivisi = () => { return ( {/* Grafik Progres Tugas per Divisi */} - - + <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 - + + + + - - - @@ -155,17 +239,26 @@ const KinerjaDivisi = () => { {divisionTasks.map((division, index) => ( - - + <Card + p="md" + radius="md" + withBorder + bg={dark ? "#141D34" : "white"} + style={{ borderColor: dark ? "#141D34" : "white" }} + h="100%" + > + <Title order={4} mb="sm" c={dark ? "white" : "darmasaba-navy"}> {division.name} {division.tasks.map((task, taskIndex) => ( - {task.title} + + {task.title} + {task.status} @@ -180,17 +273,33 @@ const KinerjaDivisi = () => { {/* Arsip Digital Perangkat Desa */} - - + <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"}> Arsip Digital Perangkat Desa {archiveItems.map((item, index) => ( - + - {item.name} - {item.count} + + {item.name} + + + {item.count} + @@ -199,17 +308,32 @@ const KinerjaDivisi = () => { {/* Kartu Progres 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"}> Progres Kegiatan / Program {activityProgress.map((activity, index) => ( - + - {activity.name} + + {activity.name} + {activity.status} @@ -223,9 +347,13 @@ const KinerjaDivisi = () => { color={activity.progress === 100 ? "green" : "blue"} w="calc(100% - 80px)" /> - {activity.progress}% + + {activity.progress}% + - {activity.date} + + {activity.date} + ))} @@ -234,38 +362,75 @@ const KinerjaDivisi = () => { {/* Statistik Dokumen & Progres 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"}> Jumlah Dokumen - + + - - - + <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 @@ -278,16 +443,26 @@ const KinerjaDivisi = () => { outerRadius={80} fill="#8884d8" dataKey="value" - label={({ name, percent }) => `${name}: ${percent ? (percent * 100).toFixed(0) : '0'}%`} + label={({ name, percent }) => + `${name}: ${percent ? (percent * 100).toFixed(0) : "0"}%` + } > {activityProgressStats.map((entry, index) => ( - + ))} @@ -296,26 +471,51 @@ const KinerjaDivisi = () => { {/* Diskusi Internal */} - - + <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"}> Diskusi Internal {discussions.map((discussion, index) => ( - + - {discussion.title} - {discussion.timestamp} + + {discussion.title} + + + {discussion.timestamp} + - {discussion.sender} + + {discussion.sender} + ))} {/* Agenda / Acara Hari Ini */} - - + <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"}> Agenda / Acara Hari Ini {todayAgenda.length > 0 ? ( @@ -326,7 +526,9 @@ const KinerjaDivisi = () => { {agenda.time} - {agenda.event} + + {agenda.event} + ))} @@ -340,4 +542,4 @@ const KinerjaDivisi = () => { ); }; -export default KinerjaDivisi; \ No newline at end of file +export default KinerjaDivisi; diff --git a/src/components/pengaduan-layanan-publik.tsx b/src/components/pengaduan-layanan-publik.tsx index 268af30..cafff0d 100644 --- a/src/components/pengaduan-layanan-publik.tsx +++ b/src/components/pengaduan-layanan-publik.tsx @@ -1,38 +1,54 @@ -import type React from "react"; -import { useState } from "react"; import { + ActionIcon, + Badge, + Box, Button, Card, + Divider, Grid, GridCol, Group, - Text, - Title, - TextInput, - Textarea, - Select, - Table, - Badge, - Stack, - useMantineColorScheme, List, - Divider, - ActionIcon, - Box + Select, + Stack, + Table, + Text, + Textarea, + TextInput, + Title, + useMantineColorScheme, } from "@mantine/core"; -import { IconMessage, IconAlertTriangle, IconClock, IconCheck, IconChevronRight } from "@tabler/icons-react"; -import { Line, LineChart, Bar, BarChart, CartesianGrid, XAxis, YAxis, Tooltip, ResponsiveContainer } from "recharts"; +import { + IconAlertTriangle, + IconCheck, + IconChevronRight, + IconClock, + IconMessage, +} from "@tabler/icons-react"; +import type React from "react"; +import { useState } from "react"; +import { + Bar, + BarChart, + CartesianGrid, + Line, + LineChart, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; const PengaduanLayananPublik = () => { const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; + const dark = colorScheme === "dark"; // Summary data const summaryData = { total: 42, baru: 14, diproses: 14, - selesai: 14 + selesai: 14, }; // Tren pengaduan data @@ -42,7 +58,7 @@ const PengaduanLayananPublik = () => { { bulan: "Mar", jumlah: 42 }, { bulan: "Apr", jumlah: 38 }, { bulan: "Mei", jumlah: 45 }, - { bulan: "Jun", jumlah: 42 } + { bulan: "Jun", jumlah: 42 }, ]; // Surat terbanyak data @@ -51,24 +67,65 @@ const PengaduanLayananPublik = () => { { jenis: "KK", jumlah: 18 }, { jenis: "Domisili", jumlah: 15 }, { jenis: "Usaha", jumlah: 12 }, - { jenis: "Lainnya", jumlah: 8 } + { jenis: "Lainnya", jumlah: 8 }, ]; // Pengajuan terbaru data const pengajuanTerbaru = [ - { nama: "Budi Santoso", jenis: "Ketertiban Umum", waktu: "2 jam yang lalu", status: "baru" }, - { nama: "Siti Rahayu", jenis: "Pelayanan Kesehatan", waktu: "5 jam yang lalu", status: "diproses" }, - { nama: "Ahmad Fauzi", jenis: "Infrastruktur", waktu: "1 hari yang lalu", status: "selesai" }, - { nama: "Dewi Lestari", jenis: "Administrasi", waktu: "1 hari yang lalu", status: "baru" }, - { nama: "Joko Widodo", jenis: "Keamanan", waktu: "2 hari yang lalu", status: "diproses" } + { + nama: "Budi Santoso", + jenis: "Ketertiban Umum", + waktu: "2 jam yang lalu", + status: "baru", + }, + { + nama: "Siti Rahayu", + jenis: "Pelayanan Kesehatan", + waktu: "5 jam yang lalu", + status: "diproses", + }, + { + nama: "Ahmad Fauzi", + jenis: "Infrastruktur", + waktu: "1 hari yang lalu", + status: "selesai", + }, + { + nama: "Dewi Lestari", + jenis: "Administrasi", + waktu: "1 hari yang lalu", + status: "baru", + }, + { + nama: "Joko Widodo", + jenis: "Keamanan", + waktu: "2 hari yang lalu", + status: "diproses", + }, ]; // Ide inovatif data const ideInovatif = [ - { nama: "Andi Prasetyo", judul: "Penerapan Smart Village", kategori: "Teknologi" }, - { nama: "Rina Kusuma", judul: "Program Ekowisata Desa", kategori: "Ekonomi" }, - { nama: "Bambang Suryono", judul: "Peningkatan Sanitasi", kategori: "Kesehatan" }, - { nama: "Lina Marlina", judul: "Pusat Kreatif Anak Muda", kategori: "Pendidikan" } + { + nama: "Andi Prasetyo", + judul: "Penerapan Smart Village", + kategori: "Teknologi", + }, + { + nama: "Rina Kusuma", + judul: "Program Ekowisata Desa", + kategori: "Ekonomi", + }, + { + nama: "Bambang Suryono", + judul: "Peningkatan Sanitasi", + kategori: "Kesehatan", + }, + { + nama: "Lina Marlina", + judul: "Pusat Kreatif Anak Muda", + kategori: "Pendidikan", + }, ]; const [activeTab, setActiveTab] = useState<"complaints" | "services">( @@ -229,10 +286,14 @@ const PengaduanLayananPublik = () => { // Status badge color mapping const getStatusColor = (status: string) => { switch (status) { - case 'baru': return 'red'; - case 'diproses': return 'yellow'; - case 'selesai': return 'green'; - default: return 'gray'; + case "baru": + return "red"; + case "diproses": + return "yellow"; + case "selesai": + return "green"; + default: + return "gray"; } }; @@ -243,7 +304,14 @@ const PengaduanLayananPublik = () => { {/* Summary Cards */} - + @@ -266,7 +334,14 @@ const PengaduanLayananPublik = () => { - + @@ -276,12 +351,7 @@ const PengaduanLayananPublik = () => { {summaryData.baru} - + @@ -289,7 +359,14 @@ const PengaduanLayananPublik = () => { - + @@ -299,12 +376,7 @@ const PengaduanLayananPublik = () => { {summaryData.diproses} - + @@ -312,7 +384,14 @@ const PengaduanLayananPublik = () => { - + @@ -322,12 +401,7 @@ const PengaduanLayananPublik = () => { {summaryData.selesai} - + @@ -336,7 +410,13 @@ const PengaduanLayananPublik = () => { {/* Grafik Tren Pengaduan */} - + Grafik Tren Pengaduan @@ -345,31 +425,58 @@ const PengaduanLayananPublik = () => { @@ -379,7 +486,14 @@ const PengaduanLayananPublik = () => { {/* Surat Terbanyak */} - + Surat Terbanyak @@ -388,30 +502,51 @@ const PengaduanLayananPublik = () => { @@ -421,7 +556,14 @@ const PengaduanLayananPublik = () => { {/* Pengajuan Terbaru */} - + Pengajuan Terbaru @@ -429,14 +571,23 @@ const PengaduanLayananPublik = () => { - {item.nama} - {item.jenis} + + {item.nama} + + + {item.jenis} + - + {item.status} - {item.waktu} + + {item.waktu} + @@ -447,7 +598,14 @@ const PengaduanLayananPublik = () => { {/* Ajuan Ide Inovatif */} - + Ajuan Ide Inovatif @@ -455,8 +613,12 @@ const PengaduanLayananPublik = () => { - {item.judul} - {item.nama} + + {item.judul} + + + {item.nama} + @@ -478,9 +640,18 @@ const PengaduanLayananPublik = () => { {/* Complaint Submission Form */} - + - Ajukan Pengaduan + + Ajukan Pengaduan +
@@ -537,24 +708,39 @@ const PengaduanLayananPublik = () => { {/* Complaints List */} - + - Daftar Pengaduan + + Daftar Pengaduan +
- Judul - Kategori - Status - Prioritas - Tanggal + + Judul + + + Kategori + + + Status + + + Prioritas + + + Tanggal + - - {complaintRows} - + {complaintRows}
@@ -565,15 +751,19 @@ const PengaduanLayananPublik = () => { - Layanan Publik Tersedia + + Layanan Publik Tersedia + {services.map((service) => ( - {service.name} - + + {service.name} + + {service.description} @@ -589,11 +779,11 @@ const PengaduanLayananPublik = () => { > {service.status} - + {service.category} - + Terakhir diperbarui: {service.lastUpdated} @@ -605,13 +795,17 @@ const PengaduanLayananPublik = () => { - Statistik Layanan + + Statistik Layanan + - Jumlah Layanan Tersedia + + Jumlah Layanan Tersedia + 12 @@ -619,7 +813,9 @@ const PengaduanLayananPublik = () => { - Layanan Terpopuler + + Layanan Terpopuler + 4 @@ -627,7 +823,9 @@ const PengaduanLayananPublik = () => { - Permintaan Baru + + Permintaan Baru + 23 @@ -642,4 +840,4 @@ const PengaduanLayananPublik = () => { ); }; -export default PengaduanLayananPublik; \ No newline at end of file +export default PengaduanLayananPublik; diff --git a/src/components/pengaturan/akses-dan-tim.tsx b/src/components/pengaturan/akses-dan-tim.tsx index 5b39465..80a8004 100644 --- a/src/components/pengaturan/akses-dan-tim.tsx +++ b/src/components/pengaturan/akses-dan-tim.tsx @@ -1,125 +1,190 @@ -import { Card, Title, Text, Space, Button, Group, Alert, Table, ActionIcon, Modal, TextInput, Select, useMantineColorScheme } from '@mantine/core'; -import { IconInfoCircle, IconUserPlus, IconTrash, IconEdit, IconUser } from '@tabler/icons-react'; -import { useState } from 'react'; +import { + ActionIcon, + Alert, + Button, + Card, + Group, + Modal, + Select, + Space, + Table, + Text, + TextInput, + Title, + useMantineColorScheme, +} from "@mantine/core"; +import { + IconEdit, + IconInfoCircle, + IconTrash, + IconUser, + IconUserPlus, +} from "@tabler/icons-react"; +import { useState } from "react"; const AksesDanTimSettings = () => { - const [opened, setOpened] = useState(false); - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; + const [opened, setOpened] = useState(false); + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; - // Sample team members data - const teamMembers = [ - { id: 1, name: 'Admin Utama', email: 'admin@desa.go.id', role: 'Administrator', status: 'Aktif' }, - { id: 2, name: 'Operator Desa', email: 'operator@desa.go.id', role: 'Operator', status: 'Aktif' }, - { id: 3, name: 'Staff Keuangan', email: 'keuangan@desa.go.id', role: 'Keuangan', status: 'Aktif' }, - { id: 4, name: 'Staff Umum', email: 'umum@desa.go.id', role: 'Umum', status: 'Nonaktif' }, - ]; + // Sample team members data + const teamMembers = [ + { + id: 1, + name: "Admin Utama", + email: "admin@desa.go.id", + role: "Administrator", + status: "Aktif", + }, + { + id: 2, + name: "Operator Desa", + email: "operator@desa.go.id", + role: "Operator", + status: "Aktif", + }, + { + id: 3, + name: "Staff Keuangan", + email: "keuangan@desa.go.id", + role: "Keuangan", + status: "Aktif", + }, + { + id: 4, + name: "Staff Umum", + email: "umum@desa.go.id", + role: "Umum", + status: "Nonaktif", + }, + ]; - const roles = [ - { value: 'administrator', label: 'Administrator' }, - { value: 'operator', label: 'Operator' }, - { value: 'keuangan', label: 'Keuangan' }, - { value: 'umum', label: 'Umum' }, - { value: 'keamanan', label: 'Keamanan' }, - ]; + const roles = [ + { value: "administrator", label: "Administrator" }, + { value: "operator", label: "Operator" }, + { value: "keuangan", label: "Keuangan" }, + { value: "umum", label: "Umum" }, + { value: "keamanan", label: "Keamanan" }, + ]; - return ( - - setOpened(false)} - title="Tambah Anggota Tim" - size="lg" - > - - - + + + + + - Akses & Tim - Kelola akses dan anggota tim Anda + + Akses & Tim + + + Kelola akses dan anggota tim Anda + - + - - Anggota Tim - - + + Anggota Tim + + - - - - Nama - Email - Peran - Status - Aksi - - - - {teamMembers.map((member) => ( - - - - - {member.name} - - - {member.email} - - {member.role} - - - - {member.status} - - - - - - - - - - - - - - ))} - -
+ + + + Nama + Email + Peran + Status + Aksi + + + + {teamMembers.map((member) => ( + + + + + {member.name} + + + {member.email} + + {member.role} + + + + {member.status} + + + + + + + + + + + + + + ))} + +
- + - } title="Informasi" color="blue" mb="md"> - Administrator memiliki akses penuh ke semua fitur. Peran lainnya memiliki akses terbatas sesuai kebutuhan. - + } + title="Informasi" + color="blue" + mb="md" + > + Administrator memiliki akses penuh ke semua fitur. Peran lainnya + memiliki akses terbatas sesuai kebutuhan. + - - - - -
- ); + + + + +
+ ); }; -export default AksesDanTimSettings; \ No newline at end of file +export default AksesDanTimSettings; diff --git a/src/components/pengaturan/keamanan.tsx b/src/components/pengaturan/keamanan.tsx index 6bd6f64..23eda15 100644 --- a/src/components/pengaturan/keamanan.tsx +++ b/src/components/pengaturan/keamanan.tsx @@ -1,57 +1,90 @@ -import { Card, Title, Text, Space, Button, Group, Alert, PasswordInput, Switch, useMantineColorScheme } from '@mantine/core'; -import { IconInfoCircle, IconLock } from '@tabler/icons-react'; +import { + Alert, + Button, + Card, + Group, + PasswordInput, + Space, + Switch, + Text, + Title, + useMantineColorScheme, +} from "@mantine/core"; +import { IconInfoCircle, IconLock } from "@tabler/icons-react"; const KeamananSettings = () => { - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; - return ( - - Pengaturan Keamanan - Kelola keamanan akun Anda + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + return ( + + + Pengaturan Keamanan + + + Kelola keamanan akun Anda + - + - + - + - + - + - - - - + + + + - + - } title="Keamanan" color="orange" mb="md"> - Gunakan kata sandi yang kuat dan unik. Hindari menggunakan kata sandi yang sama di banyak layanan. - + } + title="Keamanan" + color="orange" + mb="md" + > + Gunakan kata sandi yang kuat dan unik. Hindari menggunakan kata sandi + yang sama di banyak layanan. + - } title="Informasi" color="blue" mb="md"> - Setelah mengganti kata sandi, Anda akan diminta logout dari semua perangkat. - + } + title="Informasi" + color="blue" + mb="md" + > + Setelah mengganti kata sandi, Anda akan diminta logout dari semua + perangkat. + - - - - - - ); + + + + + + ); }; -export default KeamananSettings; \ No newline at end of file +export default KeamananSettings; diff --git a/src/components/pengaturan/notifikasi.tsx b/src/components/pengaturan/notifikasi.tsx index 38cb0de..37cbd83 100644 --- a/src/components/pengaturan/notifikasi.tsx +++ b/src/components/pengaturan/notifikasi.tsx @@ -1,55 +1,86 @@ -import { Card, Title, Text, Space, Switch, Group, Alert, Checkbox, Button, useMantineColorScheme } from '@mantine/core'; -import { IconInfoCircle } from '@tabler/icons-react'; +import { + Alert, + Button, + Card, + Checkbox, + Group, + Space, + Switch, + Text, + Title, + useMantineColorScheme, +} from "@mantine/core"; +import { IconInfoCircle } from "@tabler/icons-react"; const NotifikasiSettings = () => { - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; - return ( - - Pengaturan Notifikasi - Kelola preferensi notifikasi Anda + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + return ( + + + Pengaturan Notifikasi + + + Kelola preferensi notifikasi Anda + - + - - Metode Notifikasi - - - - - - + + + Metode Notifikasi + + + + + + + - + - - - - + + + + - + - Jenis Notifikasi - - - - - - - + + Jenis Notifikasi + + + + + + + + - + - } title="Tip" color="blue" mb="md"> - Anda dapat menyesuaikan frekuensi notifikasi mingguan sesuai kebutuhan Anda. - + } + title="Tip" + color="blue" + mb="md" + > + Anda dapat menyesuaikan frekuensi notifikasi mingguan sesuai kebutuhan + Anda. + - - - - - - ); + + + + + + ); }; -export default NotifikasiSettings; \ No newline at end of file +export default NotifikasiSettings; diff --git a/src/components/pengaturan/umum.tsx b/src/components/pengaturan/umum.tsx index 84c5c3c..2b6499d 100644 --- a/src/components/pengaturan/umum.tsx +++ b/src/components/pengaturan/umum.tsx @@ -1,58 +1,86 @@ -import { Card, Title, Text, Space, TextInput, Select, Button, Group, Switch, Alert, useMantineColorScheme } from '@mantine/core'; -import { IconInfoCircle } from '@tabler/icons-react'; +import { + Alert, + Button, + Card, + Group, + Select, + Space, + Switch, + Text, + TextInput, + Title, + useMantineColorScheme, +} from "@mantine/core"; +import { IconInfoCircle } from "@tabler/icons-react"; const UmumSettings = () => { - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; - return ( - - Pengaturan Umum - Kelola pengaturan umum aplikasi Anda + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + return ( + + + Pengaturan Umum + + + Kelola pengaturan umum aplikasi Anda + - + - + - - - - - + + + - } title="Informasi" color="blue" mb="md"> - Beberapa pengaturan mungkin memerlukan restart aplikasi untuk diterapkan sepenuhnya. - + } + title="Informasi" + color="blue" + mb="md" + > + Beberapa pengaturan mungkin memerlukan restart aplikasi untuk diterapkan + sepenuhnya. + - - - - - - ); + + + + + + ); }; -export default UmumSettings; \ No newline at end of file +export default UmumSettings; diff --git a/src/components/sidebar.tsx b/src/components/sidebar.tsx index 43b3730..67a85c6 100644 --- a/src/components/sidebar.tsx +++ b/src/components/sidebar.tsx @@ -1,16 +1,16 @@ -import { useNavigate, useLocation } from "@tanstack/react-router"; -import { Search, ChevronDown, ChevronUp } from "lucide-react"; import { - Stack, - Group, - Text, Badge, + Box, + Collapse, + Group, Input, NavLink as MantineNavLink, - Box, + Stack, + Text, useMantineColorScheme, - Collapse, } from "@mantine/core"; +import { useLocation, useNavigate } from "@tanstack/react-router"; +import { ChevronDown, ChevronUp, Search } from "lucide-react"; import { useState } from "react"; interface SidebarProps { @@ -21,46 +21,49 @@ export function Sidebar({ className }: SidebarProps) { const location = useLocation(); const navigate = useNavigate(); const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; - const isActiveBg = colorScheme === 'dark' ? "#182949" : "#E6F0FF"; - const isActiveBorder = colorScheme === 'dark' ? "#00398D" : "#1F41AE"; - + const dark = colorScheme === "dark"; + const isActiveBg = colorScheme === "dark" ? "#182949" : "#E6F0FF"; + const isActiveBorder = colorScheme === "dark" ? "#00398D" : "#1F41AE"; + // State for settings submenu collapse const [settingsOpen, setSettingsOpen] = useState( - location.pathname.startsWith('/dashboard/pengaturan') + location.pathname.startsWith("/pengaturan"), ); // Define menu items with their paths const menuItems = [ - { name: "Beranda", path: "/dashboard" }, - { name: "Kinerja Divisi", path: "/dashboard/kinerja-divisi" }, - { name: "Pengaduan & Layanan Publik", path: "/dashboard/pengaduan-layanan-publik" }, - { name: "Jenna Analytic", path: "/dashboard/jenna-analytic" }, - { name: "Demografi & Kependudukan", path: "/dashboard/demografi-pekerjaan" }, - { name: "Keuangan & Anggaran", path: "/dashboard/keuangan-anggaran" }, - { name: "Bumdes & UMKM Desa", path: "/dashboard/bumdes" }, - { name: "Sosial", path: "/dashboard/sosial" }, - { name: "Keamanan", path: "/dashboard/keamanan" }, - { name: "Bantuan", path: "/dashboard/bantuan" }, + { name: "Beranda", path: "/" }, + { name: "Kinerja Divisi", path: "/kinerja-divisi" }, + { name: "Pengaduan & Layanan Publik", path: "/pengaduan-layanan-publik" }, + { name: "Jenna Analytic", path: "/jenna-analytic" }, + { name: "Demografi & Kependudukan", path: "/demografi-pekerjaan" }, + { name: "Keuangan & Anggaran", path: "/keuangan-anggaran" }, + { name: "Bumdes & UMKM Desa", path: "/bumdes" }, + { name: "Sosial", path: "/sosial" }, + { name: "Keamanan", path: "/keamanan" }, + { name: "Bantuan", path: "/bantuan" }, ]; // Settings submenu items const settingsItems = [ - { name: "Umum", path: "/dashboard/pengaturan/umum" }, - { name: "Notifikasi", path: "/dashboard/pengaturan/notifikasi" }, - { name: "Keamanan", path: "/dashboard/pengaturan/keamanan" }, - { name: "Akses & Tim", path: "/dashboard/pengaturan/akses-dan-tim" }, + { name: "Umum", path: "/pengaturan/umum" }, + { name: "Notifikasi", path: "/pengaturan/notifikasi" }, + { name: "Keamanan", path: "/pengaturan/keamanan" }, + { name: "Akses & Tim", path: "/pengaturan/akses-dan-tim" }, ]; // Check if any settings submenu is active - const isSettingsActive = settingsItems.some(item => - location.pathname === item.path + const isSettingsActive = settingsItems.some( + (item) => location.pathname === item.path, ); return ( {/* Logo */} - + ); @@ -132,7 +137,9 @@ export function Sidebar({ className }: SidebarProps) { setSettingsOpen(!settingsOpen)} - rightSection={settingsOpen ? : } + rightSection={ + settingsOpen ? : + } label="Pengaturan" active={isSettingsActive} variant="subtle" @@ -140,7 +147,9 @@ export function Sidebar({ className }: SidebarProps) { style={{ background: isSettingsActive ? isActiveBg : "transparent", fontWeight: isSettingsActive ? "bold" : "normal", - borderLeft: isSettingsActive ? `4px solid ${isActiveBorder}` : "4px solid transparent", + borderLeft: isSettingsActive + ? `4px solid ${isActiveBorder}` + : "4px solid transparent", borderRadius: "8px", transition: "all 200ms ease", margin: "2px 0", @@ -149,12 +158,16 @@ export function Sidebar({ className }: SidebarProps) { body: { "&:hover": { background: "#F1F5F9", - } - } + }, + }, }} /> - + {settingsItems.map((item, index) => { const isActive = location.pathname === item.path; return ( @@ -168,7 +181,9 @@ export function Sidebar({ className }: SidebarProps) { style={{ background: isActive ? isActiveBg : "transparent", fontWeight: isActive ? "bold" : "normal", - borderLeft: isActive ? `4px solid ${isActiveBorder}` : "4px solid transparent", + borderLeft: isActive + ? `4px solid ${isActiveBorder}` + : "4px solid transparent", borderRadius: "8px", transition: "all 200ms ease", margin: "2px 0", @@ -177,8 +192,8 @@ export function Sidebar({ className }: SidebarProps) { body: { "&:hover": { background: "#F1F5F9", - } - } + }, + }, }} /> ); diff --git a/src/components/sosial-page.tsx b/src/components/sosial-page.tsx index 7df45f0..c313fac 100644 --- a/src/components/sosial-page.tsx +++ b/src/components/sosial-page.tsx @@ -1,289 +1,465 @@ -import { useState } from "react"; -import { - Card, - Grid, - GridCol, - Group, - Text, - Title, - Progress, - Stack, - useMantineColorScheme, - Badge, - List, - ThemeIcon +import { + Badge, + Card, + Grid, + GridCol, + Group, + List, + Progress, + Stack, + Text, + ThemeIcon, + Title, + useMantineColorScheme, } from "@mantine/core"; -import { - IconHeartbeat, - IconBabyCarriage, - IconStethoscope, - IconMedicalCross, - IconSchool, - IconBook, - IconCalendarEvent, - IconAward +import { + IconAward, + IconBabyCarriage, + IconBook, + IconCalendarEvent, + IconHeartbeat, + IconMedicalCross, + IconSchool, + IconStethoscope, } from "@tabler/icons-react"; +import { useState } from "react"; const SosialPage = () => { - const { colorScheme } = useMantineColorScheme(); - const dark = colorScheme === 'dark'; - - // Sample data for health statistics - const healthStats = { - ibuHamil: 87, - balita: 342, - alertStunting: 12, - posyanduAktif: 8, - }; + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; - // Sample data for health progress - const healthProgress = [ - { label: "Imunisasi Lengkap", value: 92, color: "green" }, - { label: "Pemeriksaan Rutin", value: 88, color: "blue" }, - { label: "Gizi Baik", value: 86, color: "teal" }, - { label: "Target Stunting", value: 14, color: "red" }, - ]; + // Sample data for health statistics + const healthStats = { + ibuHamil: 87, + balita: 342, + alertStunting: 12, + posyanduAktif: 8, + }; - // Sample data for posyandu schedule - const posyanduSchedule = [ - { nama: "Posyandu Mawar", tanggal: "Senin, 15 Feb 2026", jam: "08:00 - 11:00" }, - { nama: "Posyandu Melati", tanggal: "Selasa, 16 Feb 2026", jam: "08:00 - 11:00" }, - { nama: "Posyandu Dahlia", tanggal: "Rabu, 17 Feb 2026", jam: "08:00 - 11:00" }, - { nama: "Posyandu Anggrek", tanggal: "Kamis, 18 Feb 2026", jam: "08:00 - 11:00" }, - ]; + // Sample data for health progress + const healthProgress = [ + { label: "Imunisasi Lengkap", value: 92, color: "green" }, + { label: "Pemeriksaan Rutin", value: 88, color: "blue" }, + { label: "Gizi Baik", value: 86, color: "teal" }, + { label: "Target Stunting", value: 14, color: "red" }, + ]; - // Sample data for education stats - const educationStats = { - siswa: { - tk: 125, - sd: 480, - smp: 210, - sma: 150, - }, - sekolah: { - jumlah: 8, - guru: 42, - } - }; + // Sample data for posyandu schedule + const posyanduSchedule = [ + { + nama: "Posyandu Mawar", + tanggal: "Senin, 15 Feb 2026", + jam: "08:00 - 11:00", + }, + { + nama: "Posyandu Melati", + tanggal: "Selasa, 16 Feb 2026", + jam: "08:00 - 11:00", + }, + { + nama: "Posyandu Dahlia", + tanggal: "Rabu, 17 Feb 2026", + jam: "08:00 - 11:00", + }, + { + nama: "Posyandu Anggrek", + tanggal: "Kamis, 18 Feb 2026", + jam: "08:00 - 11:00", + }, + ]; - // Sample data for scholarships - const scholarshipData = { - penerima: 45, - dana: "Rp 1.200.000.000", - tahunAjaran: "2025/2026", - }; + // Sample data for education stats + const educationStats = { + siswa: { + tk: 125, + sd: 480, + smp: 210, + sma: 150, + }, + sekolah: { + jumlah: 8, + guru: 42, + }, + }; - // Sample data for cultural events - const culturalEvents = [ - { nama: "Hari Kesaktian Pancasila", tanggal: "1 Oktober 2025", lokasi: "Balai Desa" }, - { nama: "Festival Budaya Desa", tanggal: "20 Mei 2026", lokasi: "Lapangan Desa" }, - { nama: "Perayaan HUT Desa", tanggal: "17 Agustus 2026", lokasi: "Balai Desa" }, - ]; + // Sample data for scholarships + const scholarshipData = { + penerima: 45, + dana: "Rp 1.200.000.000", + tahunAjaran: "2025/2026", + }; - return ( - - {/* Health Statistics Cards */} - - - - - - - Ibu Hamil Aktif - - - {healthStats.ibuHamil} - - - - - - - - + // Sample data for cultural events + const culturalEvents = [ + { + nama: "Hari Kesaktian Pancasila", + tanggal: "1 Oktober 2025", + lokasi: "Balai Desa", + }, + { + nama: "Festival Budaya Desa", + tanggal: "20 Mei 2026", + lokasi: "Lapangan Desa", + }, + { + nama: "Perayaan HUT Desa", + tanggal: "17 Agustus 2026", + lokasi: "Balai Desa", + }, + ]; - - - - - - Balita Terdaftar - - - {healthStats.balita} - - - - - - - - + return ( + + {/* Health Statistics Cards */} + + + + + + + Ibu Hamil Aktif + + + {healthStats.ibuHamil} + + + + + + + + - - - - - - Alert Stunting - - - {healthStats.alertStunting} - - - - - - - - + + + + + + Balita Terdaftar + + + {healthStats.balita} + + + + + + + + - - - - - - Posyandu Aktif - - - {healthStats.posyanduAktif} - - - - - - - - - + + + + + + Alert Stunting + + + {healthStats.alertStunting} + + + + + + + + - {/* Health Progress Bars */} - - Statistik Kesehatan - - {healthProgress.map((item, index) => ( -
- - - {item.label} - - - {item.value}% - - - -
- ))} -
-
+ + + + + + Posyandu Aktif + + + {healthStats.posyanduAktif} + + + + + + + + +
- - {/* Jadwal Posyandu */} - - - Jadwal Posyandu - - {posyanduSchedule.map((item, index) => ( - - - - {item.nama} - {item.tanggal} - - - {item.jam} - - - - ))} - - - + {/* Health Progress Bars */} + + + Statistik Kesehatan + + + {healthProgress.map((item, index) => ( +
+ + + {item.label} + + + {item.value}% + + + +
+ ))} +
+
- {/* Pendidikan */} - - - Pendidikan - - - TK / PAUD - {educationStats.siswa.tk} - - - SD - {educationStats.siswa.sd} - - - SMP - {educationStats.siswa.smp} - - - SMA - {educationStats.siswa.sma} - - - - - Jumlah Lembaga Pendidikan - {educationStats.sekolah.jumlah} - - - Jumlah Tenaga Pengajar - {educationStats.sekolah.guru} - - - - - -
+ + {/* Jadwal Posyandu */} + + + + Jadwal Posyandu + + + {posyanduSchedule.map((item, index) => ( + + + + + {item.nama} + + + {item.tanggal} + + + + {item.jam} + + + + ))} + + + - - {/* Beasiswa Desa */} - - - - - Beasiswa Desa - Penerima: {scholarshipData.penerima} - - - - - - Dana Tersalurkan: {scholarshipData.dana} - Tahun Ajaran: {scholarshipData.tahunAjaran} - - + {/* Pendidikan */} + + + + Pendidikan + + + + + TK / PAUD + + + {educationStats.siswa.tk} + + + + + SD + + + {educationStats.siswa.sd} + + + + + SMP + + + {educationStats.siswa.smp} + + + + + SMA + + + {educationStats.siswa.sma} + + - {/* Kalender Event Budaya */} - - - Kalender Event Budaya - - {culturalEvents.map((event, index) => ( - - - - }> - - {event.nama} - {event.lokasi} - - {event.tanggal} - - ))} - - - - -
- ); + + + + Jumlah Lembaga Pendidikan + + + {educationStats.sekolah.jumlah} + + + + + Jumlah Tenaga Pengajar + + + {educationStats.sekolah.guru} + + + +
+
+
+
+ + + {/* Beasiswa Desa */} + + + + + + Beasiswa Desa + + + Penerima: {scholarshipData.penerima} + + + + + + + + Dana Tersalurkan:{" "} + + {scholarshipData.dana} + + + + Tahun Ajaran: {scholarshipData.tahunAjaran} + + + + + {/* Kalender Event Budaya */} + + + + Kalender Event Budaya + + + {culturalEvents.map((event, index) => ( + + + + } + > + + + {event.nama} + + + {event.lokasi} + + + + {event.tanggal} + + + ))} + + + + +
+ ); }; -export default SosialPage; \ No newline at end of file +export default SosialPage; diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx index bac49f9..bf2913b 100644 --- a/src/components/ui/card.tsx +++ b/src/components/ui/card.tsx @@ -2,7 +2,6 @@ import { Box, Card as MantineCard, type CardProps as MantineCardProps, - Title, } from "@mantine/core"; import type React from "react"; diff --git a/src/components/ui/help-card.tsx b/src/components/ui/help-card.tsx index 844c4b3..08f2448 100644 --- a/src/components/ui/help-card.tsx +++ b/src/components/ui/help-card.tsx @@ -1,90 +1,86 @@ -import { Card, useMantineTheme, useComputedColorScheme } from '@mantine/core'; -import type { CardProps } from '@mantine/core'; -import type { ReactNode } from 'react'; +import type { CardProps } from "@mantine/core"; +import { Card, useComputedColorScheme, useMantineTheme } from "@mantine/core"; +import type { ReactNode } from "react"; interface HelpCardProps extends CardProps { - children: ReactNode; - icon?: ReactNode; - title?: string; - minHeight?: string | number; // Allow specifying a minimum height + children: ReactNode; + icon?: ReactNode; + title?: string; + minHeight?: string | number; // Allow specifying a minimum height } export const HelpCard = ({ - children, - icon, - title, - minHeight = 'auto', // Default to auto, but allow override - ...props + children, + icon, + title, + minHeight = "auto", // Default to auto, but allow override + ...props }: HelpCardProps) => { - const theme = useMantineTheme(); - const colorScheme = useComputedColorScheme('light'); - const isDark = colorScheme === 'dark'; + const theme = useMantineTheme(); + const colorScheme = useComputedColorScheme("light"); + const isDark = colorScheme === "dark"; - return ( - - {(icon || title) && ( -
- {icon && ( -
- {icon} -
- )} + return ( + + {(icon || title) && ( +
+ {icon && ( +
+ {icon} +
+ )} - {title && ( -

- {title} -

- )} -
- )} + {title && ( +

+ {title} +

+ )} +
+ )} -
- {children} -
-
- ); +
{children}
+
+ ); }; diff --git a/src/frontend.tsx b/src/frontend.tsx index 568e20f..347e765 100644 --- a/src/frontend.tsx +++ b/src/frontend.tsx @@ -14,10 +14,9 @@ import { Inspector } from "react-dev-inspector"; import { createRoot } from "react-dom/client"; import { routeTree } from "./routeTree.gen"; import "./index.css"; -import '@mantine/charts/styles.css'; +import "@mantine/charts/styles.css"; import { IS_DEV, VITE_PUBLIC_URL } from "./utils/env"; - // Create a new router instance export const router = createRouter({ routeTree, @@ -102,8 +101,6 @@ const theme = createTheme({ primaryColor: "darmasaba-blue", }); - - const InspectorWrapper = IS_DEV ? Inspector : ({ children }: { children: React.ReactNode }) => <>{children}; diff --git a/src/index.css b/src/index.css index a461c50..f1d8c73 100644 --- a/src/index.css +++ b/src/index.css @@ -1 +1 @@ -@import "tailwindcss"; \ No newline at end of file +@import "tailwindcss"; diff --git a/src/middleware/authMiddleware.tsx b/src/middleware/authMiddleware.tsx index 021e26e..08e9bd0 100644 --- a/src/middleware/authMiddleware.tsx +++ b/src/middleware/authMiddleware.tsx @@ -60,16 +60,39 @@ type RouteRule = { }; const routeRules: RouteRule[] = [ + // Public routes - no auth required + { + match: (p) => p === "/" || p === "/signin" || p === "/signup", + requireAuth: false, + }, + // Profile routes - auth required for all roles { match: (p) => p === "/profile" || p.startsWith("/profile/"), requireAuth: true, redirectTo: "/signin", }, + // Dashboard and main pages - auth required for all roles (not just admin) { - match: (p) => p === "/dashboard" || p.startsWith("/dashboard/"), + match: (p) => + p.startsWith("/kinerja-divisi") || + p.startsWith("/pengaduan") || + p.startsWith("/jenna") || + p.startsWith("/demografi") || + p.startsWith("/keuangan") || + p.startsWith("/bumdes") || + p.startsWith("/sosial") || + p.startsWith("/keamanan") || + p.startsWith("/bantuan") || + p.startsWith("/pengaturan"), + requireAuth: true, + redirectTo: "/signin", + }, + // Admin routes - auth required with admin role only + { + match: (p) => p.startsWith("/admin"), requireAuth: true, requiredRole: "admin", - redirectTo: "/profile", + redirectTo: "/signin", }, ]; @@ -98,15 +121,22 @@ export function createProtectedRoute(options: ProtectedRouteOptions = {}) { location: { pathname: string; href: string }; }) => { const rule = findRouteRule(location.pathname); + + // If no rule matches, allow access by default if (!rule) return; + // If route explicitly doesn't require auth, allow access + if (rule.requireAuth === false) return; + const session = await fetchSession(); const user = session?.user; + // If auth is required but user is not logged in, redirect to login if (rule.requireAuth && !user) { redirectToLogin(rule.redirectTo ?? redirectTo, location.href); } + // If specific role is required, check it if (rule.requiredRole && user?.role !== rule.requiredRole) { redirectToLogin(rule.redirectTo ?? redirectTo, location.href); } diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 73af1b5..71bd866 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -9,35 +9,38 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' +import { Route as SosialRouteImport } from './routes/sosial' import { Route as SignupRouteImport } from './routes/signup' import { Route as SigninRouteImport } from './routes/signin' -import { Route as DashboardRouteRouteImport } from './routes/dashboard/route' +import { Route as PengaduanLayananPublikRouteImport } from './routes/pengaduan-layanan-publik' +import { Route as KinerjaDivisiRouteImport } from './routes/kinerja-divisi' +import { Route as KeuanganAnggaranRouteImport } from './routes/keuangan-anggaran' +import { Route as KeamananRouteImport } from './routes/keamanan' +import { Route as JennaAnalyticRouteImport } from './routes/jenna-analytic' +import { Route as DemografiPekerjaanRouteImport } from './routes/demografi-pekerjaan' +import { Route as BumdesRouteImport } from './routes/bumdes' +import { Route as BantuanRouteImport } from './routes/bantuan' +import { Route as PengaturanRouteRouteImport } from './routes/pengaturan/route' import { Route as AdminRouteRouteImport } from './routes/admin/route' import { Route as IndexRouteImport } from './routes/index' import { Route as UsersIndexRouteImport } from './routes/users/index' import { Route as ProfileIndexRouteImport } from './routes/profile/index' -import { Route as DashboardIndexRouteImport } from './routes/dashboard/index' import { Route as AdminIndexRouteImport } from './routes/admin/index' import { Route as UsersIdRouteImport } from './routes/users/$id' import { Route as ProfileEditRouteImport } from './routes/profile/edit' -import { Route as DashboardSosialRouteImport } from './routes/dashboard/sosial' -import { Route as DashboardPengaduanLayananPublikRouteImport } from './routes/dashboard/pengaduan-layanan-publik' -import { Route as DashboardKinerjaDivisiRouteImport } from './routes/dashboard/kinerja-divisi' -import { Route as DashboardKeuanganAnggaranRouteImport } from './routes/dashboard/keuangan-anggaran' -import { Route as DashboardKeamananRouteImport } from './routes/dashboard/keamanan' -import { Route as DashboardJennaAnalyticRouteImport } from './routes/dashboard/jenna-analytic' -import { Route as DashboardDemografiPekerjaanRouteImport } from './routes/dashboard/demografi-pekerjaan' -import { Route as DashboardBumdesRouteImport } from './routes/dashboard/bumdes' -import { Route as DashboardBantuanRouteImport } from './routes/dashboard/bantuan' +import { Route as PengaturanUmumRouteImport } from './routes/pengaturan/umum' +import { Route as PengaturanNotifikasiRouteImport } from './routes/pengaturan/notifikasi' +import { Route as PengaturanKeamananRouteImport } from './routes/pengaturan/keamanan' +import { Route as PengaturanAksesDanTimRouteImport } from './routes/pengaturan/akses-dan-tim' import { Route as AdminUsersRouteImport } from './routes/admin/users' import { Route as AdminSettingsRouteImport } from './routes/admin/settings' import { Route as AdminApikeyRouteImport } from './routes/admin/apikey' -import { Route as DashboardPengaturanRouteRouteImport } from './routes/dashboard/pengaturan/route' -import { Route as DashboardPengaturanUmumRouteImport } from './routes/dashboard/pengaturan/umum' -import { Route as DashboardPengaturanNotifikasiRouteImport } from './routes/dashboard/pengaturan/notifikasi' -import { Route as DashboardPengaturanKeamananRouteImport } from './routes/dashboard/pengaturan/keamanan' -import { Route as DashboardPengaturanAksesDanTimRouteImport } from './routes/dashboard/pengaturan/akses-dan-tim' +const SosialRoute = SosialRouteImport.update({ + id: '/sosial', + path: '/sosial', + getParentRoute: () => rootRouteImport, +} as any) const SignupRoute = SignupRouteImport.update({ id: '/signup', path: '/signup', @@ -48,9 +51,49 @@ const SigninRoute = SigninRouteImport.update({ path: '/signin', getParentRoute: () => rootRouteImport, } as any) -const DashboardRouteRoute = DashboardRouteRouteImport.update({ - id: '/dashboard', - path: '/dashboard', +const PengaduanLayananPublikRoute = PengaduanLayananPublikRouteImport.update({ + id: '/pengaduan-layanan-publik', + path: '/pengaduan-layanan-publik', + getParentRoute: () => rootRouteImport, +} as any) +const KinerjaDivisiRoute = KinerjaDivisiRouteImport.update({ + id: '/kinerja-divisi', + path: '/kinerja-divisi', + getParentRoute: () => rootRouteImport, +} as any) +const KeuanganAnggaranRoute = KeuanganAnggaranRouteImport.update({ + id: '/keuangan-anggaran', + path: '/keuangan-anggaran', + getParentRoute: () => rootRouteImport, +} as any) +const KeamananRoute = KeamananRouteImport.update({ + id: '/keamanan', + path: '/keamanan', + getParentRoute: () => rootRouteImport, +} as any) +const JennaAnalyticRoute = JennaAnalyticRouteImport.update({ + id: '/jenna-analytic', + path: '/jenna-analytic', + getParentRoute: () => rootRouteImport, +} as any) +const DemografiPekerjaanRoute = DemografiPekerjaanRouteImport.update({ + id: '/demografi-pekerjaan', + path: '/demografi-pekerjaan', + getParentRoute: () => rootRouteImport, +} as any) +const BumdesRoute = BumdesRouteImport.update({ + id: '/bumdes', + path: '/bumdes', + getParentRoute: () => rootRouteImport, +} as any) +const BantuanRoute = BantuanRouteImport.update({ + id: '/bantuan', + path: '/bantuan', + getParentRoute: () => rootRouteImport, +} as any) +const PengaturanRouteRoute = PengaturanRouteRouteImport.update({ + id: '/pengaturan', + path: '/pengaturan', getParentRoute: () => rootRouteImport, } as any) const AdminRouteRoute = AdminRouteRouteImport.update({ @@ -73,11 +116,6 @@ const ProfileIndexRoute = ProfileIndexRouteImport.update({ path: '/profile/', getParentRoute: () => rootRouteImport, } as any) -const DashboardIndexRoute = DashboardIndexRouteImport.update({ - id: '/', - path: '/', - getParentRoute: () => DashboardRouteRoute, -} as any) const AdminIndexRoute = AdminIndexRouteImport.update({ id: '/', path: '/', @@ -93,53 +131,25 @@ const ProfileEditRoute = ProfileEditRouteImport.update({ path: '/profile/edit', getParentRoute: () => rootRouteImport, } as any) -const DashboardSosialRoute = DashboardSosialRouteImport.update({ - id: '/sosial', - path: '/sosial', - getParentRoute: () => DashboardRouteRoute, +const PengaturanUmumRoute = PengaturanUmumRouteImport.update({ + id: '/umum', + path: '/umum', + getParentRoute: () => PengaturanRouteRoute, } as any) -const DashboardPengaduanLayananPublikRoute = - DashboardPengaduanLayananPublikRouteImport.update({ - id: '/pengaduan-layanan-publik', - path: '/pengaduan-layanan-publik', - getParentRoute: () => DashboardRouteRoute, - } as any) -const DashboardKinerjaDivisiRoute = DashboardKinerjaDivisiRouteImport.update({ - id: '/kinerja-divisi', - path: '/kinerja-divisi', - getParentRoute: () => DashboardRouteRoute, +const PengaturanNotifikasiRoute = PengaturanNotifikasiRouteImport.update({ + id: '/notifikasi', + path: '/notifikasi', + getParentRoute: () => PengaturanRouteRoute, } as any) -const DashboardKeuanganAnggaranRoute = - DashboardKeuanganAnggaranRouteImport.update({ - id: '/keuangan-anggaran', - path: '/keuangan-anggaran', - getParentRoute: () => DashboardRouteRoute, - } as any) -const DashboardKeamananRoute = DashboardKeamananRouteImport.update({ +const PengaturanKeamananRoute = PengaturanKeamananRouteImport.update({ id: '/keamanan', path: '/keamanan', - getParentRoute: () => DashboardRouteRoute, + getParentRoute: () => PengaturanRouteRoute, } as any) -const DashboardJennaAnalyticRoute = DashboardJennaAnalyticRouteImport.update({ - id: '/jenna-analytic', - path: '/jenna-analytic', - getParentRoute: () => DashboardRouteRoute, -} as any) -const DashboardDemografiPekerjaanRoute = - DashboardDemografiPekerjaanRouteImport.update({ - id: '/demografi-pekerjaan', - path: '/demografi-pekerjaan', - getParentRoute: () => DashboardRouteRoute, - } as any) -const DashboardBumdesRoute = DashboardBumdesRouteImport.update({ - id: '/bumdes', - path: '/bumdes', - getParentRoute: () => DashboardRouteRoute, -} as any) -const DashboardBantuanRoute = DashboardBantuanRouteImport.update({ - id: '/bantuan', - path: '/bantuan', - getParentRoute: () => DashboardRouteRoute, +const PengaturanAksesDanTimRoute = PengaturanAksesDanTimRouteImport.update({ + id: '/akses-dan-tim', + path: '/akses-dan-tim', + getParentRoute: () => PengaturanRouteRoute, } as any) const AdminUsersRoute = AdminUsersRouteImport.update({ id: '/users', @@ -156,222 +166,192 @@ const AdminApikeyRoute = AdminApikeyRouteImport.update({ path: '/apikey', getParentRoute: () => AdminRouteRoute, } as any) -const DashboardPengaturanRouteRoute = - DashboardPengaturanRouteRouteImport.update({ - id: '/pengaturan', - path: '/pengaturan', - getParentRoute: () => DashboardRouteRoute, - } as any) -const DashboardPengaturanUmumRoute = DashboardPengaturanUmumRouteImport.update({ - id: '/umum', - path: '/umum', - getParentRoute: () => DashboardPengaturanRouteRoute, -} as any) -const DashboardPengaturanNotifikasiRoute = - DashboardPengaturanNotifikasiRouteImport.update({ - id: '/notifikasi', - path: '/notifikasi', - getParentRoute: () => DashboardPengaturanRouteRoute, - } as any) -const DashboardPengaturanKeamananRoute = - DashboardPengaturanKeamananRouteImport.update({ - id: '/keamanan', - path: '/keamanan', - getParentRoute: () => DashboardPengaturanRouteRoute, - } as any) -const DashboardPengaturanAksesDanTimRoute = - DashboardPengaturanAksesDanTimRouteImport.update({ - id: '/akses-dan-tim', - path: '/akses-dan-tim', - getParentRoute: () => DashboardPengaturanRouteRoute, - } as any) export interface FileRoutesByFullPath { '/': typeof IndexRoute '/admin': typeof AdminRouteRouteWithChildren - '/dashboard': typeof DashboardRouteRouteWithChildren + '/pengaturan': typeof PengaturanRouteRouteWithChildren + '/bantuan': typeof BantuanRoute + '/bumdes': typeof BumdesRoute + '/demografi-pekerjaan': typeof DemografiPekerjaanRoute + '/jenna-analytic': typeof JennaAnalyticRoute + '/keamanan': typeof KeamananRoute + '/keuangan-anggaran': typeof KeuanganAnggaranRoute + '/kinerja-divisi': typeof KinerjaDivisiRoute + '/pengaduan-layanan-publik': typeof PengaduanLayananPublikRoute '/signin': typeof SigninRoute '/signup': typeof SignupRoute - '/dashboard/pengaturan': typeof DashboardPengaturanRouteRouteWithChildren + '/sosial': typeof SosialRoute '/admin/apikey': typeof AdminApikeyRoute '/admin/settings': typeof AdminSettingsRoute '/admin/users': typeof AdminUsersRoute - '/dashboard/bantuan': typeof DashboardBantuanRoute - '/dashboard/bumdes': typeof DashboardBumdesRoute - '/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute - '/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute - '/dashboard/keamanan': typeof DashboardKeamananRoute - '/dashboard/keuangan-anggaran': typeof DashboardKeuanganAnggaranRoute - '/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute - '/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute - '/dashboard/sosial': typeof DashboardSosialRoute + '/pengaturan/akses-dan-tim': typeof PengaturanAksesDanTimRoute + '/pengaturan/keamanan': typeof PengaturanKeamananRoute + '/pengaturan/notifikasi': typeof PengaturanNotifikasiRoute + '/pengaturan/umum': typeof PengaturanUmumRoute '/profile/edit': typeof ProfileEditRoute '/users/$id': typeof UsersIdRoute '/admin/': typeof AdminIndexRoute - '/dashboard/': typeof DashboardIndexRoute '/profile/': typeof ProfileIndexRoute '/users/': typeof UsersIndexRoute - '/dashboard/pengaturan/akses-dan-tim': typeof DashboardPengaturanAksesDanTimRoute - '/dashboard/pengaturan/keamanan': typeof DashboardPengaturanKeamananRoute - '/dashboard/pengaturan/notifikasi': typeof DashboardPengaturanNotifikasiRoute - '/dashboard/pengaturan/umum': typeof DashboardPengaturanUmumRoute } export interface FileRoutesByTo { '/': typeof IndexRoute + '/pengaturan': typeof PengaturanRouteRouteWithChildren + '/bantuan': typeof BantuanRoute + '/bumdes': typeof BumdesRoute + '/demografi-pekerjaan': typeof DemografiPekerjaanRoute + '/jenna-analytic': typeof JennaAnalyticRoute + '/keamanan': typeof KeamananRoute + '/keuangan-anggaran': typeof KeuanganAnggaranRoute + '/kinerja-divisi': typeof KinerjaDivisiRoute + '/pengaduan-layanan-publik': typeof PengaduanLayananPublikRoute '/signin': typeof SigninRoute '/signup': typeof SignupRoute - '/dashboard/pengaturan': typeof DashboardPengaturanRouteRouteWithChildren + '/sosial': typeof SosialRoute '/admin/apikey': typeof AdminApikeyRoute '/admin/settings': typeof AdminSettingsRoute '/admin/users': typeof AdminUsersRoute - '/dashboard/bantuan': typeof DashboardBantuanRoute - '/dashboard/bumdes': typeof DashboardBumdesRoute - '/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute - '/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute - '/dashboard/keamanan': typeof DashboardKeamananRoute - '/dashboard/keuangan-anggaran': typeof DashboardKeuanganAnggaranRoute - '/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute - '/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute - '/dashboard/sosial': typeof DashboardSosialRoute + '/pengaturan/akses-dan-tim': typeof PengaturanAksesDanTimRoute + '/pengaturan/keamanan': typeof PengaturanKeamananRoute + '/pengaturan/notifikasi': typeof PengaturanNotifikasiRoute + '/pengaturan/umum': typeof PengaturanUmumRoute '/profile/edit': typeof ProfileEditRoute '/users/$id': typeof UsersIdRoute '/admin': typeof AdminIndexRoute - '/dashboard': typeof DashboardIndexRoute '/profile': typeof ProfileIndexRoute '/users': typeof UsersIndexRoute - '/dashboard/pengaturan/akses-dan-tim': typeof DashboardPengaturanAksesDanTimRoute - '/dashboard/pengaturan/keamanan': typeof DashboardPengaturanKeamananRoute - '/dashboard/pengaturan/notifikasi': typeof DashboardPengaturanNotifikasiRoute - '/dashboard/pengaturan/umum': typeof DashboardPengaturanUmumRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/admin': typeof AdminRouteRouteWithChildren - '/dashboard': typeof DashboardRouteRouteWithChildren + '/pengaturan': typeof PengaturanRouteRouteWithChildren + '/bantuan': typeof BantuanRoute + '/bumdes': typeof BumdesRoute + '/demografi-pekerjaan': typeof DemografiPekerjaanRoute + '/jenna-analytic': typeof JennaAnalyticRoute + '/keamanan': typeof KeamananRoute + '/keuangan-anggaran': typeof KeuanganAnggaranRoute + '/kinerja-divisi': typeof KinerjaDivisiRoute + '/pengaduan-layanan-publik': typeof PengaduanLayananPublikRoute '/signin': typeof SigninRoute '/signup': typeof SignupRoute - '/dashboard/pengaturan': typeof DashboardPengaturanRouteRouteWithChildren + '/sosial': typeof SosialRoute '/admin/apikey': typeof AdminApikeyRoute '/admin/settings': typeof AdminSettingsRoute '/admin/users': typeof AdminUsersRoute - '/dashboard/bantuan': typeof DashboardBantuanRoute - '/dashboard/bumdes': typeof DashboardBumdesRoute - '/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute - '/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute - '/dashboard/keamanan': typeof DashboardKeamananRoute - '/dashboard/keuangan-anggaran': typeof DashboardKeuanganAnggaranRoute - '/dashboard/kinerja-divisi': typeof DashboardKinerjaDivisiRoute - '/dashboard/pengaduan-layanan-publik': typeof DashboardPengaduanLayananPublikRoute - '/dashboard/sosial': typeof DashboardSosialRoute + '/pengaturan/akses-dan-tim': typeof PengaturanAksesDanTimRoute + '/pengaturan/keamanan': typeof PengaturanKeamananRoute + '/pengaturan/notifikasi': typeof PengaturanNotifikasiRoute + '/pengaturan/umum': typeof PengaturanUmumRoute '/profile/edit': typeof ProfileEditRoute '/users/$id': typeof UsersIdRoute '/admin/': typeof AdminIndexRoute - '/dashboard/': typeof DashboardIndexRoute '/profile/': typeof ProfileIndexRoute '/users/': typeof UsersIndexRoute - '/dashboard/pengaturan/akses-dan-tim': typeof DashboardPengaturanAksesDanTimRoute - '/dashboard/pengaturan/keamanan': typeof DashboardPengaturanKeamananRoute - '/dashboard/pengaturan/notifikasi': typeof DashboardPengaturanNotifikasiRoute - '/dashboard/pengaturan/umum': typeof DashboardPengaturanUmumRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: | '/' | '/admin' - | '/dashboard' + | '/pengaturan' + | '/bantuan' + | '/bumdes' + | '/demografi-pekerjaan' + | '/jenna-analytic' + | '/keamanan' + | '/keuangan-anggaran' + | '/kinerja-divisi' + | '/pengaduan-layanan-publik' | '/signin' | '/signup' - | '/dashboard/pengaturan' + | '/sosial' | '/admin/apikey' | '/admin/settings' | '/admin/users' - | '/dashboard/bantuan' - | '/dashboard/bumdes' - | '/dashboard/demografi-pekerjaan' - | '/dashboard/jenna-analytic' - | '/dashboard/keamanan' - | '/dashboard/keuangan-anggaran' - | '/dashboard/kinerja-divisi' - | '/dashboard/pengaduan-layanan-publik' - | '/dashboard/sosial' + | '/pengaturan/akses-dan-tim' + | '/pengaturan/keamanan' + | '/pengaturan/notifikasi' + | '/pengaturan/umum' | '/profile/edit' | '/users/$id' | '/admin/' - | '/dashboard/' | '/profile/' | '/users/' - | '/dashboard/pengaturan/akses-dan-tim' - | '/dashboard/pengaturan/keamanan' - | '/dashboard/pengaturan/notifikasi' - | '/dashboard/pengaturan/umum' fileRoutesByTo: FileRoutesByTo to: | '/' + | '/pengaturan' + | '/bantuan' + | '/bumdes' + | '/demografi-pekerjaan' + | '/jenna-analytic' + | '/keamanan' + | '/keuangan-anggaran' + | '/kinerja-divisi' + | '/pengaduan-layanan-publik' | '/signin' | '/signup' - | '/dashboard/pengaturan' + | '/sosial' | '/admin/apikey' | '/admin/settings' | '/admin/users' - | '/dashboard/bantuan' - | '/dashboard/bumdes' - | '/dashboard/demografi-pekerjaan' - | '/dashboard/jenna-analytic' - | '/dashboard/keamanan' - | '/dashboard/keuangan-anggaran' - | '/dashboard/kinerja-divisi' - | '/dashboard/pengaduan-layanan-publik' - | '/dashboard/sosial' + | '/pengaturan/akses-dan-tim' + | '/pengaturan/keamanan' + | '/pengaturan/notifikasi' + | '/pengaturan/umum' | '/profile/edit' | '/users/$id' | '/admin' - | '/dashboard' | '/profile' | '/users' - | '/dashboard/pengaturan/akses-dan-tim' - | '/dashboard/pengaturan/keamanan' - | '/dashboard/pengaturan/notifikasi' - | '/dashboard/pengaturan/umum' id: | '__root__' | '/' | '/admin' - | '/dashboard' + | '/pengaturan' + | '/bantuan' + | '/bumdes' + | '/demografi-pekerjaan' + | '/jenna-analytic' + | '/keamanan' + | '/keuangan-anggaran' + | '/kinerja-divisi' + | '/pengaduan-layanan-publik' | '/signin' | '/signup' - | '/dashboard/pengaturan' + | '/sosial' | '/admin/apikey' | '/admin/settings' | '/admin/users' - | '/dashboard/bantuan' - | '/dashboard/bumdes' - | '/dashboard/demografi-pekerjaan' - | '/dashboard/jenna-analytic' - | '/dashboard/keamanan' - | '/dashboard/keuangan-anggaran' - | '/dashboard/kinerja-divisi' - | '/dashboard/pengaduan-layanan-publik' - | '/dashboard/sosial' + | '/pengaturan/akses-dan-tim' + | '/pengaturan/keamanan' + | '/pengaturan/notifikasi' + | '/pengaturan/umum' | '/profile/edit' | '/users/$id' | '/admin/' - | '/dashboard/' | '/profile/' | '/users/' - | '/dashboard/pengaturan/akses-dan-tim' - | '/dashboard/pengaturan/keamanan' - | '/dashboard/pengaturan/notifikasi' - | '/dashboard/pengaturan/umum' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute AdminRouteRoute: typeof AdminRouteRouteWithChildren - DashboardRouteRoute: typeof DashboardRouteRouteWithChildren + PengaturanRouteRoute: typeof PengaturanRouteRouteWithChildren + BantuanRoute: typeof BantuanRoute + BumdesRoute: typeof BumdesRoute + DemografiPekerjaanRoute: typeof DemografiPekerjaanRoute + JennaAnalyticRoute: typeof JennaAnalyticRoute + KeamananRoute: typeof KeamananRoute + KeuanganAnggaranRoute: typeof KeuanganAnggaranRoute + KinerjaDivisiRoute: typeof KinerjaDivisiRoute + PengaduanLayananPublikRoute: typeof PengaduanLayananPublikRoute SigninRoute: typeof SigninRoute SignupRoute: typeof SignupRoute + SosialRoute: typeof SosialRoute ProfileEditRoute: typeof ProfileEditRoute UsersIdRoute: typeof UsersIdRoute ProfileIndexRoute: typeof ProfileIndexRoute @@ -380,6 +360,13 @@ export interface RootRouteChildren { declare module '@tanstack/react-router' { interface FileRoutesByPath { + '/sosial': { + id: '/sosial' + path: '/sosial' + fullPath: '/sosial' + preLoaderRoute: typeof SosialRouteImport + parentRoute: typeof rootRouteImport + } '/signup': { id: '/signup' path: '/signup' @@ -394,11 +381,67 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof SigninRouteImport parentRoute: typeof rootRouteImport } - '/dashboard': { - id: '/dashboard' - path: '/dashboard' - fullPath: '/dashboard' - preLoaderRoute: typeof DashboardRouteRouteImport + '/pengaduan-layanan-publik': { + id: '/pengaduan-layanan-publik' + path: '/pengaduan-layanan-publik' + fullPath: '/pengaduan-layanan-publik' + preLoaderRoute: typeof PengaduanLayananPublikRouteImport + parentRoute: typeof rootRouteImport + } + '/kinerja-divisi': { + id: '/kinerja-divisi' + path: '/kinerja-divisi' + fullPath: '/kinerja-divisi' + preLoaderRoute: typeof KinerjaDivisiRouteImport + parentRoute: typeof rootRouteImport + } + '/keuangan-anggaran': { + id: '/keuangan-anggaran' + path: '/keuangan-anggaran' + fullPath: '/keuangan-anggaran' + preLoaderRoute: typeof KeuanganAnggaranRouteImport + parentRoute: typeof rootRouteImport + } + '/keamanan': { + id: '/keamanan' + path: '/keamanan' + fullPath: '/keamanan' + preLoaderRoute: typeof KeamananRouteImport + parentRoute: typeof rootRouteImport + } + '/jenna-analytic': { + id: '/jenna-analytic' + path: '/jenna-analytic' + fullPath: '/jenna-analytic' + preLoaderRoute: typeof JennaAnalyticRouteImport + parentRoute: typeof rootRouteImport + } + '/demografi-pekerjaan': { + id: '/demografi-pekerjaan' + path: '/demografi-pekerjaan' + fullPath: '/demografi-pekerjaan' + preLoaderRoute: typeof DemografiPekerjaanRouteImport + parentRoute: typeof rootRouteImport + } + '/bumdes': { + id: '/bumdes' + path: '/bumdes' + fullPath: '/bumdes' + preLoaderRoute: typeof BumdesRouteImport + parentRoute: typeof rootRouteImport + } + '/bantuan': { + id: '/bantuan' + path: '/bantuan' + fullPath: '/bantuan' + preLoaderRoute: typeof BantuanRouteImport + parentRoute: typeof rootRouteImport + } + '/pengaturan': { + id: '/pengaturan' + path: '/pengaturan' + fullPath: '/pengaturan' + preLoaderRoute: typeof PengaturanRouteRouteImport parentRoute: typeof rootRouteImport } '/admin': { @@ -429,13 +472,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ProfileIndexRouteImport parentRoute: typeof rootRouteImport } - '/dashboard/': { - id: '/dashboard/' - path: '/' - fullPath: '/dashboard/' - preLoaderRoute: typeof DashboardIndexRouteImport - parentRoute: typeof DashboardRouteRoute - } '/admin/': { id: '/admin/' path: '/' @@ -457,68 +493,33 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ProfileEditRouteImport parentRoute: typeof rootRouteImport } - '/dashboard/sosial': { - id: '/dashboard/sosial' - path: '/sosial' - fullPath: '/dashboard/sosial' - preLoaderRoute: typeof DashboardSosialRouteImport - parentRoute: typeof DashboardRouteRoute + '/pengaturan/umum': { + id: '/pengaturan/umum' + path: '/umum' + fullPath: '/pengaturan/umum' + preLoaderRoute: typeof PengaturanUmumRouteImport + parentRoute: typeof PengaturanRouteRoute } - '/dashboard/pengaduan-layanan-publik': { - id: '/dashboard/pengaduan-layanan-publik' - path: '/pengaduan-layanan-publik' - fullPath: '/dashboard/pengaduan-layanan-publik' - preLoaderRoute: typeof DashboardPengaduanLayananPublikRouteImport - parentRoute: typeof DashboardRouteRoute + '/pengaturan/notifikasi': { + id: '/pengaturan/notifikasi' + path: '/notifikasi' + fullPath: '/pengaturan/notifikasi' + preLoaderRoute: typeof PengaturanNotifikasiRouteImport + parentRoute: typeof PengaturanRouteRoute } - '/dashboard/kinerja-divisi': { - id: '/dashboard/kinerja-divisi' - path: '/kinerja-divisi' - fullPath: '/dashboard/kinerja-divisi' - preLoaderRoute: typeof DashboardKinerjaDivisiRouteImport - parentRoute: typeof DashboardRouteRoute - } - '/dashboard/keuangan-anggaran': { - id: '/dashboard/keuangan-anggaran' - path: '/keuangan-anggaran' - fullPath: '/dashboard/keuangan-anggaran' - preLoaderRoute: typeof DashboardKeuanganAnggaranRouteImport - parentRoute: typeof DashboardRouteRoute - } - '/dashboard/keamanan': { - id: '/dashboard/keamanan' + '/pengaturan/keamanan': { + id: '/pengaturan/keamanan' path: '/keamanan' - fullPath: '/dashboard/keamanan' - preLoaderRoute: typeof DashboardKeamananRouteImport - parentRoute: typeof DashboardRouteRoute + fullPath: '/pengaturan/keamanan' + preLoaderRoute: typeof PengaturanKeamananRouteImport + parentRoute: typeof PengaturanRouteRoute } - '/dashboard/jenna-analytic': { - id: '/dashboard/jenna-analytic' - path: '/jenna-analytic' - fullPath: '/dashboard/jenna-analytic' - preLoaderRoute: typeof DashboardJennaAnalyticRouteImport - parentRoute: typeof DashboardRouteRoute - } - '/dashboard/demografi-pekerjaan': { - id: '/dashboard/demografi-pekerjaan' - path: '/demografi-pekerjaan' - fullPath: '/dashboard/demografi-pekerjaan' - preLoaderRoute: typeof DashboardDemografiPekerjaanRouteImport - parentRoute: typeof DashboardRouteRoute - } - '/dashboard/bumdes': { - id: '/dashboard/bumdes' - path: '/bumdes' - fullPath: '/dashboard/bumdes' - preLoaderRoute: typeof DashboardBumdesRouteImport - parentRoute: typeof DashboardRouteRoute - } - '/dashboard/bantuan': { - id: '/dashboard/bantuan' - path: '/bantuan' - fullPath: '/dashboard/bantuan' - preLoaderRoute: typeof DashboardBantuanRouteImport - parentRoute: typeof DashboardRouteRoute + '/pengaturan/akses-dan-tim': { + id: '/pengaturan/akses-dan-tim' + path: '/akses-dan-tim' + fullPath: '/pengaturan/akses-dan-tim' + preLoaderRoute: typeof PengaturanAksesDanTimRouteImport + parentRoute: typeof PengaturanRouteRoute } '/admin/users': { id: '/admin/users' @@ -541,41 +542,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AdminApikeyRouteImport parentRoute: typeof AdminRouteRoute } - '/dashboard/pengaturan': { - id: '/dashboard/pengaturan' - path: '/pengaturan' - fullPath: '/dashboard/pengaturan' - preLoaderRoute: typeof DashboardPengaturanRouteRouteImport - parentRoute: typeof DashboardRouteRoute - } - '/dashboard/pengaturan/umum': { - id: '/dashboard/pengaturan/umum' - path: '/umum' - fullPath: '/dashboard/pengaturan/umum' - preLoaderRoute: typeof DashboardPengaturanUmumRouteImport - parentRoute: typeof DashboardPengaturanRouteRoute - } - '/dashboard/pengaturan/notifikasi': { - id: '/dashboard/pengaturan/notifikasi' - path: '/notifikasi' - fullPath: '/dashboard/pengaturan/notifikasi' - preLoaderRoute: typeof DashboardPengaturanNotifikasiRouteImport - parentRoute: typeof DashboardPengaturanRouteRoute - } - '/dashboard/pengaturan/keamanan': { - id: '/dashboard/pengaturan/keamanan' - path: '/keamanan' - fullPath: '/dashboard/pengaturan/keamanan' - preLoaderRoute: typeof DashboardPengaturanKeamananRouteImport - parentRoute: typeof DashboardPengaturanRouteRoute - } - '/dashboard/pengaturan/akses-dan-tim': { - id: '/dashboard/pengaturan/akses-dan-tim' - path: '/akses-dan-tim' - fullPath: '/dashboard/pengaturan/akses-dan-tim' - preLoaderRoute: typeof DashboardPengaturanAksesDanTimRouteImport - parentRoute: typeof DashboardPengaturanRouteRoute - } } } @@ -597,64 +563,39 @@ const AdminRouteRouteWithChildren = AdminRouteRoute._addFileChildren( AdminRouteRouteChildren, ) -interface DashboardPengaturanRouteRouteChildren { - DashboardPengaturanAksesDanTimRoute: typeof DashboardPengaturanAksesDanTimRoute - DashboardPengaturanKeamananRoute: typeof DashboardPengaturanKeamananRoute - DashboardPengaturanNotifikasiRoute: typeof DashboardPengaturanNotifikasiRoute - DashboardPengaturanUmumRoute: typeof DashboardPengaturanUmumRoute +interface PengaturanRouteRouteChildren { + PengaturanAksesDanTimRoute: typeof PengaturanAksesDanTimRoute + PengaturanKeamananRoute: typeof PengaturanKeamananRoute + PengaturanNotifikasiRoute: typeof PengaturanNotifikasiRoute + PengaturanUmumRoute: typeof PengaturanUmumRoute } -const DashboardPengaturanRouteRouteChildren: DashboardPengaturanRouteRouteChildren = - { - DashboardPengaturanAksesDanTimRoute: DashboardPengaturanAksesDanTimRoute, - DashboardPengaturanKeamananRoute: DashboardPengaturanKeamananRoute, - DashboardPengaturanNotifikasiRoute: DashboardPengaturanNotifikasiRoute, - DashboardPengaturanUmumRoute: DashboardPengaturanUmumRoute, - } - -const DashboardPengaturanRouteRouteWithChildren = - DashboardPengaturanRouteRoute._addFileChildren( - DashboardPengaturanRouteRouteChildren, - ) - -interface DashboardRouteRouteChildren { - DashboardPengaturanRouteRoute: typeof DashboardPengaturanRouteRouteWithChildren - DashboardBantuanRoute: typeof DashboardBantuanRoute - DashboardBumdesRoute: typeof DashboardBumdesRoute - DashboardDemografiPekerjaanRoute: typeof DashboardDemografiPekerjaanRoute - DashboardJennaAnalyticRoute: typeof DashboardJennaAnalyticRoute - DashboardKeamananRoute: typeof DashboardKeamananRoute - DashboardKeuanganAnggaranRoute: typeof DashboardKeuanganAnggaranRoute - DashboardKinerjaDivisiRoute: typeof DashboardKinerjaDivisiRoute - DashboardPengaduanLayananPublikRoute: typeof DashboardPengaduanLayananPublikRoute - DashboardSosialRoute: typeof DashboardSosialRoute - DashboardIndexRoute: typeof DashboardIndexRoute +const PengaturanRouteRouteChildren: PengaturanRouteRouteChildren = { + PengaturanAksesDanTimRoute: PengaturanAksesDanTimRoute, + PengaturanKeamananRoute: PengaturanKeamananRoute, + PengaturanNotifikasiRoute: PengaturanNotifikasiRoute, + PengaturanUmumRoute: PengaturanUmumRoute, } -const DashboardRouteRouteChildren: DashboardRouteRouteChildren = { - DashboardPengaturanRouteRoute: DashboardPengaturanRouteRouteWithChildren, - DashboardBantuanRoute: DashboardBantuanRoute, - DashboardBumdesRoute: DashboardBumdesRoute, - DashboardDemografiPekerjaanRoute: DashboardDemografiPekerjaanRoute, - DashboardJennaAnalyticRoute: DashboardJennaAnalyticRoute, - DashboardKeamananRoute: DashboardKeamananRoute, - DashboardKeuanganAnggaranRoute: DashboardKeuanganAnggaranRoute, - DashboardKinerjaDivisiRoute: DashboardKinerjaDivisiRoute, - DashboardPengaduanLayananPublikRoute: DashboardPengaduanLayananPublikRoute, - DashboardSosialRoute: DashboardSosialRoute, - DashboardIndexRoute: DashboardIndexRoute, -} - -const DashboardRouteRouteWithChildren = DashboardRouteRoute._addFileChildren( - DashboardRouteRouteChildren, +const PengaturanRouteRouteWithChildren = PengaturanRouteRoute._addFileChildren( + PengaturanRouteRouteChildren, ) const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, AdminRouteRoute: AdminRouteRouteWithChildren, - DashboardRouteRoute: DashboardRouteRouteWithChildren, + PengaturanRouteRoute: PengaturanRouteRouteWithChildren, + BantuanRoute: BantuanRoute, + BumdesRoute: BumdesRoute, + DemografiPekerjaanRoute: DemografiPekerjaanRoute, + JennaAnalyticRoute: JennaAnalyticRoute, + KeamananRoute: KeamananRoute, + KeuanganAnggaranRoute: KeuanganAnggaranRoute, + KinerjaDivisiRoute: KinerjaDivisiRoute, + PengaduanLayananPublikRoute: PengaduanLayananPublikRoute, SigninRoute: SigninRoute, SignupRoute: SignupRoute, + SosialRoute: SosialRoute, ProfileEditRoute: ProfileEditRoute, UsersIdRoute: UsersIdRoute, ProfileIndexRoute: ProfileIndexRoute, diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 3e12384..e536635 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -7,8 +7,20 @@ import { createRootRoute, Outlet } from "@tanstack/react-router"; export const Route = createRootRoute({ component: RootComponent, - beforeLoad: protectedRouteMiddleware, - onEnter({ context }) { + beforeLoad: async ({ location }) => { + // Only apply auth middleware for routes that need it + // Public routes: /, /signin, /signup + const isPublicRoute = + location.pathname === "/" || + location.pathname === "/signin" || + location.pathname === "/signup"; + + if (isPublicRoute) { + return; + } + + // Apply protected route middleware for all other routes + const context = await protectedRouteMiddleware({ location }); authStore.user = context?.user as any; authStore.session = context?.session as any; }, diff --git a/src/routes/admin/route.tsx b/src/routes/admin/route.tsx index 9ba9fc3..688d779 100644 --- a/src/routes/admin/route.tsx +++ b/src/routes/admin/route.tsx @@ -154,7 +154,6 @@ function DashboardLayout() { - + + + +
+ + + + +
+ +
+
+ + + + + + ); +} diff --git a/src/routes/bumdes.tsx b/src/routes/bumdes.tsx new file mode 100644 index 0000000..2a85961 --- /dev/null +++ b/src/routes/bumdes.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/bumdes")({ + component: RouteComponent, +}); + +function RouteComponent() { + return
Hello "/bumdes"!
; +} diff --git a/src/routes/dashboard/bantuan.ts b/src/routes/dashboard/bantuan.ts deleted file mode 100644 index 510fc86..0000000 --- a/src/routes/dashboard/bantuan.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import HelpPage from '@/components/help-page' - -export const Route = createFileRoute('/dashboard/bantuan')({ - component: HelpPage, -}) - diff --git a/src/routes/dashboard/bumdes.ts b/src/routes/dashboard/bumdes.ts deleted file mode 100644 index 3a7387e..0000000 --- a/src/routes/dashboard/bumdes.ts +++ /dev/null @@ -1,7 +0,0 @@ -import BumdesPage from '@/components/bumdes-page' -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/dashboard/bumdes')({ - component: BumdesPage, -}) - diff --git a/src/routes/dashboard/demografi-pekerjaan.ts b/src/routes/dashboard/demografi-pekerjaan.ts deleted file mode 100644 index de98b36..0000000 --- a/src/routes/dashboard/demografi-pekerjaan.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import DemografiPekerjaan from '../../components/demografi-pekerjaan' - -export const Route = createFileRoute('/dashboard/demografi-pekerjaan')({ - component: DemografiPekerjaan, -}) - diff --git a/src/routes/dashboard/index.ts b/src/routes/dashboard/index.ts deleted file mode 100644 index b565d53..0000000 --- a/src/routes/dashboard/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; -import { DashboardContent } from "@/components/dashboard-content"; -export const Route = createFileRoute("/dashboard/")({ - component: DashboardContent, -}); diff --git a/src/routes/dashboard/jenna-analytic.ts b/src/routes/dashboard/jenna-analytic.ts deleted file mode 100644 index 1cd3ac0..0000000 --- a/src/routes/dashboard/jenna-analytic.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import JennaAnalytic from '@/components/jenna-analytic' - -export const Route = createFileRoute('/dashboard/jenna-analytic')({ - component: JennaAnalytic, -}) diff --git a/src/routes/dashboard/keamanan.ts b/src/routes/dashboard/keamanan.ts deleted file mode 100644 index 710c89a..0000000 --- a/src/routes/dashboard/keamanan.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import KeamananPage from '@/components/keamanan-page' - -export const Route = createFileRoute('/dashboard/keamanan')({ - component: KeamananPage, -}) - diff --git a/src/routes/dashboard/keuangan-anggaran.ts b/src/routes/dashboard/keuangan-anggaran.ts deleted file mode 100644 index e5e8e8c..0000000 --- a/src/routes/dashboard/keuangan-anggaran.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import KeuanganAnggaran from '@/components/keuangan-anggaran' - -export const Route = createFileRoute('/dashboard/keuangan-anggaran')({ - component: KeuanganAnggaran, -}) diff --git a/src/routes/dashboard/kinerja-divisi.ts b/src/routes/dashboard/kinerja-divisi.ts deleted file mode 100644 index 703d9f3..0000000 --- a/src/routes/dashboard/kinerja-divisi.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; -import KinerjaDivisi from "@/components/kinerja-divisi"; -export const Route = createFileRoute("/dashboard/kinerja-divisi")({ - component: KinerjaDivisi, -}); diff --git a/src/routes/dashboard/pengaduan-layanan-publik.ts b/src/routes/dashboard/pengaduan-layanan-publik.ts deleted file mode 100644 index 49cce46..0000000 --- a/src/routes/dashboard/pengaduan-layanan-publik.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; -import PengaduanLayananPublik from "@/components/pengaduan-layanan-publik"; -export const Route = createFileRoute("/dashboard/pengaduan-layanan-publik")({ - component: PengaduanLayananPublik, -}); diff --git a/src/routes/dashboard/pengaturan/akses-dan-tim.ts b/src/routes/dashboard/pengaturan/akses-dan-tim.ts deleted file mode 100644 index bb463f7..0000000 --- a/src/routes/dashboard/pengaturan/akses-dan-tim.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import AksesDanTimSettings from '@/components/pengaturan/akses-dan-tim' - -export const Route = createFileRoute('/dashboard/pengaturan/akses-dan-tim')({ - component: AksesDanTimSettings, -}) diff --git a/src/routes/dashboard/pengaturan/keamanan.ts b/src/routes/dashboard/pengaturan/keamanan.ts deleted file mode 100644 index 46c87f9..0000000 --- a/src/routes/dashboard/pengaturan/keamanan.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import KeamananSettings from '@/components/pengaturan/keamanan' - -export const Route = createFileRoute('/dashboard/pengaturan/keamanan')({ - component: KeamananSettings, -}) - diff --git a/src/routes/dashboard/pengaturan/notifikasi.ts b/src/routes/dashboard/pengaturan/notifikasi.ts deleted file mode 100644 index a445f25..0000000 --- a/src/routes/dashboard/pengaturan/notifikasi.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import NotifikasiSettings from '@/components/pengaturan/notifikasi' - -export const Route = createFileRoute('/dashboard/pengaturan/notifikasi')({ - component: NotifikasiSettings, -}) \ No newline at end of file diff --git a/src/routes/dashboard/pengaturan/route.tsx b/src/routes/dashboard/pengaturan/route.tsx deleted file mode 100644 index 09e2000..0000000 --- a/src/routes/dashboard/pengaturan/route.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createFileRoute, Outlet } from '@tanstack/react-router'; - -export const Route = createFileRoute('/dashboard/pengaturan')({ - component: () => ( -
- -
- ), -}); \ No newline at end of file diff --git a/src/routes/dashboard/pengaturan/umum.ts b/src/routes/dashboard/pengaturan/umum.ts deleted file mode 100644 index 8d57716..0000000 --- a/src/routes/dashboard/pengaturan/umum.ts +++ /dev/null @@ -1,7 +0,0 @@ -import UmumSettings from '@/components/pengaturan/umum' -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/dashboard/pengaturan/umum')({ - component: UmumSettings, -}) - diff --git a/src/routes/dashboard/sosial.ts b/src/routes/dashboard/sosial.ts deleted file mode 100644 index b11e66e..0000000 --- a/src/routes/dashboard/sosial.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' -import SocialPage from '@/components/sosial-page' - - -export const Route = createFileRoute('/dashboard/sosial')({ - component: SocialPage, -}) - diff --git a/src/routes/demografi-pekerjaan.tsx b/src/routes/demografi-pekerjaan.tsx new file mode 100644 index 0000000..722817e --- /dev/null +++ b/src/routes/demografi-pekerjaan.tsx @@ -0,0 +1,51 @@ +import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; +import { useDisclosure } from "@mantine/hooks"; +import { createFileRoute } from "@tanstack/react-router"; +import { Header } from "@/components/header"; +import { Sidebar } from "@/components/sidebar"; +import DemografiPekerjaan from "../components/demografi-pekerjaan"; + +export const Route = createFileRoute("/demografi-pekerjaan")({ + component: DemografiPekerjaanPage, +}); + +function DemografiPekerjaanPage() { + 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 ( + + + + +
+ + + + +
+ +
+
+ + + + + + ); +} diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 8fe1381..ad6162a 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,788 +1,51 @@ -import { - ActionIcon, - Avatar, - Box, - Button, - Card, - Container, - Grid, - Group, - Image, - Paper, - rem, - SimpleGrid, - Stack, - Text, - ThemeIcon, - Title, - Transition, - useMantineColorScheme, -} from "@mantine/core"; -import { - IconApi, - IconBolt, - IconBrandGithub, - IconBrandLinkedin, - IconBrandTwitter, - IconChevronRight, - IconLock, - IconMoon, - IconRocket, - IconShield, - IconStack2, - IconSun, -} from "@tabler/icons-react"; -import { createFileRoute, Link } from "@tanstack/react-router"; -import { useEffect, useState } from "react"; +import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; +import { useDisclosure } from "@mantine/hooks"; +import { createFileRoute } from "@tanstack/react-router"; +import { DashboardContent } from "@/components/dashboard-content"; +import { Header } from "@/components/header"; +import { Sidebar } from "@/components/sidebar"; export const Route = createFileRoute("/")({ - component: HomePage, + component: DashboardPage, }); -// Navigation items -const NAV_ITEMS = [ - { label: "Home", link: "/" }, - { label: "Features", link: "#features" }, - { label: "Testimonials", link: "#testimonials" }, - { label: "Pricing", link: "/pricing" }, - { label: "Contact", link: "/contact" }, -]; - -// Features data -const FEATURES = [ - { - icon: IconBolt, - title: "Lightning Fast", - description: "Built on Bun runtime for exceptional performance and speed.", - }, - { - icon: IconShield, - title: "Secure by Design", - description: - "Enterprise-grade authentication with Better Auth integration.", - }, - { - icon: IconApi, - title: "RESTful API", - description: - "Full-featured API with Elysia.js for seamless backend operations.", - }, - { - icon: IconStack2, - title: "Modern Stack", - description: "React 19, TanStack Router, and Mantine UI for the best DX.", - }, - { - icon: IconLock, - title: "API Key Auth", - description: "Secure API key management for external integrations.", - }, - { - icon: IconRocket, - title: "Production Ready", - description: "Type-safe, tested, and optimized for production deployment.", - }, -]; - -// Testimonials data -const TESTIMONIALS = [ - { - id: "testimonial-1", - name: "Alex Johnson", - role: "Lead Developer", - content: - "This template saved us weeks of setup time. The architecture is clean and well-thought-out.", - avatar: - "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=200&q=80", - }, - { - id: "testimonial-2", - name: "Sarah Williams", - role: "CTO", - content: - "The performance improvements we saw after switching to this stack were remarkable. Highly recommended!", - avatar: - "https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=200&q=80", - }, - { - id: "testimonial-3", - name: "Michael Chen", - role: "Product Manager", - content: - "The developer experience is top-notch. Everything is well-documented and easy to extend.", - avatar: - "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=200&q=80", - }, -]; - -function NavigationBar() { - const { colorScheme, toggleColorScheme } = useMantineColorScheme(); - const [scrolled, setScrolled] = useState(false); - - useEffect(() => { - const handleScroll = () => { - setScrolled(window.scrollY > 20); - }; - - window.addEventListener("scroll", handleScroll); - return () => window.removeEventListener("scroll", handleScroll); - }, []); +function DashboardPage() { + 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 ( - - - - - - BunStack - - - - {NAV_ITEMS.map((item) => { - const isActive = window.location.pathname === item.link; - return ( - - {item.label} - - ); - })} - + + + +
+ - - toggleColorScheme()} - size="lg" - > - {colorScheme === "dark" ? ( - - ) : ( - - )} - - - - - - - ); -} - -function HeroSection() { - const [loaded, setLoaded] = useState(false); - const [imageLoaded, setImageLoaded] = useState(false); - - useEffect(() => { - setLoaded(true); - }, []); - - // Simulate delay for image transition - useEffect(() => { - const timer = setTimeout(() => { - setImageLoaded(true); - }, 200); - return () => clearTimeout(timer); - }, []); - - return ( - - - - - - {(styles) => ( - - - Build Faster with{" "} - <Text span c="blue" inherit> - Bun Stack - </Text> - - - A modern, full-stack React template powered by Bun, - Elysia.js, and TanStack Router. Ship your ideas faster than - ever. - - - - - - - )} - - - - - {(styles) => ( - - Code editor showing Bun Stack code - - )} - - - - - - ); -} - -function AnimatedFeatureCard({ - feature, - index, - isVisible, -}: { - feature: (typeof FEATURES)[number]; - index: number; - isVisible: boolean; -}) { - const [isDelayedVisible, setIsDelayedVisible] = useState(isVisible); - - useEffect(() => { - if (isVisible) { - const timer = setTimeout(() => { - setIsDelayedVisible(true); - }, index * 100); - return () => clearTimeout(timer); - } - }, [isVisible, index]); - - return ( - - {(styles) => ( - - - - - - {feature.title} - - {feature.description} - - - - )} - - ); -} - -function FeaturesSection() { - const [visibleFeatures, setVisibleFeatures] = useState( - Array(FEATURES.length).fill(false), - ); - - useEffect(() => { - const observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry, index) => { - if (entry.isIntersecting) { - setVisibleFeatures((prev) => { - const newVisible = [...prev]; - newVisible[index] = true; - return newVisible; - }); - } - }); - }, - { threshold: 0.1 }, - ); - - const elements = document.querySelectorAll(".feature-card"); - elements.forEach((el) => { - observer.observe(el); - }); - - return () => observer.disconnect(); - }, []); - - return ( - - - - {(styles) => ( -
- - Everything You Need - - - A complete toolkit for building modern web applications with - best practices built-in. - -
- )} -
-
- - {FEATURES.map((feature, index) => ( - - ))} - -
- ); -} - -function AnimatedTestimonialCard({ - testimonial, - index, - isVisible, -}: { - testimonial: (typeof TESTIMONIALS)[number]; - index: number; - isVisible: boolean; -}) { - const [isDelayedVisible, setIsDelayedVisible] = useState(isVisible); - - useEffect(() => { - if (isVisible) { - const timer = setTimeout(() => { - setIsDelayedVisible(true); - }, index * 150); - return () => clearTimeout(timer); - } - }, [isVisible, index]); - - return ( - - {(styles) => ( - - - "{testimonial.content}" - - - - - {testimonial.name} - - {testimonial.role} - - - - - )} - - ); -} - -function TestimonialsSection() { - const [visibleTestimonials, setVisibleTestimonials] = useState( - Array(TESTIMONIALS.length).fill(false), - ); - - useEffect(() => { - const observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry, index) => { - if (entry.isIntersecting) { - setVisibleTestimonials((prev) => { - const newVisible = [...prev]; - newVisible[index] = true; - return newVisible; - }); - } - }); - }, - { threshold: 0.1 }, - ); - - const elements = document.querySelectorAll(".testimonial-card"); - elements.forEach((el) => { - observer.observe(el); - }); - - return () => observer.disconnect(); - }, []); - - return ( - - - - - {(styles) => ( -
- - Loved by Developers - - - Join thousands of satisfied developers who have accelerated - their projects with Bun Stack. - -
- )} -
-
- - - {TESTIMONIALS.map((testimonial, index) => ( - - ))} - -
-
- ); -} - -function CtaSection() { - const [loaded, setLoaded] = useState(false); - - useEffect(() => { - setLoaded(true); - }, []); - - return ( - - - {(styles) => ( - - - - Ready to get started? - - - Join thousands of developers who are building faster and more - reliable applications with Bun Stack. - - - - - - - - )} - - - ); -} - -function Footer() { - const [loaded, setLoaded] = useState(false); - - useEffect(() => { - const timer = setTimeout(() => { - setLoaded(true); - }, 300); - return () => clearTimeout(timer); - }, []); - - return ( - - {(styles) => ( - - - - - - BunStack - - The ultimate full-stack solution for modern web - applications. - - - - - - - - - - - - - - - - - - Product - - Features - - - Pricing - - - Documentation - - - - - - - Company - - About - - - Blog - - - Careers - - - - - - - Subscribe to our newsletter - - Get the latest news and updates - - - - - - - - - - - - - © 2024 Bun Stack. Built with Bun, Elysia, and React. - - - - Privacy Policy - - - Terms of Service - - - - - - - )} - - ); -} - -function HomePage() { - return ( - - - - - - -