Compare commits

...

3 Commits

Author SHA1 Message Date
Rodolfo Ruiz
e4c8ed534d chore: adding collapsable submenu to Catalog 2025-08-14 17:22:45 -06:00
Rodolfo Ruiz
6300421693 feat: show drawer collapsed 2025-08-12 17:31:48 -06:00
Rodolfo Ruiz
4ac86a9097 chore: show icons only when collapsed 2025-08-12 17:13:24 -06:00
5 changed files with 291 additions and 70 deletions

BIN
public/Expand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

BIN
public/MiniLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,9 +1,7 @@
import { useState } from 'react';
import fendiLogo from '/favicon.png'
import { AppBar, Toolbar, Typography, IconButton, Box, Avatar } from '@mui/material';
import MenuDrawer from './MenuDrawer';
import MenuIcon from '@mui/icons-material/Menu';
import { useAuth } from '../context/AuthContext';
import { useNavigate } from 'react-router-dom';
@@ -15,7 +13,7 @@ export default function AppHeader({ zone = 'public', onSelectMenuItem }) {
private: '#40120EFF',
};
const [menuOpen, setMenuOpen] = useState(false);
const [drawerExpanded, setDrawerExpanded] = useState(true);
const { user, logout } = useAuth();
const isPrivate = zone === 'private';
@@ -33,11 +31,6 @@ export default function AppHeader({ zone = 'public', onSelectMenuItem }) {
fontSize: { xs: '0.75rem', md: '1rem' },
}} >
<Toolbar sx={{ justifyContent: 'space-between', flexWrap: 'wrap' }}>
<Box display="flex" alignItems="center">
<IconButton edge="start" color="inherit" onClick={() => setMenuOpen(true)}>
<MenuIcon />
</IconButton>
</Box>
{/* Login button only visible for public zone */}
{isPublic && !user && (
@@ -60,8 +53,8 @@ export default function AppHeader({ zone = 'public', onSelectMenuItem }) {
{/* Rendering the Drawer */}
<MenuDrawer
zone="private"
open={menuOpen}
onClose={() => setMenuOpen(false)}
open={drawerExpanded}
onClose={() => setDrawerExpanded(false)}
onSelect={onSelectMenuItem} // pass handler from App
/>

View File

@@ -1,5 +1,5 @@
import { Box, Typography } from '@mui/material';
import fendiLogo from '/logo.png'
import fendiLogo from '/Logo.png'
export default function Footer({ zone = 'public' }) {
const bgColor = {

View File

@@ -1,12 +1,30 @@
import { Drawer, List, ListItem, ListItemText, ListItemIcon, Typography, Box, useMediaQuery, InputBase } from '@mui/material';
import {
Drawer,
List,
ListItem,
ListItemText,
ListItemIcon,
IconButton,
Box,
useMediaQuery,
InputBase,
Tooltip,
Divider,
ListItemButton,
Collapse
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { useEffect, useMemo, useState } from 'react';
import { useAuth } from '../context/AuthContext';
import ExitToAppIcon from '@mui/icons-material/ExitToApp';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';
// ---- Menu options (unchanged) ----
const menuOptions = {
public: [
{ text: 'Dashboard', icon: <img src="/Dashboard.png" alt="Dashboard" width={24} height={24} />},
{ text: 'Dashboard', icon: <img src="/Dashboard.png" alt="Dashboard" width={24} height={24} /> },
{ text: 'Logout', icon: <ExitToAppIcon /> },
],
restricted: [],
@@ -24,72 +42,282 @@ const menuOptions = {
],
};
export default function MenuDrawer({ zone = 'public', open, onClose, onSelect }) {
const isMobile = useMediaQuery('(max-width:900px)');
const items = menuOptions[zone];
// Minivariant sizes
const OPEN_WIDTH = 300;
const MINI_WIDTH = 72;
export default function MenuDrawer({ zone = 'public', open, onClose, onSelect }) {
const theme = useTheme();
const isMobile = useMediaQuery('(max-width:900px)');
const items = useMemo(() => menuOptions[zone] ?? [], [zone]);
const { logout } = useAuth();
// Collapsed state is only meaningful on desktop (permanent drawer)
const [collapsed, setCollapsed] = useState(false);
const catalogChildren = [
'Furniture',
'Lighting',
'Textiles',
'Decorative Accessories',
'Kitchen & Dining',
'Outdoor Living',
];
const [openCatalog, setOpenCatalog] = useState(false);
// Interpret parent "open" prop:
// - Mobile (temporary): open controls visibility
// - Desktop (permanent): open=true => expanded, open=false => collapsed
useEffect(() => {
if (!isMobile) {
setCollapsed(!open);
}
}, [open, isMobile]);
const paperWidth = isMobile ? OPEN_WIDTH : (collapsed ? MINI_WIDTH : OPEN_WIDTH);
return (
<Drawer anchor="left" open={open} onClose={onClose} slotProps={{
paper: {
sx: {
<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: '#FFFFFFFF',
width: isMobile ? '100vw' : 300,
color: '#40120EFF'
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 textAlign="center" p={3}>
<img
src="/logo.png"
alt="Dream Views"
style={{ margin: 'auto', marginBottom: 8 }}
/>
}}
>
{/* Header */}
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 1,
px: collapsed ? 1 : 2,
py: 1.5,
justifyContent: collapsed ? 'center' : 'space-between',
}}
>
{/* Expanded - default */}
{!collapsed && (
<Box textAlign="center" p={3} alignItems="center" minHeight={72}>
<img
src="Logo.png"
alt="Dream Views"
/>
<Box sx={{ position: 'relative', display: { xs: 'none', md: 'flex' } }}>
<InputBase
placeholder="Filter options..."
sx={{
pl: 4,
pr: 2,
py: 0.5,
borderRadius: 2,
border: '1px solid #40120EFF', // Borde visible
color: '#40120EFF',
width: { md: '300px', lg: '400px' }
}}
/>
</Box>
</Box>
<List sx={{ width: isMobile ? '100vw' : 250, marginTop: 0 }}>
{items.map(({ text, icon }, index) => (
<ListItem key={index} onClick={() => {
onClose(); // Close drawer
onSelect?.(text); // Notify parent of selected item
if (text === 'Logout') {
logout(); // cerrar sesión y redirigir
} else {
onSelect?.(text); // navegar al resto de vistas
}
}}>
<ListItemIcon sx={{ color: '#40120EFF' }}>{icon}</ListItemIcon>
<ListItemText
primary={text}
slotProps={{
primary: {
sx: {
color: '#40120EFF',
fontWeight: 'medium',
},
},
<InputBase
placeholder="Filter options..."
sx={{
pl: 1.5,
pr: 1.5,
py: 0.75,
borderRadius: 2,
border: '1px solid #40120EFF',
color: '#40120EFF',
width: '100%',
}}
/>
</ListItem>
))}
</Box>
)}
</Box>
{/* Collapsed */}
{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>
)}
{/* Items */}
<List sx={{
width: '100%',
py: 0,
display: 'flex',
flexDirection: 'column',
alignItems: 'stretch'
}}>
{items.map(({ text, icon }, index) => {
const isCatalog = text === 'Catalog';
// Special case: Catalog with submenu
if (isCatalog) {
return (
<Box key={`catalog-${index}`}>
<Tooltip
title={collapsed ? text : ''}
placement="right"
disableHoverListener={!collapsed}
>
<ListItem
onClick={() => {
if (collapsed) {
// Expand drawer first so submenu is visible
setCollapsed(false);
setOpenCatalog(true);
} else {
setOpenCatalog((v) => !v);
}
}}
sx={{
px: collapsed ? 0 : 2,
minHeight: collapsed ? 48 : 44,
cursor: 'pointer',
justifyContent: collapsed ? 'center' : 'flex-start',
width: '100%',
}}
>
<ListItemIcon
sx={{
color: '#40120EFF',
minWidth: collapsed ? 'auto' : 40,
mr: collapsed ? 0 : 1.5,
justifyContent: 'center',
}}
>
{icon}
</ListItemIcon>
{!collapsed && (
<>
<ListItemText
primary={text}
slotProps={{
primary: {
sx: {
color: '#40120EFF',
fontWeight: 'medium',
},
},
}}
/>
{openCatalog ? <ExpandLess /> : <ExpandMore />}
</>
)}
</ListItem>
</Tooltip>
{/* Submenu list */}
{!collapsed && (
<Collapse in={openCatalog} timeout="auto" unmountOnExit>
<List component="div" disablePadding sx={{ pl: 7 }}>
{catalogChildren.map((child) => (
<ListItemButton
key={child}
sx={{ py: 0.5, borderRadius: 1 }}
onClick={() => {
if (isMobile) onClose?.();
onSelect?.(child);
}}
>
<ListItemText
primary={child}
slotProps={{
primary: {
sx: { color: '#40120EFF', fontWeight: 400 },
},
}}
/>
</ListItemButton>
))}
</List>
</Collapse>
)}
</Box>
);
}
// Default items
return (
<Tooltip
key={`${text}-${index}`}
title={collapsed ? (text || ' ') : ''}
placement="right"
disableHoverListener={!collapsed}
>
<ListItem
onClick={() => {
if (isMobile) onClose?.();
if (text === 'Logout') {
logout();
} else {
onSelect?.(text);
}
}}
sx={{
px: collapsed ? 0 : 2,
minHeight: collapsed ? 48 : 44,
cursor: 'pointer',
justifyContent: collapsed ? 'center' : 'flex-start',
width: '100%',
}}
>
<ListItemIcon
sx={{
color: '#40120EFF',
minWidth: collapsed ? 'auto' : 40,
mr: collapsed ? 0 : 1.5,
justifyContent: 'center',
}}
>
{icon}
</ListItemIcon>
{!collapsed && (
<ListItemText
primary={text}
slotProps={{
primary: {
sx: {
color: '#40120EFF',
fontWeight: 'medium',
},
},
}}
/>
)}
</ListItem>
</Tooltip>
);
})}
</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>
);
}