Fix: Sesion 1 Hora y Refresh con Redirección

This commit is contained in:
2026-02-16 20:33:38 -03:00
parent bd45e89bd2
commit 5a7c3f62f1
3 changed files with 102 additions and 68 deletions

View File

@@ -1,6 +1,8 @@
import { createContext, useContext, useState, useEffect, type ReactNode } from 'react';
import { AuthService, type UserSession } from '../services/auth.service';
import { ChatService } from '../services/chat.service';
import { createContext, useContext, useState,
useEffect, useCallback, type ReactNode,
} from "react";
import { AuthService, type UserSession } from "../services/auth.service";
import { ChatService } from "../services/chat.service";
interface AuthContextType {
user: UserSession | null;
@@ -19,7 +21,19 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const [loading, setLoading] = useState(true);
const [unreadCount, setUnreadCount] = useState(0);
const fetchUnreadCount = async () => {
// Función para cerrar sesión limpiamente
const logout = useCallback(() => {
AuthService.logout();
setUser(null);
setUnreadCount(0);
localStorage.removeItem("userProfile");
// Redirigir a home
if (window.location.pathname !== "/") {
window.location.href = "/";
}
}, []);
const fetchUnreadCount = useCallback(async () => {
const currentUser = AuthService.getCurrentUser();
if (currentUser) {
try {
@@ -29,64 +43,96 @@ export function AuthProvider({ children }: { children: ReactNode }) {
setUnreadCount(0);
}
}
};
// Verificar sesión al cargar la app (Solo una vez)
useEffect(() => {
const initAuth = async () => {
try {
const sessionUser = await AuthService.checkSession();
if (sessionUser) {
setUser(sessionUser);
await fetchUnreadCount(); // <--- 5. LLAMAR AL CARGAR LA APP
} else {
setUser(null);
setUnreadCount(0);
}
} catch (error) {
setUser(null);
setUnreadCount(0);
} finally {
setLoading(false);
}
};
initAuth();
}, []);
// Función centralizada para verificar la sesión
const verifySession = useCallback(async () => {
try {
const sessionUser = await AuthService.checkSession();
if (sessionUser) {
// Si la sesión es válida, actualizamos el estado si es necesario
// Comparamos IDs para evitar re-renders innecesarios si es el mismo usuario
if (sessionUser.id !== user?.id) {
setUser(sessionUser);
}
await fetchUnreadCount();
} else {
// Si el backend dice null (sesión inválida), sacamos al usuario
if (user) logout();
}
} catch (error) {
// Si hay error de red o 401 que no se pudo refrescar
if (user) logout();
} finally {
setLoading(false);
}
}, [user, logout, fetchUnreadCount]);
const login = (userData: UserSession) => {
setUser(userData);
localStorage.setItem('userProfile', JSON.stringify(userData));
localStorage.setItem("userProfile", JSON.stringify(userData));
fetchUnreadCount();
};
const logout = () => {
AuthService.logout();
setUser(null);
setUnreadCount(0);
localStorage.removeItem('userProfile');
const refreshSession = async () => {
await verifySession();
};
const refreshSession = async () => {
const sessionUser = await AuthService.checkSession();
setUser(sessionUser);
if (sessionUser) {
await fetchUnreadCount();
}
};
// 1. Carga Inicial
useEffect(() => {
verifySession();
}, [verifySession]);
// 2. DETECTOR DE PESTAÑA ACTIVA
useEffect(() => {
const handleVisibilityChange = () => {
// Solo verificamos cuando el usuario VUELVE a la pestaña
if (document.visibilityState === "visible") {
console.log("🔄 Pestaña activa: Verificando sesión...");
verifySession();
}
};
document.addEventListener("visibilitychange", handleVisibilityChange);
return () =>
document.removeEventListener("visibilitychange", handleVisibilityChange);
}, [verifySession]);
// 3. HEARTBEAT - Verifica la sesión cada 5 minutos mientras la pestaña esté abierta
useEffect(() => {
if (!user) return; // No gastar recursos si no hay usuario
const interval = setInterval(
() => {
verifySession();
},
5 * 60 * 1000,
); // 5 minutos
return () => clearInterval(interval);
}, [user, verifySession]);
return (
<AuthContext.Provider value={{ user, loading, unreadCount, login, logout, refreshSession, fetchUnreadCount }}>
<AuthContext.Provider
value={{
user,
loading,
unreadCount,
login,
logout,
refreshSession,
fetchUnreadCount,
}}
>
{children}
</AuthContext.Provider>
);
}
// Hook personalizado para usar el contexto fácilmente
export function useAuth() {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
}
}