Files
motovaultpro/frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx
2026-02-13 19:39:16 -06:00

160 lines
4.6 KiB
TypeScript

/**
* @ai-summary Hamburger menu drawer for mobile navigation
* @ai-context Bottom slide-up drawer with all navigation options
*/
import React from 'react';
import {
Box,
SwipeableDrawer,
List,
ListItemButton,
ListItemIcon,
ListItemText,
Typography,
useTheme
} from '@mui/material';
import HomeRoundedIcon from '@mui/icons-material/HomeRounded';
import DirectionsCarRoundedIcon from '@mui/icons-material/DirectionsCarRounded';
import LocalGasStationRoundedIcon from '@mui/icons-material/LocalGasStationRounded';
import DescriptionRoundedIcon from '@mui/icons-material/DescriptionRounded';
import BuildRoundedIcon from '@mui/icons-material/BuildRounded';
import SettingsRoundedIcon from '@mui/icons-material/SettingsRounded';
import { MobileScreen } from '../../../core/store/navigation';
// iOS swipeable drawer configuration
const iOS = typeof navigator !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent);
interface HamburgerDrawerProps {
open: boolean;
onClose: () => void;
onNavigate: (screen: MobileScreen) => void;
activeScreen: MobileScreen;
}
interface MenuItem {
screen: MobileScreen;
label: string;
icon: React.ReactNode;
}
// Menu items from bottom to top (reversed order in array for rendering)
const menuItems: MenuItem[] = [
{ screen: 'Settings', label: 'Settings', icon: <SettingsRoundedIcon /> },
{ screen: 'Documents', label: 'Documents', icon: <DescriptionRoundedIcon /> },
{ screen: 'Maintenance', label: 'Maintenance', icon: <BuildRoundedIcon /> },
{ screen: 'Log Fuel', label: 'Log Fuel', icon: <LocalGasStationRoundedIcon /> },
{ screen: 'Vehicles', label: 'Vehicles', icon: <DirectionsCarRoundedIcon /> },
{ screen: 'Dashboard', label: 'Dashboard', icon: <HomeRoundedIcon /> },
];
export const HamburgerDrawer: React.FC<HamburgerDrawerProps> = ({
open,
onClose,
onNavigate,
activeScreen
}) => {
const theme = useTheme();
const handleNavigate = (screen: MobileScreen) => {
onNavigate(screen);
onClose();
};
return (
<SwipeableDrawer
anchor="bottom"
open={open}
onClose={onClose}
onOpen={() => {}}
disableSwipeToOpen
disableBackdropTransition={!iOS}
disableDiscovery={iOS}
sx={{
'& .MuiDrawer-paper': {
borderTopLeftRadius: 16,
borderTopRightRadius: 16,
maxHeight: '60vh',
overflow: 'visible'
}
}}
>
<Box sx={{ pb: 4 }}>
{/* Drawer handle */}
<Box
sx={{
width: 40,
height: 4,
backgroundColor: theme.palette.divider,
borderRadius: 2,
margin: '12px auto 8px'
}}
/>
{/* Header */}
<Typography
variant="subtitle1"
sx={{
fontWeight: 600,
px: 2,
py: 1.5,
color: theme.palette.text.secondary
}}
>
Menu
</Typography>
{/* Menu Items */}
<List disablePadding>
{menuItems.map(({ screen, label, icon }) => {
const isActive = activeScreen === screen;
return (
<ListItemButton
key={screen}
onClick={() => handleNavigate(screen)}
sx={{
py: 1.5,
px: 2,
minHeight: 56,
backgroundColor: isActive
? theme.palette.primary.main + '14'
: 'transparent',
borderLeft: isActive
? `3px solid ${theme.palette.primary.main}`
: '3px solid transparent',
'&:hover': {
backgroundColor: isActive
? theme.palette.primary.main + '20'
: theme.palette.action.hover
}
}}
>
<ListItemIcon
sx={{
minWidth: 40,
color: isActive
? theme.palette.primary.main
: theme.palette.text.secondary
}}
>
{icon}
</ListItemIcon>
<ListItemText
primary={label}
primaryTypographyProps={{
fontWeight: isActive ? 600 : 500,
fontSize: '0.95rem',
color: isActive
? theme.palette.primary.main
: theme.palette.text.primary
}}
/>
</ListItemButton>
);
})}
</List>
</Box>
</SwipeableDrawer>
);
};