175 lines
5.1 KiB
TypeScript
175 lines
5.1 KiB
TypeScript
import * as React from "react";
|
||
import Box from "@mui/material/Box";
|
||
import Toolbar from "@mui/material/Toolbar";
|
||
import IconButton from "@mui/material/IconButton";
|
||
import { Menu, ChevronLeftIcon, ChevronRightIcon, User } from "lucide-react";
|
||
import { useTheme } from "@mui/material/styles";
|
||
import { AppBar } from "./ui/AppBar";
|
||
import { Drawer } from "./ui/Drawer";
|
||
import { DrawerHeader } from "./ui/DrawerHeader";
|
||
import { NavigationList } from "@features";
|
||
import { authStore, menuStore, isMediaIdEmpty } from "@shared";
|
||
import { observer } from "mobx-react-lite";
|
||
import { useEffect } from "react";
|
||
import { Typography } from "@mui/material";
|
||
import { CitySelector } from "@widgets";
|
||
|
||
interface LayoutProps {
|
||
children: React.ReactNode;
|
||
}
|
||
|
||
export const Layout: React.FC<LayoutProps> = observer(({ children }) => {
|
||
const theme = useTheme();
|
||
const [open, setOpen] = React.useState(true);
|
||
const { setIsMenuOpen } = menuStore;
|
||
|
||
React.useEffect(() => {
|
||
setIsMenuOpen(open);
|
||
}, [open]);
|
||
|
||
const { getMeAction, me } = authStore;
|
||
|
||
useEffect(() => {
|
||
getMeAction();
|
||
}, []);
|
||
|
||
const handleDrawerOpen = () => {
|
||
setOpen(true);
|
||
};
|
||
|
||
const handleDrawerClose = () => {
|
||
setOpen(false);
|
||
};
|
||
|
||
return (
|
||
<Box
|
||
sx={{
|
||
display: "flex",
|
||
height: "100vh",
|
||
minHeight: 0,
|
||
overflow: "hidden",
|
||
}}
|
||
>
|
||
<AppBar position="fixed" open={open}>
|
||
<Toolbar className="flex justify-between">
|
||
<div className="flex items-center">
|
||
<IconButton
|
||
color="inherit"
|
||
aria-label="open drawer"
|
||
onClick={handleDrawerOpen}
|
||
edge="start"
|
||
sx={[
|
||
{
|
||
marginRight: 5,
|
||
},
|
||
open && { display: "none" },
|
||
]}
|
||
>
|
||
<Menu />
|
||
</IconButton>
|
||
<CitySelector />
|
||
</div>
|
||
|
||
<div className="flex gap-2 items-center">
|
||
{(() => {
|
||
const hasAvatar = me?.icon && !isMediaIdEmpty(me.icon);
|
||
const token = localStorage.getItem("token");
|
||
|
||
return (
|
||
<>
|
||
<div className="flex flex-col gap-1">
|
||
<p className="text-white">{me?.name}</p>
|
||
<div
|
||
className="text-center text-xs"
|
||
style={{
|
||
backgroundColor: "#877361",
|
||
borderRadius: "4px",
|
||
color: "white",
|
||
padding: "2px 10px",
|
||
}}
|
||
>
|
||
{me?.roles?.includes("admin")
|
||
? "Администратор"
|
||
: "Режим пользователя"}
|
||
</div>
|
||
</div>
|
||
<div className="w-10 h-10 rounded-full flex items-center justify-center overflow-hidden bg-gray-600 shrink-0">
|
||
{hasAvatar ? (
|
||
<img
|
||
src={`${
|
||
import.meta.env.VITE_KRBL_MEDIA
|
||
}${me?.icon}/download?token=${token}`}
|
||
alt="Аватар"
|
||
className="w-full h-full object-cover"
|
||
/>
|
||
) : (
|
||
<User className="text-white" size={20} />
|
||
)}
|
||
</div>
|
||
</>
|
||
);
|
||
})()}
|
||
</div>
|
||
</Toolbar>
|
||
</AppBar>
|
||
<Drawer variant="permanent" open={open}>
|
||
<DrawerHeader>
|
||
<Box
|
||
sx={{
|
||
display: "flex",
|
||
alignItems: "center",
|
||
gap: 2,
|
||
cursor: "pointer",
|
||
}}
|
||
onClick={() => {
|
||
setOpen(!open);
|
||
}}
|
||
>
|
||
<img
|
||
src="/favicon_ship.svg"
|
||
alt="logo"
|
||
width={40}
|
||
height={40}
|
||
style={{ filter: "brightness(0)", marginLeft: "-5px" }}
|
||
/>
|
||
<Typography variant="h6" component="h1">
|
||
Белые ночи
|
||
</Typography>
|
||
</Box>
|
||
{open && (
|
||
<IconButton onClick={handleDrawerClose}>
|
||
{theme.direction === "rtl" ? (
|
||
<ChevronRightIcon />
|
||
) : (
|
||
<ChevronLeftIcon />
|
||
)}
|
||
</IconButton>
|
||
)}
|
||
</DrawerHeader>
|
||
<NavigationList open={open} onDrawerOpen={handleDrawerOpen} />
|
||
<div className="mt-auto flex justify-center items-center pb-5 text-sm text-gray-300">
|
||
v.{__APP_VERSION__}
|
||
</div>
|
||
</Drawer>
|
||
<Box
|
||
component="main"
|
||
sx={{
|
||
width: "100%",
|
||
flexGrow: 1,
|
||
minWidth: 0,
|
||
minHeight: 0,
|
||
height: "100vh",
|
||
p: 3,
|
||
overflowY: "auto",
|
||
overflowX: "hidden",
|
||
maxWidth: "100vw",
|
||
boxSizing: "border-box",
|
||
}}
|
||
>
|
||
<div className="mt-16"></div>
|
||
{children}
|
||
</Box>
|
||
</Box>
|
||
);
|
||
});
|