134 lines
3.4 KiB
TypeScript
134 lines
3.4 KiB
TypeScript
'use client';
|
|
import { createContext, useState, useEffect, useContext } from 'react';
|
|
import { TokenContextType, TokenType } from '@/types/user';
|
|
import { TokenProps } from '@/types/user';
|
|
import { useRouter, usePathname } from '@/src/navigation';
|
|
import { roles } from '@/config/selection';
|
|
import { ToastContext } from './ToastProvider';
|
|
const LOCAL_STORAGE_KEY = 'testplat-auth-token';
|
|
|
|
function storeTokenToLocalStorage(token: TokenType) {
|
|
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(token));
|
|
}
|
|
|
|
function removeTokenFromLocalStorage() {
|
|
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
|
}
|
|
|
|
const defaultContext = {
|
|
token: {
|
|
access_token: '',
|
|
user: null,
|
|
},
|
|
isSignedIn: () => false,
|
|
isAdmin: () => false,
|
|
setToken: (token: TokenType) => {},
|
|
storeTokenToLocalStorage,
|
|
removeTokenFromLocalStorage,
|
|
};
|
|
const TokenContext = createContext<TokenContextType>(defaultContext);
|
|
|
|
const TokenProvider = ({ toastMessages, locale, children }: TokenProps) => {
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
const toastContext = useContext(ToastContext);
|
|
|
|
const [hasRestoreFinished, setHasRestoreFinished] = useState(false);
|
|
const [token, setToken] = useState<TokenType>({
|
|
access_token: '',
|
|
expires_at: 0,
|
|
user: null,
|
|
});
|
|
|
|
const tokenExists = () => {
|
|
if (token && token.user && token.user.username) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const isTokenValid = () => {
|
|
if (Date.now() < token.expires_at) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const isSignedIn = () => {
|
|
if (tokenExists() && isTokenValid()) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const isAdmin = () => {
|
|
if (tokenExists() && isTokenValid()) {
|
|
const adminRoleIndex = roles.findIndex((entry) => entry.uid === 'administrator');
|
|
if (token.user.role === adminRoleIndex) {
|
|
return true;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const tokenContext = {
|
|
token,
|
|
isSignedIn,
|
|
isAdmin,
|
|
setToken,
|
|
storeTokenToLocalStorage,
|
|
removeTokenFromLocalStorage,
|
|
};
|
|
|
|
const restoreTokenFromLocalStorage = () => {
|
|
const tokenString = localStorage.getItem(LOCAL_STORAGE_KEY);
|
|
if (tokenString) {
|
|
const restoredToken = JSON.parse(tokenString);
|
|
setToken(restoredToken);
|
|
}
|
|
setHasRestoreFinished(true);
|
|
};
|
|
|
|
useEffect(() => {
|
|
restoreTokenFromLocalStorage();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
// pravate paths are '/account', '/admin', '/projects/*'
|
|
const isPrivatePath = (pathname: string) => {
|
|
return (
|
|
/^\/account(\/)?$/.test(pathname) || /^\/admin(\/)?$/.test(pathname) || /^\/projects(\/.*)?$/.test(pathname)
|
|
);
|
|
};
|
|
|
|
const checkSignInPage = () => {
|
|
if (!hasRestoreFinished) {
|
|
return;
|
|
}
|
|
if (isPrivatePath(pathname) && !isSignedIn()) {
|
|
if (tokenExists()) {
|
|
toastContext.showToast(toastMessages.needSignedIn, 'error');
|
|
router.push(`/account/signin`, { locale: locale });
|
|
return;
|
|
}
|
|
if (isTokenValid()) {
|
|
toastContext.showToast(toastMessages.sessionExpired, 'error');
|
|
router.push(`/account/signin`, { locale: locale });
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
checkSignInPage();
|
|
}, [pathname, hasRestoreFinished]);
|
|
|
|
return <TokenContext.Provider value={tokenContext}>{children}</TokenContext.Provider>;
|
|
};
|
|
|
|
export { TokenContext };
|
|
export default TokenProvider;
|