feat(frontend): enhance 401 handling to clear tokens and redirect

- Update fetch interceptor to special-case 401 responses
- Clear invalid tokens from localStorage on 401 (token, refreshToken, user)
- Distinguish between page navigation and API calls:
  - Page navigation: throw error to prevent further processing
  - API calls: show toast error with session expired message
- Suppress network error toast for redirect errors
- Compile TypeScript to JavaScript

This ensures frontend properly handles expired sessions by clearing
stale credentials and showing appropriate error messages.
This commit is contained in:
2026-02-16 16:50:19 -05:00
parent 7b07645ee2
commit 53aad2701b
+31 -3
View File
@@ -160,15 +160,43 @@ const setupFetchInterceptor = (): void => {
window.fetch = async (...args: Parameters<typeof fetch>): Promise<Response> => {
try {
const response = await originalFetch(...args);
// Special handling for 401 Unauthorized
if (response.status === 401) {
// Clear invalid tokens from localStorage
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
localStorage.removeItem('user');
// Check if this was a page navigation (not API call)
const url = args[0] as string;
// Don't show toast for page navigations - will be handled by redirect
if (!url.startsWith('/api/')) {
// Direct navigation to protected page will be caught by middleware
// Just throw to prevent further processing
throw new Error('Session expired');
}
// API call - show toast error
const errorMessage = await parseFetchError(response);
showToast(errorMessage, 'error');
return response;
}
// Handle other errors
if (!response.ok) {
const errorMessage = await parseFetchError(response);
showToast(errorMessage, 'error');
}
return response;
} catch (error) {
showToast('Network error: Unable to connect to server', 'error');
// Don't show toast for redirect errors
if ((error as Error).message !== 'Session expired') {
showToast('Network error: Unable to connect to server', 'error');
}
throw error;
}
};