112 lines
3.6 KiB
TypeScript
112 lines
3.6 KiB
TypeScript
import React, { ReactNode, useEffect } from 'react'
|
||
import { useState } from 'react'
|
||
import jwt from 'jsonwebtoken';
|
||
import { mdiForwardburger, mdiBackburger, mdiMenu } from '@mdi/js'
|
||
import menuAside from '../menuAside'
|
||
import menuNavBar from '../menuNavBar'
|
||
import BaseIcon from '../components/BaseIcon'
|
||
import NavBar from '../components/NavBar'
|
||
import NavBarItemPlain from '../components/NavBarItemPlain'
|
||
import AsideMenu from '../components/AsideMenu'
|
||
import FooterBar from '../components/FooterBar'
|
||
import { useAppDispatch, useAppSelector } from '../stores/hooks'
|
||
import Search from '../components/Search';
|
||
import { useRouter } from 'next/router'
|
||
import {findMe, logoutUser} from "../stores/authSlice";
|
||
|
||
type Props = {
|
||
children: ReactNode
|
||
}
|
||
|
||
export default function LayoutAuthenticated({
|
||
children,
|
||
}: Props) {
|
||
const dispatch = useAppDispatch()
|
||
const router = useRouter()
|
||
const { token, currentUser } = useAppSelector((state) => state.auth)
|
||
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
||
let localToken
|
||
if (typeof window !== 'undefined') {
|
||
// Perform localStorage action
|
||
localToken = localStorage.getItem('token')
|
||
}
|
||
|
||
const isTokenValid = () => {
|
||
const token = localStorage.getItem('token');
|
||
if (!token) return;
|
||
const date = new Date().getTime() / 1000;
|
||
const data = jwt.decode(token);
|
||
if (!data) return;
|
||
return date < data.exp;
|
||
};
|
||
|
||
useEffect(() => {
|
||
dispatch(findMe());
|
||
if (!isTokenValid()) {
|
||
dispatch(logoutUser());
|
||
router.push('/login');
|
||
}
|
||
}, [token, localToken]);
|
||
|
||
const darkMode = useAppSelector((state) => state.style.darkMode)
|
||
|
||
const [isAsideMobileExpanded, setIsAsideMobileExpanded] = useState(false)
|
||
const [isAsideLgActive, setIsAsideLgActive] = useState(false)
|
||
|
||
useEffect(() => {
|
||
const handleRouteChangeStart = () => {
|
||
setIsAsideMobileExpanded(false)
|
||
setIsAsideLgActive(false)
|
||
}
|
||
|
||
router.events.on('routeChangeStart', handleRouteChangeStart)
|
||
|
||
// If the component is unmounted, unsubscribe
|
||
// from the event with the `off` method:
|
||
return () => {
|
||
router.events.off('routeChangeStart', handleRouteChangeStart)
|
||
}
|
||
}, [router.events, dispatch])
|
||
|
||
const layoutAsidePadding = 'xl:pl-60'
|
||
|
||
return (
|
||
<div className={`${darkMode ? 'dark' : ''} overflow-hidden lg:overflow-visible`}>
|
||
<div
|
||
className={`${layoutAsidePadding} ${
|
||
isAsideMobileExpanded ? 'ml-60 lg:ml-0' : ''
|
||
} pt-14 min-h-screen w-screen transition-position lg:w-auto ${bgColor} dark:bg-dark-800 dark:text-slate-100`}
|
||
>
|
||
<NavBar
|
||
menu={menuNavBar}
|
||
className={`${layoutAsidePadding} ${isAsideMobileExpanded ? 'ml-60 lg:ml-0' : ''}`}
|
||
>
|
||
<NavBarItemPlain
|
||
display="flex lg:hidden"
|
||
onClick={() => setIsAsideMobileExpanded(!isAsideMobileExpanded)}
|
||
>
|
||
<BaseIcon path={isAsideMobileExpanded ? mdiBackburger : mdiForwardburger} size="24" />
|
||
</NavBarItemPlain>
|
||
<NavBarItemPlain
|
||
display="hidden lg:flex xl:hidden"
|
||
onClick={() => setIsAsideLgActive(true)}
|
||
>
|
||
<BaseIcon path={mdiMenu} size="24" />
|
||
</NavBarItemPlain>
|
||
<NavBarItemPlain useMargin>
|
||
<Search />
|
||
</NavBarItemPlain>
|
||
</NavBar>
|
||
<AsideMenu
|
||
isAsideMobileExpanded={isAsideMobileExpanded}
|
||
isAsideLgActive={isAsideLgActive}
|
||
menu={menuAside}
|
||
onAsideLgClose={() => setIsAsideLgActive(false)}
|
||
/>
|
||
{children}
|
||
<FooterBar>Hand-crafted & Made with ❤️</FooterBar>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|