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 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> | ||||
|   ); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Rodolfo Ruiz
					Rodolfo Ruiz