166 lines
6.3 KiB
TypeScript
166 lines
6.3 KiB
TypeScript
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||
import { IconLogout, IconSettings, IconMoon, IconSun, IconMenu2, IconUser, IconLogin } from '@tabler/icons-react';
|
||
import { getUserData, logout, useAuthStore } from '../store/auth';
|
||
import { useEffect, useState } from 'react';
|
||
import { UserData } from '../interfaces/auth';
|
||
import { pages } from '../constants/app';
|
||
import { Button, Image, makeStyles, Menu, MenuButton, MenuItem, MenuList, MenuPopover, MenuTrigger, Text } from '@fluentui/react-components';
|
||
import { setColorScheme, useAppStore } from '../store/app';
|
||
|
||
const useStyles = makeStyles({
|
||
root: {
|
||
display: 'grid',
|
||
gridTemplateRows: 'min-content auto',
|
||
height: '100vh',
|
||
maxHeight: '100vh',
|
||
overflow: 'hidden'
|
||
},
|
||
header: {
|
||
display: 'flex',
|
||
maxHeight: '3rem',
|
||
borderBottom: '1px solid var(--colorNeutralShadowKey)'
|
||
},
|
||
|
||
main: {
|
||
display: 'flex',
|
||
overflow: 'hidden',
|
||
width: '100%',
|
||
height: '100%',
|
||
},
|
||
navbar: {
|
||
overflow: 'auto',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
maxWidth: '200px',
|
||
position: 'relative',
|
||
width: '100%',
|
||
height: '100%',
|
||
transition: 'max-width .2s ease-in-out',
|
||
borderRight: '1px solid var(--colorNeutralShadowKey)'
|
||
},
|
||
content: {
|
||
overflow: 'auto',
|
||
display: 'flex',
|
||
position: 'relative',
|
||
width: '100%',
|
||
height: '100%'
|
||
}
|
||
})
|
||
|
||
function DashboardLayout() {
|
||
const navigate = useNavigate()
|
||
const location = useLocation()
|
||
const { colorScheme } = useAppStore()
|
||
|
||
const getPageTitle = () => {
|
||
const currentPath = location.pathname
|
||
const allPages = [...pages]
|
||
const currentPage = allPages.find(page => page.path === currentPath)
|
||
return currentPage ? currentPage.label : "Панель управления"
|
||
}
|
||
|
||
const authStore = useAuthStore()
|
||
const [userData, setUserData] = useState<UserData>()
|
||
|
||
useEffect(() => {
|
||
if (authStore) {
|
||
const stored = getUserData()
|
||
if (stored) {
|
||
setUserData(stored)
|
||
}
|
||
}
|
||
}, [authStore])
|
||
|
||
const classes = useStyles()
|
||
|
||
const [navbarOpen, setNavbarOpen] = useState(true)
|
||
|
||
useEffect(() => {
|
||
if (colorScheme === 'dark') {
|
||
document.body.dataset.agThemeMode = 'dark'
|
||
} else {
|
||
document.body.dataset.agThemeMode = 'light'
|
||
}
|
||
}, [colorScheme])
|
||
|
||
return (
|
||
<div className={classes.root}>
|
||
<div className={classes.header}>
|
||
<div style={{
|
||
display: 'flex',
|
||
width: '100%',
|
||
alignItems: 'center',
|
||
gap: '0.75rem',
|
||
padding: '0.5rem 0.5rem 0.5rem 0.25rem',
|
||
}}>
|
||
<Button appearance='subtle' onClick={() => setNavbarOpen(!navbarOpen)} icon={<IconMenu2 />} />
|
||
|
||
<Text weight='bold' size={400}>
|
||
{getPageTitle()}
|
||
</Text>
|
||
|
||
<div id='header-portal' style={{ marginLeft: 'auto' }}>
|
||
|
||
</div>
|
||
|
||
<Menu positioning={{ autoSize: true }}>
|
||
<MenuTrigger>
|
||
<MenuButton appearance='transparent' icon={authStore.isAuthenticated ? <IconUser /> : <IconSettings />}>{authStore.isAuthenticated && `${userData?.name} ${userData?.surname}`}</MenuButton>
|
||
</MenuTrigger>
|
||
|
||
<MenuPopover>
|
||
<MenuList>
|
||
{!authStore.isAuthenticated && <MenuItem icon={<IconLogin />} onClick={() => navigate('/auth/signin')}>Войти</MenuItem>}
|
||
|
||
<MenuItem icon={colorScheme === 'dark' ? <IconMoon /> : <IconSun />} onClick={() => colorScheme === 'dark' ? setColorScheme('light') : setColorScheme('dark')}>Тема: {colorScheme === 'dark' ? 'тёмная' : 'светлая'}</MenuItem>
|
||
{authStore.isAuthenticated && <MenuItem icon={<IconSettings />} onClick={() => navigate('/settings')}>Настройки профиля</MenuItem>}
|
||
{authStore.isAuthenticated && <MenuItem icon={<IconLogout />} onClick={() => {
|
||
logout()
|
||
|
||
if (pages.find(page => page.path === '/auth/signin')?.enabled) {
|
||
navigate("/auth/signin")
|
||
}
|
||
}}>Выход</MenuItem>}
|
||
<MenuItem icon={<Image src={'/logo2.svg'} width={24} />}>
|
||
0.1.0
|
||
</MenuItem>
|
||
</MenuList>
|
||
</MenuPopover>
|
||
</Menu>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.main}>
|
||
<div className={classes.navbar} style={{
|
||
maxWidth: navbarOpen ? '200px' : '2.70rem',
|
||
}}>
|
||
{pages.filter((page) => page.drawer).filter((page) => page.enabled).map((item) => (
|
||
<Button key={item.path} style={{ paddingLeft: '0.5rem', flexShrink: 0, flexWrap: 'nowrap', textWrap: 'nowrap', borderRadius: 0 }} appearance={location.pathname === item.path ? 'primary' : 'subtle'} onClick={() => navigate(item.path)}>
|
||
<div style={{ display: 'flex', }}>
|
||
{item.icon}
|
||
</div>
|
||
|
||
<div style={{
|
||
display: 'flex',
|
||
justifyContent: 'flex-start',
|
||
width: '100%',
|
||
overflow: 'hidden',
|
||
marginLeft: '1rem',
|
||
}}>
|
||
{item.label}
|
||
</div>
|
||
|
||
</Button>
|
||
))}
|
||
</div>
|
||
|
||
<div className={classes.content}>
|
||
<Outlet />
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default DashboardLayout |