first commit
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import NavLayout from "./NavLayout.tsx";
|
||||
import { Route, Routes, useNavigate } from "react-router-dom";
|
||||
import Home from "../Home.tsx";
|
||||
import './MainLayout.css';
|
||||
import { validateToken, GetUserPrivileges, TokenPayload, UnAuthorized } from '../Auth/Auth.tsx';
|
||||
import '../LoadingScreen.css'
|
||||
import AccountDropdown from "./AccountDropdown.tsx";
|
||||
import AccountSettings from "../Auth/AccountSetting.tsx";
|
||||
import { Api as Auth } from '../client/auth_client.ts';
|
||||
import '../Pages/NotFound.tsx';
|
||||
import NotFound from "../Pages/NotFound.tsx";
|
||||
import "../Pages/UserAccountList.tsx";
|
||||
import UserAccountList from "../Pages/UserAccountList.tsx";
|
||||
|
||||
const MainLayout: React.FC = () => {
|
||||
const [tokenPayload, setTokenPayload] = useState<TokenPayload | null>(null);
|
||||
const [tokenExpiryTime, setTokenExpiryTime] = useState<number | null>(null);
|
||||
const [isAuthenticating, setIsAuthenticating] = useState(true);
|
||||
const [privilegesList, setPrivilegesList] = useState<string[]>();
|
||||
const [isTokenRegenerating, setIsTokenRegenerating] = useState<boolean>(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const validateAndSetToken = async () => {
|
||||
if (isTokenRegenerating) return;
|
||||
|
||||
const token = localStorage.getItem('authToken');
|
||||
if (token) {
|
||||
const payload = await validateToken(token);
|
||||
if (payload) {
|
||||
setTokenPayload(payload);
|
||||
setTokenExpiryTime(payload.exp);
|
||||
setIsAuthenticating(false);
|
||||
} else {
|
||||
localStorage.removeItem('authToken');
|
||||
navigate('/login');
|
||||
}
|
||||
} else {
|
||||
navigate('/login');
|
||||
}
|
||||
};
|
||||
|
||||
const getUserPrivileges = async () => {
|
||||
const privileges = await GetUserPrivileges(navigate);
|
||||
setPrivilegesList(privileges);
|
||||
};
|
||||
|
||||
getUserPrivileges().then();
|
||||
validateAndSetToken().then();
|
||||
}, [navigate, isTokenRegenerating]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tokenExpiryTime) {
|
||||
const currentTime = Math.floor(Date.now() / 1000);
|
||||
const timeUntilExpiry = tokenExpiryTime - currentTime;
|
||||
|
||||
if (timeUntilExpiry > 900) {
|
||||
const timeoutId = setTimeout(() => {
|
||||
regenerateToken().then();
|
||||
}, (timeUntilExpiry - 900) * 1000);
|
||||
return () => clearTimeout(timeoutId);
|
||||
} else {
|
||||
regenerateToken().then();
|
||||
}
|
||||
}
|
||||
}, [tokenExpiryTime]);
|
||||
|
||||
const regenerateToken = async () => {
|
||||
if (isTokenRegenerating) return;
|
||||
|
||||
setIsTokenRegenerating(true);
|
||||
const token = localStorage.getItem('authToken');
|
||||
if (token) {
|
||||
const client = new Auth({
|
||||
baseUrl: 'auth',
|
||||
securityWorker: () => ({ headers: { Authorization: `Bearer ${token}` } }),
|
||||
});
|
||||
try {
|
||||
const responseToken = await client.regenerateToken.regenerateTokenList();
|
||||
if (responseToken.status === 401) {
|
||||
await UnAuthorized(navigate);
|
||||
} else if (responseToken.data.token) {
|
||||
const newToken = responseToken.data.token;
|
||||
localStorage.setItem('authToken', newToken);
|
||||
const newPayload = await validateToken(newToken);
|
||||
if (newPayload) {
|
||||
setTokenPayload(newPayload);
|
||||
setTokenExpiryTime(newPayload.exp);
|
||||
} else {
|
||||
await validateToken(newToken);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Token regeneration failed', error);
|
||||
localStorage.removeItem('authToken');
|
||||
navigate('/login');
|
||||
} finally {
|
||||
setIsTokenRegenerating(false);
|
||||
}
|
||||
} else {
|
||||
setIsTokenRegenerating(false);
|
||||
navigate('/login');
|
||||
}
|
||||
};
|
||||
|
||||
if (isAuthenticating) {
|
||||
return (
|
||||
<div className="loading-screen">
|
||||
<div className="spinner">
|
||||
<div className="lds-ring">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<div className="sidebar">
|
||||
<NavLayout privilegeList={privilegesList} />
|
||||
</div>
|
||||
|
||||
<main className="main-content">
|
||||
<div className="top-row px-4">
|
||||
{tokenPayload && (
|
||||
<AccountDropdown
|
||||
tokenPayload={tokenPayload}
|
||||
privilegeList={privilegesList}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="content px-4">
|
||||
<Routes>
|
||||
<Route path="/" element={<Home tokenPayload={tokenPayload} />} />
|
||||
|
||||
<Route
|
||||
path="/accountSettings/"
|
||||
element={<AccountSettings />}
|
||||
/>
|
||||
<Route path="/accounts/" element={<UserAccountList />} />
|
||||
<Route path="/*" element={<NotFound />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainLayout;
|
||||
Reference in New Issue
Block a user