Refactor Dashboard component to handle authentication errors and improve token validation logic

This commit is contained in:
IluaAir
2025-10-19 00:14:34 +03:00
parent 6b241bcfe5
commit fd8105d30a
4 changed files with 71 additions and 15 deletions

View File

@@ -84,7 +84,10 @@ export const login = async (username, password) => {
export const refreshToken = async () => {
try {
const response = await client.post(API_ENDPOINTS.AUTH.REFRESH);
const fingerprint = localStorage.getItem('fingerprint');
const response = await client.post(API_ENDPOINTS.AUTH.REFRESH, {
fingerprint: fingerprint,
});
if (response.data.access_token && response.data.token_type === 'bearer') {
localStorage.setItem('access_token', response.data.access_token);
}
@@ -92,7 +95,6 @@ export const refreshToken = async () => {
} catch (error) {
localStorage.removeItem('access_token');
localStorage.removeItem('fingerprint');
cookies.remove('refresh_token');
throw error.response?.data || error.message;
}
};

View File

@@ -7,22 +7,38 @@ export function cn(...inputs) {
return twMerge(clsx(inputs));
}
let refreshPromise = null;
export async function jwtexp(token) {
console.log("jwtexp called from:", new Error().stack);
const decoded = decode(token);
const currentTime = Date.now() / 1000;
const tokenExp = decoded.exp;
console.log("Token exp:", tokenExp, "Current time:", currentTime);
if (tokenExp < currentTime || tokenExp - currentTime < 120) {
console.log("Token needs refresh");
if (refreshPromise) {
console.log("Refresh already in progress, waiting...");
return await refreshPromise;
}
refreshPromise = (async () => {
try {
console.log("Starting token refresh...");
await refreshToken();
console.log("Token refreshed successfully");
return true;
} catch (error) {
console.error("Failed to refresh token:", error);
return false;
} finally {
refreshPromise = null;
}
})();
return await refreshPromise;
}
console.log("Token is valid");

View File

@@ -5,9 +5,7 @@ import App from './App.jsx'
import { BrowserRouter } from 'react-router'
createRoot(document.getElementById('root')).render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>,
)

View File

@@ -18,11 +18,32 @@ const menuItems = [
export default function Dashboard() {
const [tasksFromBackend, setTasksFromBackend] = useState([]);
const [loading, setLoading] = useState(true);
const [authError, setAuthError] = useState(false);
// Fetch tasks
useEffect(() => {
console.log('Dashboard useEffect triggered');
const fetchTasks = async () => {
try {
console.log('Starting fetchTasks...');
const token = localStorage.getItem('access_token');
if (token) {
console.log('Token found, validating...');
const isTokenValid = await jwtexp(token);
if (!isTokenValid) {
console.error('Token validation failed');
setAuthError(true);
setLoading(false);
return;
}
} else {
console.error('No access token found');
setAuthError(true);
setLoading(false);
return;
}
console.log('Fetching user tasks...');
const response = await getUserTasks(1);
console.log('Tasks from backend:', response);
setTasksFromBackend(response);
@@ -98,6 +119,25 @@ export default function Dashboard() {
);
}
if (authError) {
return (
<div className="dashboard-container">
<div className="flex items-center justify-center min-h-screen">
<div className="text-center">
<p className="text-xl text-red-500 mb-4">Authentication Error</p>
<p className="text-gray-600">Please log in again</p>
<button
onClick={() => window.location.href = '/login'}
className="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Go to Login
</button>
</div>
</div>
</div>
);
}
return (
<div className="dashboard-container">
{/* Navigation Rail - Material Design 3 */}