refactor(ui): fix layout issues and temporarily disable auth features
- app & navbar: comment out login, register, and logout features. - scan-page: align info cards vertically and reduce upload area padding. - mobile-nav: implement React Portal to fix overlapping menu issue.
This commit is contained in:
+8
-10
@@ -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,16 +14,16 @@ 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";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{ path: "/", element: <Navigate to="/dashboard" replace /> },
|
||||
{ path: "/login", element: <LoginPage /> },
|
||||
{ path: "/register", element: <RegisterPage /> },
|
||||
// { path: "/login", element: <LoginPage /> },
|
||||
// { path: "/register", element: <RegisterPage /> },
|
||||
{
|
||||
path: "/dashboard",
|
||||
element: (
|
||||
@@ -67,11 +67,9 @@ const router = createBrowserRouter([
|
||||
{
|
||||
path: "/expert/reviews",
|
||||
element: (
|
||||
<AuthGuard requireExpert>
|
||||
<MainLayout>
|
||||
<ExpertReviewsPage />
|
||||
</MainLayout>
|
||||
</AuthGuard>
|
||||
<MainLayout>
|
||||
<ExpertReviewsPage />
|
||||
</MainLayout>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,38 +1,58 @@
|
||||
import { createPortal } from "react-dom";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import { X, Leaf } from "lucide-react";
|
||||
|
||||
type Props = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
userRole?: string | null;
|
||||
};
|
||||
|
||||
const NAV_ITEMS = [
|
||||
{ path: "/dashboard", label: "Dashboard" },
|
||||
{ path: "/scan", label: "Scan Tanaman" },
|
||||
{ path: "/diagnoses", label: "Diagnosa" },
|
||||
{ path: "/catalog", label: "Pustaka" },
|
||||
{ path: "/catalog", label: "Pustaka", altPath: "/library" },
|
||||
];
|
||||
|
||||
export function MobileNav({ open, onClose, userRole }: Props) {
|
||||
export function MobileNav({ open, onClose }: Props) {
|
||||
const location = useLocation();
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
const isActive = (path: string) => location.pathname === path;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 lg:hidden">
|
||||
const navContent = (
|
||||
<div
|
||||
// 2. Ubah z-50 menjadi z-[999] agar levelnya mentok paling atas
|
||||
className={`fixed inset-0 z-[999] lg:hidden transition-opacity duration-300 ease-in-out ${
|
||||
open ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||
}`}
|
||||
aria-hidden={!open}
|
||||
>
|
||||
{/* Backdrop */}
|
||||
<div className="fixed inset-0 bg-black/40" onClick={onClose} />
|
||||
<div
|
||||
className="fixed inset-0 bg-black/60 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
/>
|
||||
|
||||
{/* Panel */}
|
||||
<div className="fixed inset-y-0 right-0 z-50 w-full max-w-sm bg-[#306D29] shadow-xl">
|
||||
<div className="flex items-center justify-between px-6 h-20 border-b border-white/10">
|
||||
<div
|
||||
className={`fixed inset-y-0 right-0 z-[999] flex w-full max-w-sm flex-col bg-[#306D29] shadow-2xl transition-transform duration-300 ease-in-out ${
|
||||
open ? "translate-x-0" : "translate-x-full"
|
||||
}`}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-6 h-20 border-b border-white/10 shrink-0">
|
||||
<div className="flex items-center gap-3 font-semibold text-white">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-2xl bg-[#48A111]">
|
||||
<Leaf className="h-5 w-5" />
|
||||
<Link to="/dashboard" onClick={onClose}>
|
||||
<Leaf className="h-5 w-5" />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="leading-tight">
|
||||
<div className="text-lg font-bold">ZeaVis Edu</div>
|
||||
<div className="text-[13px] font-normal text-[#9AD872]">
|
||||
Smart AI for Corn Disease Detection
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-lg font-bold">ZeaVis Edu</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
@@ -43,9 +63,11 @@ export function MobileNav({ open, onClose, userRole }: Props) {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<nav className="flex flex-col gap-2 px-4 pt-6">
|
||||
{/* Nav items */}
|
||||
<nav className="flex flex-col gap-2 overflow-y-auto px-4 py-6 flex-1">
|
||||
{NAV_ITEMS.map((item) => {
|
||||
const active = isActive(item.path);
|
||||
const active =
|
||||
isActive(item.path) || (item.altPath && isActive(item.altPath));
|
||||
return (
|
||||
<Link
|
||||
key={item.path}
|
||||
@@ -61,22 +83,12 @@ export function MobileNav({ open, onClose, userRole }: Props) {
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
{userRole === "expert" && (
|
||||
<Link
|
||||
to="/expert/reviews"
|
||||
onClick={onClose}
|
||||
className={`rounded-full px-4 py-3 text-[16px] font-medium transition-colors ${
|
||||
isActive("/expert/reviews")
|
||||
? "bg-[#48A111] text-white shadow-sm"
|
||||
: "text-white/85 hover:bg-white/10 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
Review
|
||||
</Link>
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return typeof document !== "undefined"
|
||||
? createPortal(navContent, document.body)
|
||||
: navContent;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import { Leaf, Menu } from "lucide-react";
|
||||
import { MobileNav } from "./mobile-nav";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useAuthStore } from "@/store/auth-store";
|
||||
import { apiClient } from "@/lib/api-client";
|
||||
|
||||
export function Navbar() {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const setUser = useAuthStore((state) => state.setUser);
|
||||
const user = useAuthStore((state) => state.user);
|
||||
//
|
||||
|
||||
const isActive = (path: string) => location.pathname === path;
|
||||
|
||||
@@ -25,17 +18,6 @@ export function Navbar() {
|
||||
: "text-white/85 hover:bg-white/10 hover:text-white",
|
||||
].join(" ");
|
||||
|
||||
const logoutMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
await apiClient.logout();
|
||||
},
|
||||
onSuccess: () => {
|
||||
setUser(null);
|
||||
queryClient.clear();
|
||||
navigate("/login");
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-40 bg-[#306D29] text-white shadow-sm backdrop-blur">
|
||||
<div className="mx-auto flex h-20 max-w-6xl items-center justify-between px-6">
|
||||
@@ -54,26 +36,35 @@ export function Navbar() {
|
||||
</div>
|
||||
|
||||
<nav className="hidden lg:flex items-center gap-2">
|
||||
<Link to="/dashboard" className={navLinkClassName(isActive("/dashboard"))}>
|
||||
<Link
|
||||
to="/dashboard"
|
||||
className={navLinkClassName(isActive("/dashboard"))}
|
||||
>
|
||||
Dashboard
|
||||
</Link>
|
||||
<Link to="/scan" className={navLinkClassName(isActive("/scan"))}>
|
||||
Scan Tanaman
|
||||
</Link>
|
||||
<Link to="/diagnoses" className={navLinkClassName(isActive("/diagnoses"))}>
|
||||
<Link
|
||||
to="/diagnoses"
|
||||
className={navLinkClassName(isActive("/diagnoses"))}
|
||||
>
|
||||
Diagnosa
|
||||
</Link>
|
||||
<Link to="/catalog" className={navLinkClassName(isActive("/catalog") || isActive("/library"))}>
|
||||
<Link
|
||||
to="/catalog"
|
||||
className={navLinkClassName(
|
||||
isActive("/catalog") || isActive("/library"),
|
||||
)}
|
||||
>
|
||||
Pustaka
|
||||
</Link>
|
||||
{user?.role === "expert" && (
|
||||
<Link
|
||||
to="/expert/reviews"
|
||||
className={navLinkClassName(isActive("/expert/reviews"))}
|
||||
>
|
||||
Review
|
||||
</Link>
|
||||
)}
|
||||
<Link
|
||||
to="/expert/reviews"
|
||||
className={navLinkClassName(isActive("/expert/reviews"))}
|
||||
>
|
||||
Review
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
<button
|
||||
|
||||
@@ -103,7 +103,7 @@ export function ScanPage() {
|
||||
{!previewUrl ? (
|
||||
<div className="space-y-3">
|
||||
<div
|
||||
className="w-full border-2 border-dashed border-green-300 rounded-md p-12 h-60 text-center cursor-pointer"
|
||||
className="w-full border-2 border-dashed border-green-300 rounded-md p-10 h-60 text-center cursor-pointer"
|
||||
onClick={() => inputRef.current?.click()}
|
||||
>
|
||||
<Upload className="mx-auto text-green-500 mb-3" size={48} />
|
||||
|
||||
Reference in New Issue
Block a user