import React, { useRef, useState, useEffect } from 'react'; import { Outlet, NavLink, useNavigate, useLocation } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; import { useTheme } from '../context/ThemeContext'; import { LayoutDashboard, Map, Calendar, LogOut, User, Home, MessageSquare, ChevronLeft, ChevronRight, Sun, Moon, Trophy, Users, Briefcase, FileText, Menu, X } from 'lucide-react'; import PageTransition from './PageTransition'; import Chatbot from './Chatbot'; import Logo from '../assets/images/LynkedUp_Icon.png'; const SidebarItem = ({ to, icon: Icon, label, isCollapsed, onClick }) => { return ( ` group relative flex items-center px-3 py-3 rounded-xl mb-1 transition-all duration-200 outline-none ${isCollapsed ? 'justify-center' : 'space-x-3'} ${isActive ? 'text-zinc-900 dark:text-white font-semibold' : 'text-zinc-500 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-white' } ` } > {({ isActive }) => ( <> {/* Glow/Border Effect Container */}
{/* Sharp Border */}
{/* Masking Background (Creates the border look) */}
{/* Content */} {label} {'S'}{'.'}{'a'}{'.'}{'t'}{'.'}{'y'}{'.'}{'a'}{'.'}{'m'}{'.'} {/* Collapsed Tooltip */} {isCollapsed && (
{label}
)} )} ); }; const Layout = () => { const { user, logout } = useAuth(); const { theme, toggleTheme } = useTheme(); const navigate = useNavigate(); const location = useLocation(); // -- State -- // Desktop: User controls collapse manually. Default open. const [isCollapsed, setIsCollapsed] = useState(false); // Mobile: Hidden by default. const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const handleLogout = () => { logout(); navigate('/login'); }; // Close mobile menu on route change useEffect(() => { setIsMobileMenuOpen(false); }, [location.pathname]); // Body scroll lock when mobile menu is open useEffect(() => { document.body.style.overflow = isMobileMenuOpen ? 'hidden' : ''; return () => { document.body.style.overflow = ''; }; }, [isMobileMenuOpen]); // Keyboard Accessibility: Close mobile menu on ESC useEffect(() => { const handleEsc = (e) => { if (e.key === 'Escape') { setIsMobileMenuOpen(false); } }; window.addEventListener('keydown', handleEsc); return () => window.removeEventListener('keydown', handleEsc); }, []); // Determine standard layout vs full screen for Public pages const isPublic = ['/', '/login'].includes(location.pathname); if (isPublic) { return ( ); } // Role-specific Navigation Items const getNavItems = () => { if (!user) return []; const commonItems = [ { to: "/", icon: Home, label: "Home" }, { to: "/chat-assistant", icon: MessageSquare, label: "AI Assistant" }, ]; switch (user.role) { case 'OWNER': return [ { to: "/owner/snapshot", icon: LayoutDashboard, label: "Dashboard" }, { to: "/owner/projects", icon: Briefcase, label: "Projects" }, { to: "/owner/vendors", icon: Users, label: "Vendors" }, { to: "/owner/people", icon: User, label: "People" }, { to: "/owner/documents", icon: FileText, label: "Documents" }, { to: "/owner/maps", icon: Map, label: "Territory Map" }, // Admin pages — Owner is superuser { to: "/admin/dashboard", icon: LayoutDashboard, label: "Admin Panel" }, { to: "/admin/schedule", icon: Calendar, label: "Team Schedule" }, { to: "/admin/leaderboard", icon: Trophy, label: "Leaderboard" }, ...commonItems ]; case 'ADMIN': return [ { to: "/admin/dashboard", icon: LayoutDashboard, label: "Dashboard" }, { to: "/admin/schedule", icon: Calendar, label: "Schedule" }, { to: "/admin/leaderboard", icon: Trophy, label: "Leaderboard" }, { to: "/admin/maps", icon: Map, label: "Territory Map" }, ...commonItems ]; case 'CONTRACTOR': case 'SUBCONTRACTOR': return [ { to: user.role === 'CONTRACTOR' ? "/contractor/dashboard" : "/subcontractor/dashboard", icon: LayoutDashboard, label: "Dashboard" }, { to: user.role === 'CONTRACTOR' ? "/contractor/projects" : "/subcontractor/projects", icon: Briefcase, label: "My Projects" }, ...commonItems ]; case 'VENDOR': return [ { to: "/vendor/dashboard", icon: LayoutDashboard, label: "Dashboard" }, { to: "/vendor/orders", icon: Briefcase, label: "Orders" }, ...commonItems ]; case 'FIELD_AGENT': return [ { to: "/emp/fa/dashboard", icon: LayoutDashboard, label: "Dashboard" }, { to: "/emp/fa/maps", icon: Map, label: "My Map" }, ...commonItems ]; default: // Customer or Fallback return [ { to: "/customer/profile", icon: LayoutDashboard, label: "Dashboard" }, ...commonItems ]; } }; const navItems = getNavItems(); return (
{/* --- Mobile Header --- */}
LynkedUp Pro LynkedUp Pro
{/* --- Mobile Backdrop --- */} {isMobileMenuOpen && (
setIsMobileMenuOpen(false)} aria-hidden="true" /> )} {/* --- Sidebar --- */} {/* --- Main Content --- */}
); }; export default Layout;