From 56139388d369a499bd02f4c98b89b9c53d9960f7 Mon Sep 17 00:00:00 2001 From: seriouselly Date: Mon, 8 Jun 2026 00:20:00 +0700 Subject: [PATCH 1/5] feat(auth): implement full logout system and protect application routes - Add LogoutProses function in app.tsx to destroy session via apiClient.logout() and clear user state - Apply to private routes (/dashboard, /scan, /expert/reviews, etc.) to prevent unauthorized access - Update the "Logout" button design in Navbar and MobileNav with a red accent and LogOut icon - Fix vulnerability allowing direct URL access to the dashboard by bypassing login --- apps/web/src/app.tsx | 101 ++++++++++++------ apps/web/src/components/layout/mobile-nav.tsx | 11 +- apps/web/src/components/layout/navbar.tsx | 12 ++- 3 files changed, 89 insertions(+), 35 deletions(-) diff --git a/apps/web/src/app.tsx b/apps/web/src/app.tsx index 93b7301..5626052 100644 --- a/apps/web/src/app.tsx +++ b/apps/web/src/app.tsx @@ -5,7 +5,7 @@ import { Navigate, } from "react-router-dom"; import { AuthInitializer } from "@/components/auth-initializer"; -// import { AuthGuard } from "@/components/auth-guard"; +import { AuthGuard } from "@/components/auth-guard"; import { DashboardPage } from "@/pages/dashboard-page"; import { ScanPage } from "@/pages/scan-page"; import { LibraryPage } from "@/pages/library-page"; @@ -14,78 +14,119 @@ import { DiseaseDetailPage } from "@/pages/disease-detail-page"; import { DiagnosisDetailPage } from "@/pages/diagnosis-detail-page"; import { ExpertReviewsPage } from "@/pages/expert-reviews-page"; import { DiagnosesPage } from "@/pages/diagnoses-page"; -// import { LoginPage } from "@/pages/login-page"; -// import { RegisterPage } from "@/pages/register-page"; +import { LoginPage } from "@/pages/login-page"; +import { RegisterPage } from "@/pages/register-page"; import { MainLayout } from "@/components/layout/main-layout"; +import { useEffect } from "react"; +import { useAuthStore } from "@/store/auth-store"; +import { apiClient } from "@/lib/api-client"; + +function LogoutProses() { + const setUser = useAuthStore((state) => state.setUser); + + useEffect(() => { + apiClient.logout().then(() => { + setUser(null); + + }).catch((error) => { + console.error("Oops, gagal logout dari server:", error); + setUser(null); + }); + }, [setUser]); + + return ; +} const queryClient = new QueryClient(); const router = createBrowserRouter([ - { path: "/", element: }, - // { path: "/login", element: }, - // { path: "/register", element: }, + { path: "/", element: }, + { path: "/login", element: }, + { path: "/register", element: }, { path: "/dashboard", element: ( - - - + + + + + ), }, { path: "/scan", element: ( - - - + + + + + ), }, { path: "/library", element: ( - - - + + + + + ), }, { path: "/diagnoses", element: ( - - - + + + + + ), }, { path: "/diagnoses/:id", element: ( - - - + + + + + ), }, { path: "/expert/reviews", element: ( - - - + + + + + ), }, { path: "/catalog", element: ( - - - + + + + + ), }, { path: "/catalog/:slug", element: ( - - - + + + + + + ), + }, + { + path: "/logout", + element: ( + ), }, ]); diff --git a/apps/web/src/components/layout/mobile-nav.tsx b/apps/web/src/components/layout/mobile-nav.tsx index c5f68dc..a28c161 100644 --- a/apps/web/src/components/layout/mobile-nav.tsx +++ b/apps/web/src/components/layout/mobile-nav.tsx @@ -1,6 +1,6 @@ import { createPortal } from "react-dom"; import { Link, useLocation } from "react-router-dom"; -import { X, Leaf } from "lucide-react"; +import { X, Leaf, LogOut } from "lucide-react"; type Props = { open: boolean; @@ -22,7 +22,6 @@ export function MobileNav({ open, onClose }: Props) { const navContent = (
); })} + + Keluar + +
diff --git a/apps/web/src/components/layout/navbar.tsx b/apps/web/src/components/layout/navbar.tsx index 20993e1..f5511d5 100644 --- a/apps/web/src/components/layout/navbar.tsx +++ b/apps/web/src/components/layout/navbar.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { Link, useLocation } from "react-router-dom"; -import { Leaf, Menu } from "lucide-react"; +import { Leaf, LogOut, Menu } from "lucide-react"; import { MobileNav } from "./mobile-nav"; export function Navbar() { @@ -43,7 +43,7 @@ export function Navbar() { Dashboard - Scan Tanaman + Scan Daun - Review + Hasil Pakar + + + Keluar From af69dc4df7459327199fb30e951389db36154db4 Mon Sep 17 00:00:00 2001 From: seriouselly Date: Mon, 8 Jun 2026 21:00:55 +0700 Subject: [PATCH 2/5] refactor(layout): implement responsive sidebar and synchronize mobile menu - Create a new `Sidebar` component for desktop with collapse/mini-sidebar feature. - Rename `navbar.tsx` to `mobile-header.tsx` to better reflect its mobile-specific purpose. - Synchronize icons (from lucide-react) and menu labels between desktop `Sidebar` and touch-based `MobileNav`. - Fix 'Logout' button sizing in the mobile menu by removing forced margins for better responsiveness on narrow screens. - Remove conflicting 'aria-hidden' attribute in MobileNav to resolve browser accessibility (a11y) warnings. - Add a spacer in `main-layout.tsx` to prevent the bottom content from being overlapped by the fixed Footer. --- apps/web/src/components/layout/footer.tsx | 4 +- .../web/src/components/layout/main-layout.tsx | 59 +++++++- apps/web/src/components/layout/mobile-nav.tsx | 64 +++++--- apps/web/src/components/layout/navbar.tsx | 97 ------------ apps/web/src/components/layout/sidebar.tsx | 139 ++++++++++++++++++ 5 files changed, 232 insertions(+), 131 deletions(-) delete mode 100644 apps/web/src/components/layout/navbar.tsx create mode 100644 apps/web/src/components/layout/sidebar.tsx diff --git a/apps/web/src/components/layout/footer.tsx b/apps/web/src/components/layout/footer.tsx index 6995856..669f1d8 100644 --- a/apps/web/src/components/layout/footer.tsx +++ b/apps/web/src/components/layout/footer.tsx @@ -1,7 +1,7 @@ export function Footer() { return ( -