E-Commerce-Module/frontend/src/layouts/MainLayout.jsx

274 lines
No EOL
8.3 KiB
JavaScript

import React, { useState } from 'react';
import { Outlet } from 'react-router-dom';
import { Box, Container, AppBar, Toolbar, Typography, Button,
IconButton, Drawer, List, ListItem, ListItemIcon, ListItemText,
Divider, Badge, useMediaQuery } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import MenuIcon from '@mui/icons-material/Menu';
import HomeIcon from '@mui/icons-material/Home';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import CategoryIcon from '@mui/icons-material/Category';
import PersonIcon from '@mui/icons-material/Person';
import LoginIcon from '@mui/icons-material/Login';
import LogoutIcon from '@mui/icons-material/Logout';
import DashboardIcon from '@mui/icons-material/Dashboard';
import Brightness4Icon from '@mui/icons-material/Brightness4';
import Brightness7Icon from '@mui/icons-material/Brightness7';
import ReceiptIcon from '@mui/icons-material/Receipt';
import BookIcon from '@mui/icons-material/Book';
import { Link as RouterLink, useNavigate } from 'react-router-dom';
import { useAuth, useCart, useDarkMode } from '../hooks/reduxHooks';
import Footer from '../components/Footer';
import { useQuery } from '@tanstack/react-query';
import apiClient from '@services/api';
import useBrandingSettings from '@hooks/brandingHooks';
import imageUtils from '@utils/imageUtils';
const MainLayout = () => {
const [drawerOpen, setDrawerOpen] = useState(false);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const navigate = useNavigate();
const { isAuthenticated, isAdmin, logout } = useAuth();
const { itemCount } = useCart();
const [darkMode, toggleDarkMode] = useDarkMode();
const { data: brandingSettings } = useBrandingSettings();
const siteName = brandingSettings?.site_name || 'Rocks, Bones & Sticks';
const logoUrl = imageUtils.getImageUrl(brandingSettings?.logo_url)
const handleDrawerToggle = () => {
setDrawerOpen(!drawerOpen);
};
const handleLogout = () => {
logout();
navigate('/');
};
let mainMenu = [
{ text: 'Home', icon: <HomeIcon />, path: '/' },
{ text: 'Products', icon: <CategoryIcon />, path: '/products' },
{ text: 'Blog', icon: <BookIcon />, path: '/blog' },
{ text: 'Cart', icon: <ShoppingCartIcon />, path: '/cart', badge: itemCount > 0 ? itemCount : null },
];
if (isAuthenticated) {
mainMenu.push(
{ text: 'My Orders', icon: <ReceiptIcon />, path: '/account/orders' }
);
}
const authMenu = isAuthenticated ?
[
{ text: 'Logout', icon: <LogoutIcon />, onClick: handleLogout }
] : [
{ text: 'Login', icon: <LoginIcon />, path: '/auth/login' },
{ text: 'Register', icon: <PersonIcon />, path: '/auth/register' }
];
// Add admin menu if user is admin
if (isAuthenticated && isAdmin) {
mainMenu.push(
{ text: 'Admin Dashboard', icon: <DashboardIcon />, path: '/admin' }
);
}
const drawer = (
<Box sx={{ width: 250 }} role="presentation" onClick={handleDrawerToggle}>
<Box sx={{ display: 'flex', p: 2, alignItems: 'center' }}>
{logoUrl ? (
<Box
component="img"
src={logoUrl}
alt={siteName}
sx={{
height: 40,
maxWidth: '100%',
objectFit: 'contain'
}}
/>
) : (
<Typography variant="h6" component="div">
{siteName}
</Typography>
)}
</Box>
<Divider />
<List>
{mainMenu.map((item) => (
<ListItem
button
key={item.text}
component={item.path ? RouterLink : 'button'}
to={item.path}
onClick={item.onClick}
>
<ListItemIcon>
{item.badge ? (
<Badge badgeContent={item.badge} color="primary">
{item.icon}
</Badge>
) : (
item.icon
)}
</ListItemIcon>
<ListItemText primary={item.text} />
</ListItem>
))}
</List>
<Divider />
<List>
<ListItem button onClick={toggleDarkMode}>
<ListItemIcon>
{darkMode ? <Brightness7Icon /> : <Brightness4Icon />}
</ListItemIcon>
<ListItemText primary={darkMode ? "Light Mode" : "Dark Mode"} />
</ListItem>
{authMenu.map((item) => (
<ListItem
button
key={item.text}
component={item.path ? RouterLink : 'button'}
to={item.path}
onClick={item.onClick}
>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItem>
))}
</List>
</Box>
);
return (
<Box sx={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
<AppBar position="sticky" color="primary">
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{ mr: 2, display: { sm: 'flex' } }}
>
<MenuIcon />
</IconButton>
{logoUrl ? (
<Box
component={RouterLink}
to="/"
sx={{
flexGrow: 1,
display: { xs: 'none', sm: 'flex' },
textDecoration: 'none',
color: 'white'
}}
>
<Box
component="img"
src={logoUrl}
alt={siteName}
sx={{
height: 40,
maxWidth: '200px',
objectFit: 'contain'
}}
/>
</Box>
) : (
<Typography
variant="h6"
component={RouterLink}
to="/"
sx={{
flexGrow: 1,
color: 'white',
textDecoration: 'none',
display: { xs: 'none', sm: 'block' }
}}
>
{siteName}
</Typography>
)}
{/* Desktop navigation */}
{!isMobile && (
<Box sx={{ display: 'flex', alignItems: 'center' }}>
{mainMenu.map((item) => (
<Button
key={item.text}
color="inherit"
component={RouterLink}
to={item.path}
sx={{ ml: 1 }}
startIcon={item.badge ? (
<Badge badgeContent={item.badge} color="secondary">
{item.icon}
</Badge>
) : item.icon}
>
{item.text}
</Button>
))}
<IconButton
sx={{ ml: 1 }}
onClick={toggleDarkMode}
color="inherit"
>
{darkMode ? <Brightness7Icon /> : <Brightness4Icon />}
</IconButton>
{authMenu.map((item) => (
item.path ? (
<Button
key={item.text}
color="inherit"
component={RouterLink}
to={item.path}
sx={{ ml: 1 }}
startIcon={item.icon}
>
{item.text}
</Button>
) : (
<Button
key={item.text}
color="inherit"
onClick={item.onClick}
sx={{ ml: 1 }}
startIcon={item.icon}
>
{item.text}
</Button>
)
))}
</Box>
)}
</Toolbar>
</AppBar>
<Drawer
anchor="left"
open={drawerOpen}
onClose={handleDrawerToggle}
>
{drawer}
</Drawer>
<Box component="main" sx={{ flexGrow: 1 }}>
<Container maxWidth="lg" sx={{ pt: 3, pb: 6 }}>
<Outlet />
</Container>
</Box>
<Footer brandingSettings={brandingSettings} />
</Box>
);
};
export default MainLayout;