Add session expiration handling with toast notification and auto-redirect to login

This commit is contained in:
DGSoft 2025-12-12 12:39:34 +01:00
parent c7cfbad3d8
commit f52fb50a39
2 changed files with 26 additions and 3 deletions

View File

@ -1,5 +1,6 @@
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'; import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { authAPI } from '../services/api'; import { authAPI } from '../services/api';
import { useToast } from './ToastContext';
import type { User, LoginRequest, RegisterRequest } from '../types'; import type { User, LoginRequest, RegisterRequest } from '../types';
interface AuthContextType { interface AuthContextType {
@ -19,6 +20,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
const [user, setUser] = useState<User | null>(null); const [user, setUser] = useState<User | null>(null);
const [token, setToken] = useState<string | null>(localStorage.getItem('token')); const [token, setToken] = useState<string | null>(localStorage.getItem('token'));
const [presenceWs, setPresenceWs] = useState<WebSocket | null>(null); const [presenceWs, setPresenceWs] = useState<WebSocket | null>(null);
const { addToast } = useToast();
useEffect(() => { useEffect(() => {
if (token && window.location.pathname !== '/login' && window.location.pathname !== '/register') { if (token && window.location.pathname !== '/login' && window.location.pathname !== '/register') {
@ -29,6 +31,23 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
} }
}, [token]); }, [token]);
// Listen for session expired events
useEffect(() => {
const handleSessionExpired = () => {
addToast('Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.', 'warning', 5000);
setToken(null);
setUser(null);
closePresenceConnection();
// Redirect to login after a short delay to show the toast
setTimeout(() => {
window.location.href = '/login';
}, 1000);
};
window.addEventListener('sessionExpired', handleSessionExpired);
return () => window.removeEventListener('sessionExpired', handleSessionExpired);
}, [addToast]);
const loadUser = async () => { const loadUser = async () => {
try { try {
const userData = await authAPI.getCurrentUser(); const userData = await authAPI.getCurrentUser();
@ -48,8 +67,12 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
localStorage.removeItem('token'); localStorage.removeItem('token');
setToken(null); setToken(null);
setUser(null); setUser(null);
// Close presence WebSocket if open
closePresenceConnection(); closePresenceConnection();
// Show toast and redirect to login
addToast('Sitzung konnte nicht wiederhergestellt werden. Bitte melden Sie sich erneut an.', 'error', 5000);
setTimeout(() => {
window.location.href = '/login';
}, 1000);
} }
}; };

View File

@ -33,8 +33,8 @@ api.interceptors.response.use(
localStorage.removeItem('token'); localStorage.removeItem('token');
localStorage.removeItem('lastVisitedPath'); localStorage.removeItem('lastVisitedPath');
sessionStorage.removeItem('routeRestored'); sessionStorage.removeItem('routeRestored');
// Don't redirect, just clear auth state // Dispatch event to notify AuthContext
// The app will handle the redirect appropriately window.dispatchEvent(new CustomEvent('sessionExpired'));
} }
return Promise.reject(error); return Promise.reject(error);
} }