diff --git a/web/src/components/Sidebar.tsx b/web/src/components/Sidebar.tsx index 639b6f9..03ad977 100644 --- a/web/src/components/Sidebar.tsx +++ b/web/src/components/Sidebar.tsx @@ -1,5 +1,5 @@ import { useLocation, useNavigate } from 'react-router-dom'; -import { useSelector } from 'react-redux'; +import { useSelector, useDispatch } from 'react-redux'; import { Drawer, List, @@ -9,6 +9,9 @@ import { Toolbar, Box, Typography, + Tooltip, + useMediaQuery, + useTheme, } from '@mui/material'; import DashboardIcon from '@mui/icons-material/Dashboard'; import DescriptionIcon from '@mui/icons-material/Description'; @@ -16,11 +19,13 @@ import AddCircleIcon from '@mui/icons-material/AddCircle'; import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; import AssignmentIcon from '@mui/icons-material/Assignment'; import PeopleIcon from '@mui/icons-material/People'; -import { selectSidebarOpen } from '../app/slices/uiSlice'; +import { selectSidebarOpen, setSidebarOpen } from '../app/slices/uiSlice'; import { selectUser } from '../app/slices/authSlice'; import type { RootState } from '../app/store'; import { DRAWER_WIDTH } from '../constants'; +const COLLAPSED_WIDTH = 72; + const dispatcherNav = [ { label: 'Dashboard', path: '/', icon: }, { label: 'My Proposals', path: '/proposals', icon: }, @@ -50,126 +55,131 @@ function isNavActive(pathname: string, itemPath: string): boolean { export default function Sidebar() { const navigate = useNavigate(); const location = useLocation(); + const dispatch = useDispatch(); + const theme = useTheme(); const open = useSelector((state: RootState) => selectSidebarOpen(state)); const user = useSelector((state: RootState) => selectUser(state)); + const isMobile = useMediaQuery(theme.breakpoints.down('md')); // <900px + const isCollapsed = useMediaQuery(theme.breakpoints.between('md', 'lg')); // 900–1200px + const isAdmin = user?.role === 'Admin' || user?.role === 'SysAdmin'; const isSysAdmin = user?.role === 'SysAdmin'; const navItems = dispatcherNav; + const drawerVariant = isMobile ? 'temporary' : 'persistent'; + const effectiveWidth = isCollapsed ? COLLAPSED_WIDTH : DRAWER_WIDTH; + + const handleNavClick = (path: string) => { + navigate(path); + if (isMobile) { + dispatch(setSidebarOpen(false)); + } + }; + + const handleDrawerClose = () => { + dispatch(setSidebarOpen(false)); + }; + + const renderNavItem = (item: { label: string; path: string; icon: React.ReactNode }) => { + const button = ( + handleNavClick(item.path)} + sx={{ + py: 1, + justifyContent: isCollapsed ? 'center' : 'flex-start', + minHeight: 40, + }} + > + + {item.icon} + + {!isCollapsed && ( + + )} + + ); + + if (isCollapsed) { + return ( + + {button} + + ); + } + + return button; + }; + return ( - - Proposals - - - {navItems.map((item) => ( - navigate(item.path)} - sx={{ py: 1 }} - > - {item.icon} - - - ))} - - {isAdmin && ( <> - - Admin - + {!isCollapsed && ( + + Admin + + )} - {adminNav.map((item) => ( - navigate(item.path)} - sx={{ py: 1 }} - > - {item.icon} - - - ))} - {isSysAdmin && sysadminNav.map((item) => ( - navigate(item.path)} - sx={{ py: 1 }} - > - {item.icon} - - - ))} + {adminNav.map((item) => renderNavItem(item))} + {isSysAdmin && sysadminNav.map((item) => renderNavItem(item))} )} - - Proposals - + {!isCollapsed && ( + + Proposals + + )} - {navItems.map((item) => ( - navigate(item.path)} - sx={{ py: 1 }} - > - {item.icon} - - - ))} + {navItems.map((item) => renderNavItem(item))} - {user && ( + {user && !isCollapsed && ( {user.displayName} {user.role}