mirror of
https://github.com/Sea-Haven-Industries/seahaven-ap.git
synced 2026-10-07 16:18:53 +00:00
108 lines
2.6 KiB
TypeScript
108 lines
2.6 KiB
TypeScript
|
|
import {
|
||
|
|
AppBar,
|
||
|
|
Box,
|
||
|
|
Drawer,
|
||
|
|
List,
|
||
|
|
ListItemButton,
|
||
|
|
ListItemText,
|
||
|
|
Toolbar,
|
||
|
|
Typography,
|
||
|
|
} from "@mui/material";
|
||
|
|
import type { ReactNode } from "react";
|
||
|
|
import { useLocation } from "react-router";
|
||
|
|
import { useNavigate, type Path } from "@/router";
|
||
|
|
|
||
|
|
const DRAWER_WIDTH = 240;
|
||
|
|
|
||
|
|
type NavItem = {
|
||
|
|
label: string;
|
||
|
|
to: Path;
|
||
|
|
testId: string;
|
||
|
|
};
|
||
|
|
|
||
|
|
const navItems: NavItem[] = [
|
||
|
|
{ label: "Dashboard", to: "/", testId: "nav-dashboard" },
|
||
|
|
{ label: "Approvals", to: "/approvals", testId: "nav-approvals" },
|
||
|
|
{ label: "Settings", to: "/settings", testId: "nav-settings" },
|
||
|
|
];
|
||
|
|
|
||
|
|
type AppShellProps = {
|
||
|
|
children: ReactNode;
|
||
|
|
};
|
||
|
|
|
||
|
|
export function AppShell({ children }: AppShellProps) {
|
||
|
|
const location = useLocation();
|
||
|
|
const navigate = useNavigate();
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Box sx={{ display: "flex", minHeight: "100vh" }}>
|
||
|
|
<AppBar
|
||
|
|
position="fixed"
|
||
|
|
elevation={0}
|
||
|
|
sx={{
|
||
|
|
zIndex: (theme) => theme.zIndex.drawer + 1,
|
||
|
|
borderBottom: 1,
|
||
|
|
borderColor: "divider",
|
||
|
|
bgcolor: "background.paper",
|
||
|
|
color: "text.primary",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<Toolbar>
|
||
|
|
<Typography variant="h6" sx={{ fontFamily: "inherit", fontWeight: 600 }}>
|
||
|
|
Sea Haven AP
|
||
|
|
</Typography>
|
||
|
|
</Toolbar>
|
||
|
|
</AppBar>
|
||
|
|
|
||
|
|
<Drawer
|
||
|
|
variant="permanent"
|
||
|
|
sx={{
|
||
|
|
width: DRAWER_WIDTH,
|
||
|
|
flexShrink: 0,
|
||
|
|
[`& .MuiDrawer-paper`]: {
|
||
|
|
width: DRAWER_WIDTH,
|
||
|
|
boxSizing: "border-box",
|
||
|
|
borderRight: 1,
|
||
|
|
borderColor: "divider",
|
||
|
|
},
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<Toolbar />
|
||
|
|
<Box sx={{ overflow: "auto", py: 1 }}>
|
||
|
|
<List dense>
|
||
|
|
{navItems.map((item) => {
|
||
|
|
const selected =
|
||
|
|
item.to === "/"
|
||
|
|
? location.pathname === "/"
|
||
|
|
: location.pathname === item.to || location.pathname.startsWith(`${item.to}/`);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<ListItemButton
|
||
|
|
key={item.to}
|
||
|
|
selected={selected}
|
||
|
|
data-testid={item.testId}
|
||
|
|
onClick={() => navigate(item.to)}
|
||
|
|
>
|
||
|
|
<ListItemText primary={item.label} />
|
||
|
|
</ListItemButton>
|
||
|
|
);
|
||
|
|
})}
|
||
|
|
</List>
|
||
|
|
</Box>
|
||
|
|
</Drawer>
|
||
|
|
|
||
|
|
<Box
|
||
|
|
component="main"
|
||
|
|
sx={{
|
||
|
|
flexGrow: 1,
|
||
|
|
width: `calc(100% - ${DRAWER_WIDTH}px)`,
|
||
|
|
bgcolor: "background.default",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<Toolbar />
|
||
|
|
{children}
|
||
|
|
</Box>
|
||
|
|
</Box>
|
||
|
|
);
|
||
|
|
}
|