chore: add the new menu for private mode - admin
This commit is contained in:
parent
e85a401209
commit
91ed5ccaa5
@ -2,6 +2,7 @@ import { useState } from 'react';
|
||||
import { AppBar, Toolbar, Typography, IconButton, Box, Avatar } from '@mui/material';
|
||||
|
||||
import MenuDrawer from './MenuDrawer';
|
||||
import MenuDrawerPrivate from './MenuDrawerPrivate';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
@ -86,7 +87,7 @@ export default function AppHeader({ zone = 'public', onSelectMenuItem }) {
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<MenuDrawer
|
||||
<MenuDrawerPrivate
|
||||
zone="private"
|
||||
onSelect={handleMenuSelect}
|
||||
onExpandedChange={(expanded) => setDrawerExpanded(expanded)}
|
||||
|
||||
299
src/components/MenuDrawerPrivate.jsx
Normal file
299
src/components/MenuDrawerPrivate.jsx
Normal file
@ -0,0 +1,299 @@
|
||||
// src/components/MenuDrawerPrivate.jsx
|
||||
import React, { useMemo, useState, useEffect } from 'react';
|
||||
import {
|
||||
Drawer, List, ListItemButton, ListItemIcon, ListItemText,
|
||||
Collapse, IconButton, Tooltip, Box, useMediaQuery, InputBase
|
||||
} from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
// MUI icons (you can replace with your PNGs later)
|
||||
import InsightsIcon from '@mui/icons-material/Insights';
|
||||
import Inventory2Icon from '@mui/icons-material/Inventory2';
|
||||
import PeopleAltIcon from '@mui/icons-material/PeopleAlt';
|
||||
import BusinessIcon from '@mui/icons-material/Business';
|
||||
import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import ExpandLess from '@mui/icons-material/ExpandLess';
|
||||
import ExpandMore from '@mui/icons-material/ExpandMore';
|
||||
|
||||
const OPEN_WIDTH = 400;
|
||||
const MINI_WIDTH = 72;
|
||||
|
||||
// ---- Hierarchy (from your diagram). Leaves are "CRUD" pages (clickables). ----
|
||||
const menuData = [
|
||||
{
|
||||
title: 'Business Intelligence',
|
||||
icon: <InsightsIcon />,
|
||||
children: [
|
||||
{ title: 'Sales Report' },
|
||||
{ title: 'Customer Insights' },
|
||||
{ title: 'Customer Insights 2' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Products Management',
|
||||
icon: <Inventory2Icon />,
|
||||
children: [
|
||||
{
|
||||
title: 'Catalog Management',
|
||||
children: [
|
||||
{
|
||||
title: 'Category Dictionary',
|
||||
children: [
|
||||
{ title: 'Categories' },
|
||||
{ title: 'Products' },
|
||||
{ title: 'All Assets Library' },
|
||||
{ title: 'Media Management' },
|
||||
{ title: 'Product Collections' },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Customers',
|
||||
icon: <PeopleAltIcon />,
|
||||
children: [
|
||||
{ title: 'CRM' },
|
||||
{ title: 'Customer List' },
|
||||
{
|
||||
title: 'Projects',
|
||||
children: [
|
||||
{ title: 'Customer Collections' },
|
||||
{ title: 'Sales' },
|
||||
{ title: 'Quotes' },
|
||||
{ title: 'Orders' },
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Providers (Brands and Clients)',
|
||||
icon: <BusinessIcon />,
|
||||
children: [
|
||||
{ title: 'Brand Partners' },
|
||||
{ title: 'Companies' },
|
||||
{ title: 'Suppliers' },
|
||||
{ title: 'Materials Providers' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Users',
|
||||
icon: <AdminPanelSettingsIcon />,
|
||||
children: [
|
||||
{ title: 'Users Management' },
|
||||
{ title: 'Access Control' },
|
||||
{ title: 'Roles' },
|
||||
{ title: 'Permissions' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
icon: <SettingsIcon />,
|
||||
children: [
|
||||
{ title: 'General Settings' },
|
||||
{ title: 'WebApp Configuration' },
|
||||
{ title: 'Mobile App Configuration' },
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
export default function MenuDrawerPrivate({
|
||||
open, // optional: for mobile temporary drawer
|
||||
onClose, // optional: for mobile temporary drawer
|
||||
onSelect, // (title) => void
|
||||
onExpandedChange, // (boolean) => void // optional: tell header if expanded/collapsed
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery('(max-width:900px)');
|
||||
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
// open states per branch key
|
||||
const [openMap, setOpenMap] = useState({});
|
||||
|
||||
// keep collapsed in sync only if "open" prop provided (mobile)
|
||||
useEffect(() => {
|
||||
if (!isMobile) return;
|
||||
if (typeof open === 'boolean') {
|
||||
// temporary drawer: collapsed UI is not shown on mobile, treat as expanded
|
||||
setCollapsed(false);
|
||||
}
|
||||
}, [open, isMobile]);
|
||||
|
||||
// inform parent of expanded/collapsed (desktop)
|
||||
useEffect(() => {
|
||||
onExpandedChange?.(isMobile ? true : !collapsed);
|
||||
}, [collapsed, isMobile, onExpandedChange]);
|
||||
|
||||
const paperWidth = isMobile ? OPEN_WIDTH : (collapsed ? MINI_WIDTH : OPEN_WIDTH);
|
||||
|
||||
const toggleCollapse = () => setCollapsed(c => !c);
|
||||
|
||||
const handleToggleNode = (key) => {
|
||||
// if rail collapsed, expand rail first to reveal submenu
|
||||
if (!isMobile && collapsed) {
|
||||
setCollapsed(false);
|
||||
setOpenMap((m) => ({ ...m, [key]: true }));
|
||||
return;
|
||||
}
|
||||
setOpenMap((m) => ({ ...m, [key]: !m[key] }));
|
||||
};
|
||||
|
||||
const renderNode = (node, keyPrefix = '') => {
|
||||
const key = `${keyPrefix}${node.title}`;
|
||||
const hasChildren = !!node.children?.length;
|
||||
|
||||
return (
|
||||
<Box key={key}>
|
||||
<Tooltip title={collapsed ? node.title : ''} placement="right" disableHoverListener={!collapsed}>
|
||||
<ListItemButton
|
||||
onClick={() => {
|
||||
if (hasChildren) {
|
||||
handleToggleNode(key);
|
||||
} else {
|
||||
onSelect?.(node.title);
|
||||
if (isMobile) onClose?.();
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
px: collapsed ? 0 : 2,
|
||||
minHeight: 48,
|
||||
justifyContent: collapsed ? 'center' : 'flex-start',
|
||||
}}
|
||||
>
|
||||
{node.icon && (
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
color: '#40120EFF',
|
||||
minWidth: collapsed ? 'auto' : 40,
|
||||
mr: collapsed ? 0 : 1.5,
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{node.icon}
|
||||
</ListItemIcon>
|
||||
)}
|
||||
|
||||
{!collapsed && (
|
||||
<>
|
||||
<ListItemText
|
||||
primary={node.title}
|
||||
slotProps={{
|
||||
primary: { sx: { color: '#40120EFF', fontWeight: hasChildren ? 600 : 400, whiteSpace: 'nowrap' } }
|
||||
}}
|
||||
/>
|
||||
{hasChildren ? (openMap[key] ? <ExpandLess /> : <ExpandMore />) : null}
|
||||
</>
|
||||
)}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
|
||||
{hasChildren && !collapsed && (
|
||||
<Collapse in={!!openMap[key]} timeout="auto" unmountOnExit>
|
||||
<List component="div" disablePadding sx={{ pl: 7 }}>
|
||||
{node.children.map((child, idx) => renderNode(child, `${key}-`))}
|
||||
</List>
|
||||
</Collapse>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
anchor="left"
|
||||
variant={isMobile ? 'temporary' : 'permanent'}
|
||||
open={isMobile ? open : true}
|
||||
onClose={isMobile ? onClose : undefined}
|
||||
ModalProps={{ keepMounted: true }}
|
||||
sx={{
|
||||
width: paperWidth,
|
||||
flexShrink: 0,
|
||||
'& .MuiDrawer-paper': {
|
||||
width: paperWidth,
|
||||
boxSizing: 'border-box',
|
||||
backgroundColor: '#FFFFFF',
|
||||
color: '#40120EFF',
|
||||
transition: theme.transitions.create('width', {
|
||||
duration: theme.transitions.duration.standard,
|
||||
easing: theme.transitions.easing.sharp,
|
||||
}),
|
||||
borderRight: '1px solid rgba(0,0,0,0.08)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
px: collapsed ? 1 : 2,
|
||||
py: 1.5,
|
||||
justifyContent: collapsed ? 'center' : 'space-between',
|
||||
}}
|
||||
>
|
||||
{!collapsed && (
|
||||
<Box textAlign="center" p={3} alignItems="center" minHeight={72}>
|
||||
<img
|
||||
src="Logo.png"
|
||||
alt="Dream Views"
|
||||
/>
|
||||
|
||||
<InputBase
|
||||
placeholder="Filter options..."
|
||||
sx={{
|
||||
pl: 1.5,
|
||||
pr: 1.5,
|
||||
py: 0.75,
|
||||
borderRadius: 2,
|
||||
border: '1px solid #40120EFF',
|
||||
color: '#40120EFF',
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{collapsed && (
|
||||
<Box textAlign="center" p={3} minHeight={112} justifyContent="center" display="flex"
|
||||
alignItems="start">
|
||||
<img
|
||||
style={{ marginTop: 5 }}
|
||||
src="MiniLogo.png"
|
||||
alt="Dream Views"
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Tree */}
|
||||
<List sx={{ width: '100%', py: 0 }}>
|
||||
{menuData.map((node) => renderNode(node))}
|
||||
</List>
|
||||
|
||||
<Tooltip title={collapsed ? 'Expand' : 'Collapse'} placement="right">
|
||||
<IconButton onClick={() => setCollapsed((c) => !c)} sx={{
|
||||
backgroundColor: 'transparent',
|
||||
color: 'transparent',
|
||||
'&:hover': {
|
||||
backgroundColor: '#fff4ec',
|
||||
borderColor: 'transparent'
|
||||
},
|
||||
borderRadius: 0,
|
||||
marginLeft: 2,
|
||||
width: 40,
|
||||
height: 40,
|
||||
}}>
|
||||
<img
|
||||
src={collapsed ? '/Expand.png' : '/Contract.png'}
|
||||
alt={collapsed ? 'Expand' : 'Contract'}
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user