Fix session expiration handling

This commit is contained in:
2026-04-23 01:10:15 -05:00
parent da4b06094e
commit 820e335d9a
22 changed files with 308 additions and 51 deletions
+35 -4
View File
@@ -1,6 +1,14 @@
import { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { login as apiLogin, logout as apiLogout, getMe } from '../api/auth';
import { updateSignatureAppearancePreference as apiUpdateSignatureAppearancePreference } from '../api/users';
import {
clearAccessToken,
expireSession,
getAccessToken,
getAccessTokenExpiryDelay,
SESSION_EXPIRED_EVENT,
setAccessToken,
} from '../utils/session';
const AuthContext = createContext(null);
@@ -8,13 +16,24 @@ export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const scheduleSessionExpiry = useCallback((token) => {
const delay = getAccessTokenExpiryDelay(token);
if (delay === null) return undefined;
const timeoutId = window.setTimeout(() => {
expireSession();
}, delay);
return () => window.clearTimeout(timeoutId);
}, []);
useEffect(() => {
const token = localStorage.getItem('accessToken');
const token = getAccessToken();
if (token) {
getMe()
.then(({ data }) => setUser(data.data.user))
.catch(() => {
localStorage.removeItem('accessToken');
clearAccessToken();
})
.finally(() => setLoading(false));
} else {
@@ -22,17 +41,29 @@ export function AuthProvider({ children }) {
}
}, []);
useEffect(() => {
const handleSessionExpired = () => setUser(null);
window.addEventListener(SESSION_EXPIRED_EVENT, handleSessionExpired);
return () => window.removeEventListener(SESSION_EXPIRED_EVENT, handleSessionExpired);
}, []);
useEffect(() => {
const token = getAccessToken();
if (!user || !token) return undefined;
return scheduleSessionExpiry(token);
}, [scheduleSessionExpiry, user]);
const login = useCallback(async (email, password) => {
const { data } = await apiLogin({ email, password });
const { accessToken, user: userData } = data.data;
localStorage.setItem('accessToken', accessToken);
setAccessToken(accessToken);
setUser(userData);
return userData;
}, []);
const logout = useCallback(async () => {
try { await apiLogout(); } catch { /* ignore */ }
localStorage.removeItem('accessToken');
clearAccessToken();
setUser(null);
}, []);