Abhisingh-18's picture
Mirror of github.com/Abhisingh18/Labour-Connect
b24b684 verified
Raw
History Blame Contribute Delete
6.96 kB
import { useState } from "react";
import {
AppBar,
Avatar,
Box,
Divider,
Drawer,
IconButton,
List,
ListItemButton,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
Stack,
Toolbar,
Typography,
useMediaQuery,
} from "@mui/material";
import { useTheme } from "@mui/material/styles";
import MenuRoundedIcon from "@mui/icons-material/MenuRounded";
import DashboardRoundedIcon from "@mui/icons-material/DashboardRounded";
import EngineeringRoundedIcon from "@mui/icons-material/EngineeringRounded";
import PeopleRoundedIcon from "@mui/icons-material/PeopleRounded";
import CategoryRoundedIcon from "@mui/icons-material/CategoryRounded";
import EventNoteRoundedIcon from "@mui/icons-material/EventNoteRounded";
import StarRoundedIcon from "@mui/icons-material/StarRounded";
import LogoutRoundedIcon from "@mui/icons-material/LogoutRounded";
import HandymanRoundedIcon from "@mui/icons-material/HandymanRounded";
import { NavLink, Outlet, useLocation } from "react-router-dom";
import { useAuth } from "@/auth/AuthContext";
import { initials } from "@/utils/format";
const DRAWER_WIDTH = 256;
const NAV = [
{ to: "/", label: "Dashboard", icon: <DashboardRoundedIcon /> },
{ to: "/workers", label: "Workers", icon: <EngineeringRoundedIcon /> },
{ to: "/customers", label: "Customers", icon: <PeopleRoundedIcon /> },
{ to: "/categories", label: "Categories", icon: <CategoryRoundedIcon /> },
{ to: "/bookings", label: "Bookings", icon: <EventNoteRoundedIcon /> },
{ to: "/reviews", label: "Reviews", icon: <StarRoundedIcon /> },
];
export default function Layout() {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md"));
const [mobileOpen, setMobileOpen] = useState(false);
const [anchor, setAnchor] = useState<null | HTMLElement>(null);
const { user, logout } = useAuth();
const location = useLocation();
const title =
NAV.find((n) => n.to === location.pathname)?.label ?? "Admin";
const drawer = (
<Box sx={{ height: "100%", display: "flex", flexDirection: "column" }}>
<Stack direction="row" alignItems="center" spacing={1.5} sx={{ px: 3, py: 2.5 }}>
<Box
sx={{
width: 40,
height: 40,
borderRadius: 2.5,
background: "linear-gradient(135deg,#6366F1,#4F46E5)",
display: "grid",
placeItems: "center",
}}
>
<HandymanRoundedIcon sx={{ color: "#fff", fontSize: 22 }} />
</Box>
<Box>
<Typography sx={{ fontFamily: "Plus Jakarta Sans", fontWeight: 800, lineHeight: 1.1 }}>
Labour Connect
</Typography>
<Typography variant="caption" color="text.secondary">
Admin Panel
</Typography>
</Box>
</Stack>
<Divider />
<List sx={{ px: 1.5, py: 2, flex: 1 }}>
{NAV.map((item) => (
<ListItemButton
key={item.to}
component={NavLink}
to={item.to}
end={item.to === "/"}
onClick={() => isMobile && setMobileOpen(false)}
sx={{
borderRadius: 2.5,
mb: 0.5,
color: "text.secondary",
"&.active": {
bgcolor: "primary.light",
color: "primary.main",
fontWeight: 700,
"& .MuiListItemIcon-root": { color: "primary.main" },
},
}}
>
<ListItemIcon sx={{ minWidth: 40, color: "inherit" }}>
{item.icon}
</ListItemIcon>
<ListItemText
primary={item.label}
primaryTypographyProps={{ fontWeight: 600, fontSize: 14 }}
/>
</ListItemButton>
))}
</List>
</Box>
);
return (
<Box sx={{ display: "flex", minHeight: "100vh", bgcolor: "background.default" }}>
<AppBar
position="fixed"
elevation={0}
sx={{
width: { md: `calc(100% - ${DRAWER_WIDTH}px)` },
ml: { md: `${DRAWER_WIDTH}px` },
bgcolor: "background.paper",
color: "text.primary",
borderBottom: "1px solid",
borderColor: "divider",
}}
>
<Toolbar>
<IconButton
edge="start"
onClick={() => setMobileOpen(true)}
sx={{ mr: 2, display: { md: "none" } }}
>
<MenuRoundedIcon />
</IconButton>
<Typography variant="h6" sx={{ flexGrow: 1 }}>
{title}
</Typography>
<IconButton onClick={(e) => setAnchor(e.currentTarget)}>
<Avatar sx={{ width: 36, height: 36, bgcolor: "primary.main", fontSize: 15 }}>
{initials(user?.name)}
</Avatar>
</IconButton>
<Menu
anchorEl={anchor}
open={Boolean(anchor)}
onClose={() => setAnchor(null)}
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
transformOrigin={{ vertical: "top", horizontal: "right" }}
>
<Box sx={{ px: 2, py: 1 }}>
<Typography fontWeight={700}>{user?.name}</Typography>
<Typography variant="caption" color="text.secondary">
{user?.email}
</Typography>
</Box>
<Divider />
<MenuItem onClick={logout}>
<ListItemIcon>
<LogoutRoundedIcon fontSize="small" />
</ListItemIcon>
Log out
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
<Box component="nav" sx={{ width: { md: DRAWER_WIDTH }, flexShrink: { md: 0 } }}>
<Drawer
variant="temporary"
open={mobileOpen}
onClose={() => setMobileOpen(false)}
ModalProps={{ keepMounted: true }}
sx={{
display: { xs: "block", md: "none" },
"& .MuiDrawer-paper": { width: DRAWER_WIDTH, boxSizing: "border-box" },
}}
>
{drawer}
</Drawer>
<Drawer
variant="permanent"
open
sx={{
display: { xs: "none", md: "block" },
"& .MuiDrawer-paper": {
width: DRAWER_WIDTH,
boxSizing: "border-box",
borderRight: "1px solid",
borderColor: "divider",
},
}}
>
{drawer}
</Drawer>
</Box>
<Box
component="main"
sx={{
flexGrow: 1,
width: { md: `calc(100% - ${DRAWER_WIDTH}px)` },
p: { xs: 2, md: 4 },
}}
>
<Toolbar />
<Outlet />
</Box>
</Box>
);
}