chore: add the new menu for private mode - admin
This commit is contained in:
		| @@ -2,6 +2,7 @@ import { useState } from 'react'; | |||||||
| import { AppBar, Toolbar, Typography, IconButton, Box, Avatar } from '@mui/material'; | import { AppBar, Toolbar, Typography, IconButton, Box, Avatar } from '@mui/material'; | ||||||
|  |  | ||||||
| import MenuDrawer from './MenuDrawer'; | import MenuDrawer from './MenuDrawer'; | ||||||
|  | import MenuDrawerPrivate from './MenuDrawerPrivate'; | ||||||
| import { useAuth } from '../context/AuthContext'; | import { useAuth } from '../context/AuthContext'; | ||||||
| import { useNavigate } from 'react-router-dom'; | import { useNavigate } from 'react-router-dom'; | ||||||
|  |  | ||||||
| @@ -86,7 +87,7 @@ export default function AppHeader({ zone = 'public', onSelectMenuItem }) { | |||||||
|           )} |           )} | ||||||
|         </Box> |         </Box> | ||||||
|  |  | ||||||
|         <MenuDrawer |         <MenuDrawerPrivate | ||||||
|           zone="private" |           zone="private" | ||||||
|           onSelect={handleMenuSelect} |           onSelect={handleMenuSelect} | ||||||
|           onExpandedChange={(expanded) => setDrawerExpanded(expanded)} |           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> | ||||||
|  |   ); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Rodolfo Ruiz
					Rodolfo Ruiz