From 34804127c58a65d56b150566e33ad718c5e4b1a9 Mon Sep 17 00:00:00 2001 From: nico Date: Thu, 26 Mar 2026 17:10:40 +0800 Subject: [PATCH] Refactor: move AppShell to global layout, add breadcrumbs, and restructure profile routes --- src/components/header.tsx | 74 ++++- src/components/layout/main-layout.tsx | 66 ++++ src/routeTree.gen.ts | 57 +++- src/routes/__root.tsx | 22 +- src/routes/admin/index.tsx | 5 +- src/routes/admin/route.tsx | 4 +- src/routes/bantuan.tsx | 62 +--- src/routes/bumdes.tsx | 62 +--- src/routes/demografi-pekerjaan.tsx | 62 +--- src/routes/index.tsx | 68 +--- src/routes/jenna-analytic.tsx | 62 +--- src/routes/keamanan.tsx | 62 +--- src/routes/keuangan-anggaran.tsx | 62 +--- src/routes/kinerja-divisi.tsx | 62 +--- src/routes/pengaduan-layanan-publik.tsx | 62 +--- src/routes/pengaturan/route.tsx | 83 +---- src/routes/profile/edit.tsx | 139 ++++----- src/routes/profile/index.tsx | 395 ++++++++++++------------ src/routes/profile/route.tsx | 69 +++++ src/routes/sosial.tsx | 62 +--- 20 files changed, 548 insertions(+), 992 deletions(-) create mode 100644 src/components/layout/main-layout.tsx create mode 100644 src/routes/profile/route.tsx diff --git a/src/components/header.tsx b/src/components/header.tsx index 6983c7a..a52a90f 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -1,8 +1,10 @@ import { ActionIcon, + Anchor, Avatar, Badge, Box, + Breadcrumbs, Divider, Group, Text, @@ -20,14 +22,70 @@ interface HeaderProps { } export function Header({ onSidebarToggle }: HeaderProps) { - const _location = useLocation(); + const location = useLocation(); const navigate = useNavigate(); const { colorScheme, toggleColorScheme } = useMantineColorScheme(); const dark = colorScheme === "dark"; + const pathnames = location.pathname.split("/").filter((x) => x); + + const breadcrumbItems = [ + navigate({ to: "/" })} + c="white" + size="sm" + underline="hover" + > + Desa Darmasaba + , + ...pathnames.map((value, index) => { + const to = `/${pathnames.slice(0, index + 1).join("/")}`; + const isLast = index === pathnames.length - 1; + + // Map route path to human-readable label + const labelMap: Record = { + "kinerja-divisi": "Kinerja Divisi", + "pengaduan-layanan-publik": "Pengaduan & Layanan Publik", + "jenna-analytic": "Jenna Analytic", + "demografi-pekerjaan": "Demografi & Kependudukan", + "keuangan-anggaran": "Keuangan & Anggaran", + bumdes: "Bumdes & UMKM", + sosial: "Sosial", + keamanan: "Keamanan", + bantuan: "Bantuan", + pengaturan: "Pengaturan", + umum: "Umum", + notifikasi: "Notifikasi", + "akses-dan-tim": "Akses & Tim", + profile: "Profil", + edit: "Edit", + }; + + const label = + labelMap[value] || value.charAt(0).toUpperCase() + value.slice(1); + + return isLast ? ( + + {label} + + ) : ( + navigate({ to })} + c="white" + size="sm" + underline="hover" + > + {label} + + ); + }), + ]; + return ( - {/* Title */} + {/* Title & Breadcrumbs */} + + / + + } + styles={{ + separator: { color: "white" }, + }} + > + {breadcrumbItems} + {/* Right Section */} diff --git a/src/components/layout/main-layout.tsx b/src/components/layout/main-layout.tsx new file mode 100644 index 0000000..f6b26d1 --- /dev/null +++ b/src/components/layout/main-layout.tsx @@ -0,0 +1,66 @@ +import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; +import type React from "react"; +import { Header } from "@/components/header"; +import { Sidebar } from "@/components/sidebar"; +import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; + +interface MainLayoutProps { + children: React.ReactNode; +} + +export function MainLayout({ children }: MainLayoutProps) { + const { + opened, + toggleMobile, + sidebarCollapsed, + toggleSidebar, + handleMainClick, + } = useSidebarFullscreen(); + const { colorScheme } = useMantineColorScheme(); + + const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; + const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; + const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; + + return ( + + + + +
+ + + + +
+ +
+
+ + + {children} + + + ); +} diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 71bd866..898d718 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -20,6 +20,7 @@ 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 ProfileRouteRouteImport } from './routes/profile/route' import { Route as PengaturanRouteRouteImport } from './routes/pengaturan/route' import { Route as AdminRouteRouteImport } from './routes/admin/route' import { Route as IndexRouteImport } from './routes/index' @@ -91,6 +92,11 @@ const BantuanRoute = BantuanRouteImport.update({ path: '/bantuan', getParentRoute: () => rootRouteImport, } as any) +const ProfileRouteRoute = ProfileRouteRouteImport.update({ + id: '/profile', + path: '/profile', + getParentRoute: () => rootRouteImport, +} as any) const PengaturanRouteRoute = PengaturanRouteRouteImport.update({ id: '/pengaturan', path: '/pengaturan', @@ -112,9 +118,9 @@ const UsersIndexRoute = UsersIndexRouteImport.update({ getParentRoute: () => rootRouteImport, } as any) const ProfileIndexRoute = ProfileIndexRouteImport.update({ - id: '/profile/', - path: '/profile/', - getParentRoute: () => rootRouteImport, + id: '/', + path: '/', + getParentRoute: () => ProfileRouteRoute, } as any) const AdminIndexRoute = AdminIndexRouteImport.update({ id: '/', @@ -127,9 +133,9 @@ const UsersIdRoute = UsersIdRouteImport.update({ getParentRoute: () => rootRouteImport, } as any) const ProfileEditRoute = ProfileEditRouteImport.update({ - id: '/profile/edit', - path: '/profile/edit', - getParentRoute: () => rootRouteImport, + id: '/edit', + path: '/edit', + getParentRoute: () => ProfileRouteRoute, } as any) const PengaturanUmumRoute = PengaturanUmumRouteImport.update({ id: '/umum', @@ -171,6 +177,7 @@ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/admin': typeof AdminRouteRouteWithChildren '/pengaturan': typeof PengaturanRouteRouteWithChildren + '/profile': typeof ProfileRouteRouteWithChildren '/bantuan': typeof BantuanRoute '/bumdes': typeof BumdesRoute '/demografi-pekerjaan': typeof DemografiPekerjaanRoute @@ -227,6 +234,7 @@ export interface FileRoutesById { '/': typeof IndexRoute '/admin': typeof AdminRouteRouteWithChildren '/pengaturan': typeof PengaturanRouteRouteWithChildren + '/profile': typeof ProfileRouteRouteWithChildren '/bantuan': typeof BantuanRoute '/bumdes': typeof BumdesRoute '/demografi-pekerjaan': typeof DemografiPekerjaanRoute @@ -257,6 +265,7 @@ export interface FileRouteTypes { | '/' | '/admin' | '/pengaturan' + | '/profile' | '/bantuan' | '/bumdes' | '/demografi-pekerjaan' @@ -312,6 +321,7 @@ export interface FileRouteTypes { | '/' | '/admin' | '/pengaturan' + | '/profile' | '/bantuan' | '/bumdes' | '/demografi-pekerjaan' @@ -341,6 +351,7 @@ export interface RootRouteChildren { IndexRoute: typeof IndexRoute AdminRouteRoute: typeof AdminRouteRouteWithChildren PengaturanRouteRoute: typeof PengaturanRouteRouteWithChildren + ProfileRouteRoute: typeof ProfileRouteRouteWithChildren BantuanRoute: typeof BantuanRoute BumdesRoute: typeof BumdesRoute DemografiPekerjaanRoute: typeof DemografiPekerjaanRoute @@ -352,9 +363,7 @@ export interface RootRouteChildren { SigninRoute: typeof SigninRoute SignupRoute: typeof SignupRoute SosialRoute: typeof SosialRoute - ProfileEditRoute: typeof ProfileEditRoute UsersIdRoute: typeof UsersIdRoute - ProfileIndexRoute: typeof ProfileIndexRoute UsersIndexRoute: typeof UsersIndexRoute } @@ -437,6 +446,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof BantuanRouteImport parentRoute: typeof rootRouteImport } + '/profile': { + id: '/profile' + path: '/profile' + fullPath: '/profile' + preLoaderRoute: typeof ProfileRouteRouteImport + parentRoute: typeof rootRouteImport + } '/pengaturan': { id: '/pengaturan' path: '/pengaturan' @@ -467,10 +483,10 @@ declare module '@tanstack/react-router' { } '/profile/': { id: '/profile/' - path: '/profile' + path: '/' fullPath: '/profile/' preLoaderRoute: typeof ProfileIndexRouteImport - parentRoute: typeof rootRouteImport + parentRoute: typeof ProfileRouteRoute } '/admin/': { id: '/admin/' @@ -488,10 +504,10 @@ declare module '@tanstack/react-router' { } '/profile/edit': { id: '/profile/edit' - path: '/profile/edit' + path: '/edit' fullPath: '/profile/edit' preLoaderRoute: typeof ProfileEditRouteImport - parentRoute: typeof rootRouteImport + parentRoute: typeof ProfileRouteRoute } '/pengaturan/umum': { id: '/pengaturan/umum' @@ -581,10 +597,25 @@ const PengaturanRouteRouteWithChildren = PengaturanRouteRoute._addFileChildren( PengaturanRouteRouteChildren, ) +interface ProfileRouteRouteChildren { + ProfileEditRoute: typeof ProfileEditRoute + ProfileIndexRoute: typeof ProfileIndexRoute +} + +const ProfileRouteRouteChildren: ProfileRouteRouteChildren = { + ProfileEditRoute: ProfileEditRoute, + ProfileIndexRoute: ProfileIndexRoute, +} + +const ProfileRouteRouteWithChildren = ProfileRouteRoute._addFileChildren( + ProfileRouteRouteChildren, +) + const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, AdminRouteRoute: AdminRouteRouteWithChildren, PengaturanRouteRoute: PengaturanRouteRouteWithChildren, + ProfileRouteRoute: ProfileRouteRouteWithChildren, BantuanRoute: BantuanRoute, BumdesRoute: BumdesRoute, DemografiPekerjaanRoute: DemografiPekerjaanRoute, @@ -596,9 +627,7 @@ const rootRouteChildren: RootRouteChildren = { SigninRoute: SigninRoute, SignupRoute: SignupRoute, SosialRoute: SosialRoute, - ProfileEditRoute: ProfileEditRoute, UsersIdRoute: UsersIdRoute, - ProfileIndexRoute: ProfileIndexRoute, UsersIndexRoute: UsersIndexRoute, } export const routeTree = rootRouteImport diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index dc45ab2..d46ac2c 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -3,7 +3,12 @@ import { protectedRouteMiddleware } from "@/middleware/authMiddleware"; import { authStore } from "@/store/auth"; import "@mantine/core/styles.css"; import "@mantine/dates/styles.css"; -import { createRootRoute, Outlet } from "@tanstack/react-router"; +import { + createRootRoute, + Outlet, + useRouterState, +} from "@tanstack/react-router"; +import { MainLayout } from "@/components/layout/main-layout"; export const Route = createRootRoute({ component: RootComponent, @@ -21,5 +26,18 @@ export const Route = createRootRoute({ }); function RootComponent() { - return ; + const routerState = useRouterState(); + const isPublicRoute = ["/signin", "/signup", "/admin", "/profile"].some( + (path) => routerState.location.pathname.startsWith(path), + ); + + if (isPublicRoute) { + return ; + } + + return ( + + + + ); } diff --git a/src/routes/admin/index.tsx b/src/routes/admin/index.tsx index 4c6455f..940e579 100644 --- a/src/routes/admin/index.tsx +++ b/src/routes/admin/index.tsx @@ -4,7 +4,6 @@ import { Box, Button, Card, - Container, Grid, Group, Progress, @@ -55,7 +54,7 @@ function DashboardComponent() { ]; return ( - + </Grid.Col> </Grid> - </Container> + </Box> ); } diff --git a/src/routes/admin/route.tsx b/src/routes/admin/route.tsx index 3bc045a..dc33b5d 100644 --- a/src/routes/admin/route.tsx +++ b/src/routes/admin/route.tsx @@ -315,9 +315,7 @@ function DashboardLayout() { </AppShell.Navbar> <AppShell.Main> - <Box p="lg" style={{ minHeight: "calc(100vh - 100px)" }}> - <Outlet /> - </Box> + <Outlet /> </AppShell.Main> </AppShell> ); diff --git a/src/routes/bantuan.tsx b/src/routes/bantuan.tsx index 9f92ce6..000be7f 100644 --- a/src/routes/bantuan.tsx +++ b/src/routes/bantuan.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; -import { Header } from "@/components/header"; import HelpPage from "@/components/help-page"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; export const Route = createFileRoute("/bantuan")({ - component: BantuanRoute, + component: HelpPage, }); - -function BantuanRoute() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <HelpPage /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/bumdes.tsx b/src/routes/bumdes.tsx index ba70a9f..0363248 100644 --- a/src/routes/bumdes.tsx +++ b/src/routes/bumdes.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; import BumdesPage from "@/components/bumdes-page"; -import { Header } from "@/components/header"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; export const Route = createFileRoute("/bumdes")({ - component: BumdesRoute, + component: BumdesPage, }); - -function BumdesRoute() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <BumdesPage /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/demografi-pekerjaan.tsx b/src/routes/demografi-pekerjaan.tsx index 3d6641e..3da2572 100644 --- a/src/routes/demografi-pekerjaan.tsx +++ b/src/routes/demografi-pekerjaan.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; -import { Header } from "@/components/header"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; import DemografiPekerjaan from "../components/demografi-pekerjaan"; export const Route = createFileRoute("/demografi-pekerjaan")({ - component: DemografiPekerjaanPage, + component: DemografiPekerjaan, }); - -function DemografiPekerjaanPage() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <DemografiPekerjaan /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 9f1c50e..7a8c89a 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,72 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; -import { useDisclosure } from "@mantine/hooks"; import { createFileRoute } from "@tanstack/react-router"; -import { useState } from "react"; import { DashboardContent } from "@/components/dashboard-content"; -import { Header } from "@/components/header"; -import { Sidebar } from "@/components/sidebar"; export const Route = createFileRoute("/")({ - component: DashboardPage, + component: DashboardContent, }); - -function DashboardPage() { - const [opened, { toggle }] = useDisclosure(); - const [sidebarCollapsed, setSidebarCollapsed] = useDisclosure(false); - const [clickCount, setClickCount] = useState(0); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - const handleMainClick = () => { - if (!sidebarCollapsed) { - const newCount = clickCount + 1; - setClickCount(newCount); - - if (newCount === 2) { - setSidebarCollapsed.toggle(); - setClickCount(0); - } else { - setTimeout(() => setClickCount(0), 300); - } - } - }; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" /> - <Header onSidebarToggle={setSidebarCollapsed.toggle} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <DashboardContent /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/jenna-analytic.tsx b/src/routes/jenna-analytic.tsx index ba5b92b..464c28e 100644 --- a/src/routes/jenna-analytic.tsx +++ b/src/routes/jenna-analytic.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; -import { Header } from "@/components/header"; import JennaAnalytic from "@/components/jenna-analytic"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; export const Route = createFileRoute("/jenna-analytic")({ - component: JennaAnalyticPage, + component: JennaAnalytic, }); - -function JennaAnalyticPage() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <JennaAnalytic /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/keamanan.tsx b/src/routes/keamanan.tsx index 2c6b284..cfd2cf6 100644 --- a/src/routes/keamanan.tsx +++ b/src/routes/keamanan.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; -import { Header } from "@/components/header"; import KeamananPage from "@/components/keamanan-page"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; export const Route = createFileRoute("/keamanan")({ - component: KeamananRoute, + component: KeamananPage, }); - -function KeamananRoute() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <KeamananPage /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/keuangan-anggaran.tsx b/src/routes/keuangan-anggaran.tsx index 7fd3a89..496e127 100644 --- a/src/routes/keuangan-anggaran.tsx +++ b/src/routes/keuangan-anggaran.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; -import { Header } from "@/components/header"; import KeuanganAnggaran from "@/components/keuangan-anggaran"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; export const Route = createFileRoute("/keuangan-anggaran")({ - component: KeuanganAnggaranPage, + component: KeuanganAnggaran, }); - -function KeuanganAnggaranPage() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <KeuanganAnggaran /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/kinerja-divisi.tsx b/src/routes/kinerja-divisi.tsx index 9108f71..37fe932 100644 --- a/src/routes/kinerja-divisi.tsx +++ b/src/routes/kinerja-divisi.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; -import { Header } from "@/components/header"; import KinerjaDivisi from "@/components/kinerja-divisi"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; export const Route = createFileRoute("/kinerja-divisi")({ - component: KinerjaDivisiPage, + component: KinerjaDivisi, }); - -function KinerjaDivisiPage() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <KinerjaDivisi /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/pengaduan-layanan-publik.tsx b/src/routes/pengaduan-layanan-publik.tsx index 23f8f14..5f56c2d 100644 --- a/src/routes/pengaduan-layanan-publik.tsx +++ b/src/routes/pengaduan-layanan-publik.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; -import { Header } from "@/components/header"; import PengaduanLayananPublik from "@/components/pengaduan-layanan-publik"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; export const Route = createFileRoute("/pengaduan-layanan-publik")({ - component: PengaduanLayananPublikPage, + component: PengaduanLayananPublik, }); - -function PengaduanLayananPublikPage() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="md"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <PengaduanLayananPublik /> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/pengaturan/route.tsx b/src/routes/pengaturan/route.tsx index 5ed59d5..66813ed 100644 --- a/src/routes/pengaturan/route.tsx +++ b/src/routes/pengaturan/route.tsx @@ -1,84 +1,5 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; -import { useMediaQuery } from "@mantine/hooks"; -import { - createFileRoute, - Outlet, - useRouterState, -} from "@tanstack/react-router"; -import { useEffect } from "react"; -import { Header } from "@/components/header"; -import { Sidebar } from "@/components/sidebar"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; +import { createFileRoute, Outlet } from "@tanstack/react-router"; export const Route = createFileRoute("/pengaturan")({ - component: PengaturanLayout, + component: Outlet, }); - -function PengaturanLayout() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - - const isMobile = useMediaQuery("(max-width: 48em)"); - const _routerState = useRouterState(); - - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - // Auto close navbar on route change (mobile only) - useEffect(() => { - if (isMobile && opened) { - toggleMobile(); - } - }, [isMobile, opened, toggleMobile]); - - return ( - <AppShell - header={{ height: 60 }} - navbar={{ - width: 300, - breakpoint: "sm", - collapsed: { mobile: !opened, desktop: sidebarCollapsed }, - }} - padding="md" - > - <AppShell.Header bg={headerBgColor}> - <Group h="100%" px="lg" align="center" wrap="nowrap"> - <Burger - opened={opened} - onClick={toggleMobile} - hiddenFrom="sm" - size="sm" - /> - <Header onSidebarToggle={toggleSidebar} /> - </Group> - </AppShell.Header> - - <AppShell.Navbar - p="md" - bg={navbarBgColor} - style={{ display: "flex", flexDirection: "column" }} - > - <div style={{ flex: 1, overflowY: "auto" }}> - <Sidebar /> - </div> - </AppShell.Navbar> - - <AppShell.Main - bg={mainBgColor} - onClick={handleMainClick} - style={{ cursor: sidebarCollapsed ? "default" : "pointer" }} - > - <div className="p-2"> - <Outlet /> - </div> - </AppShell.Main> - </AppShell> - ); -} diff --git a/src/routes/profile/edit.tsx b/src/routes/profile/edit.tsx index ff857bf..007d175 100644 --- a/src/routes/profile/edit.tsx +++ b/src/routes/profile/edit.tsx @@ -1,7 +1,7 @@ import { + Box, Button, Card, - Container, Divider, Group, Stack, @@ -63,77 +63,72 @@ function EditProfile() { }; return ( - <Container size="sm" py={50}> - <Stack gap="xl"> - <Group justify="space-between" align="center"> - <Box> - <Title order={1} c="orange.6"> - Edit Profil - - - Perbarui informasi profil publik Anda - - - - - - - - + + + + Edit Profil + + + Perbarui informasi profil publik Anda + + + - - - - - + Kembali + + + + + + +
+ + + + + +
+
+ ); } - -// Need Box from @mantine/core -import { Box } from "@mantine/core"; diff --git a/src/routes/profile/index.tsx b/src/routes/profile/index.tsx index f9f287d..1bd3648 100644 --- a/src/routes/profile/index.tsx +++ b/src/routes/profile/index.tsx @@ -6,7 +6,6 @@ import { Button, Card, Code, - Container, Divider, Grid, Group, @@ -141,213 +140,211 @@ function Profile() { ); return ( - - - {/* Header Section */} - - - - Profil Saya - - - Kelola informasi akun dan pengaturan keamanan Anda - - - - {snap.user?.role === "admin" && ( - - )} + + {/* Header Section */} + + + + Profil Saya + + + Kelola informasi akun dan pengaturan keamanan Anda + + + + {snap.user?.role === "admin" && ( - - + )} + + + - + - {/* Profile Overview Card */} - - - - - - {snap.user?.name?.charAt(0).toUpperCase()} - - - {snap.user?.name} - - - {snap.user?.email} + {/* Profile Overview Card */} + + + + + + {snap.user?.name?.charAt(0).toUpperCase()} + + + {snap.user?.name} + + + {snap.user?.email} + + + • + + + {snap.user?.role || "user"} + + + + + + + + + + + + Informasi Identitas + + + + + + + + + + + + + + + + + + + + + + Keamanan & Sesi + + + + + + Sesi Saat Ini - - • + + + Aktif Sekarang + + + ID: {snap.session?.id?.substring(0, 8)}... + + + + + + + Session Token - - {snap.user?.role || "user"} - - + + + {snap.session?.token + ? `${snap.session.token.substring(0, 32)}...` + : "N/A"} + + + snap.session?.token && + copyToClipboard(snap.session.token, "token") + } + > + {copied === "token" ? ( + + ) : ( + + )} + + + + + - - - - - - - - - Informasi Identitas - - - - - - - - - - - - - - - - - - - - - - Keamanan & Sesi - - - - - - Sesi Saat Ini - - - - Aktif Sekarang - - - ID: {snap.session?.id?.substring(0, 8)}... - - - - - - - Session Token - - - - {snap.session?.token - ? `${snap.session.token.substring(0, 32)}...` - : "N/A"} - - - snap.session?.token && - copyToClipboard(snap.session.token, "token") - } - > - {copied === "token" ? ( - - ) : ( - - )} - - - - - - - - - - - - + + + + + ); } diff --git a/src/routes/profile/route.tsx b/src/routes/profile/route.tsx new file mode 100644 index 0000000..fbece82 --- /dev/null +++ b/src/routes/profile/route.tsx @@ -0,0 +1,69 @@ +import { + AppShell, + Button, + Container, + Group, + Text, + useMantineColorScheme, +} from "@mantine/core"; +import { IconChevronLeft } from "@tabler/icons-react"; +import { createFileRoute, Outlet, useNavigate } from "@tanstack/react-router"; + +export const Route = createFileRoute("/profile")({ + component: ProfileLayout, +}); + +function ProfileLayout() { + const navigate = useNavigate(); + const { colorScheme } = useMantineColorScheme(); + const dark = colorScheme === "dark"; + + return ( + + + + + + + + + + PENGATURAN AKUN + + + + + + + + + + + ); +} + +import { Box } from "@mantine/core"; diff --git a/src/routes/sosial.tsx b/src/routes/sosial.tsx index 344cb7b..c8c6190 100644 --- a/src/routes/sosial.tsx +++ b/src/routes/sosial.tsx @@ -1,66 +1,6 @@ -import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { createFileRoute } from "@tanstack/react-router"; -import { Header } from "@/components/header"; -import { Sidebar } from "@/components/sidebar"; import SosialPage from "@/components/sosial-page"; -import { useSidebarFullscreen } from "@/hooks/use-sidebar-fullscreen"; export const Route = createFileRoute("/sosial")({ - component: SosialRoute, + component: SosialPage, }); - -function SosialRoute() { - const { - opened, - toggleMobile, - sidebarCollapsed, - toggleSidebar, - handleMainClick, - } = useSidebarFullscreen(); - const { colorScheme } = useMantineColorScheme(); - const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; - const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; - const mainBgColor = colorScheme === "dark" ? "#11192D" : "#edf3f8ff"; - - return ( - - - - -
- - - - -
- -
-
- - - - - - ); -}