Implementación AnomalIA - Fix de dropdowns y permisos.
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 5m17s
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 5m17s
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import React, { createContext, useState, useContext, type ReactNode, useEffect } from 'react';
|
||||
import type { LoginResponseDto } from '../models/dtos/Usuarios/LoginResponseDto';
|
||||
import React, { createContext, useState, useContext, type ReactNode, useEffect, useCallback } from 'react';
|
||||
import { jwtDecode } from 'jwt-decode';
|
||||
import { getAlertas, marcarAlertaLeida, marcarGrupoComoLeido, type AlertaGenericaDto } from '../services/Anomalia/alertaService';
|
||||
|
||||
// Interfaz para los datos del usuario que guardaremos en el contexto
|
||||
export interface UserContextData {
|
||||
userId: number;
|
||||
username: string;
|
||||
@@ -11,33 +10,37 @@ export interface UserContextData {
|
||||
debeCambiarClave: boolean;
|
||||
perfil: string;
|
||||
idPerfil: number;
|
||||
permissions: string[]; // Guardamos los codAcc
|
||||
permissions: string[];
|
||||
}
|
||||
|
||||
// Interfaz para el payload decodificado del JWT
|
||||
interface DecodedJwtPayload {
|
||||
sub: string; // User ID (viene como string)
|
||||
name: string; // Username
|
||||
given_name?: string; // Nombre (estándar, pero verifica tu token)
|
||||
family_name?: string; // Apellido (estándar, pero verifica tu token)
|
||||
role: string | string[]; // Puede ser uno o varios roles
|
||||
sub: string;
|
||||
name: string;
|
||||
given_name?: string;
|
||||
family_name?: string;
|
||||
role: string | string[];
|
||||
perfil: string;
|
||||
idPerfil: string; // (viene como string)
|
||||
debeCambiarClave: string; // (viene como string "True" o "False")
|
||||
permission?: string | string[]; // Nuestros claims de permiso (codAcc)
|
||||
[key: string]: any; // Para otros claims
|
||||
idPerfil: string;
|
||||
debeCambiarClave: string;
|
||||
permission?: string | string[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface AuthContextType {
|
||||
isAuthenticated: boolean;
|
||||
user: UserContextData | null; // Usar el tipo extendido
|
||||
user: UserContextData | null;
|
||||
token: string | null;
|
||||
isLoading: boolean;
|
||||
alertas: AlertaGenericaDto[];
|
||||
showForcedPasswordChangeModal: boolean;
|
||||
isPasswordChangeForced: boolean;
|
||||
|
||||
marcarAlertaComoLeida: (idAlerta: number) => Promise<void>;
|
||||
marcarGrupoDeAlertasLeido: (tipoAlerta: string, idEntidad: number) => Promise<void>;
|
||||
|
||||
setShowForcedPasswordChangeModal: (show: boolean) => void;
|
||||
passwordChangeCompleted: () => void;
|
||||
login: (apiLoginResponse: LoginResponseDto) => void; // Recibe el DTO de la API
|
||||
login: (apiLoginResponse: any) => void; // DTO no definido aquí, usamos any
|
||||
logout: () => void;
|
||||
}
|
||||
|
||||
@@ -50,24 +53,57 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [showForcedPasswordChangeModal, setShowForcedPasswordChangeModal] = useState<boolean>(false);
|
||||
const [isPasswordChangeForced, setIsPasswordChangeForced] = useState<boolean>(false);
|
||||
const [alertas, setAlertas] = useState<AlertaGenericaDto[]>([]);
|
||||
|
||||
const processTokenAndSetUser = (jwtToken: string) => {
|
||||
const fetchAlertas = useCallback(async (currentUser: UserContextData | null) => {
|
||||
if (currentUser && (currentUser.esSuperAdmin || currentUser.permissions.includes('AL001'))) {
|
||||
try {
|
||||
const data = await getAlertas();
|
||||
setAlertas(data || []);
|
||||
} catch (error) {
|
||||
console.error("Error al obtener alertas en AuthContext:", error);
|
||||
setAlertas([]);
|
||||
}
|
||||
} else {
|
||||
setAlertas([]);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const marcarAlertaComoLeida = async (idAlerta: number) => {
|
||||
try {
|
||||
await marcarAlertaLeida(idAlerta);
|
||||
await fetchAlertas(user); // Refresca el estado global
|
||||
} catch (error) {
|
||||
console.error("Error al marcar alerta como leída:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const marcarGrupoDeAlertasLeido = async (tipoAlerta: string, idEntidad: number) => {
|
||||
try {
|
||||
await marcarGrupoComoLeido({ tipoAlerta, idEntidad });
|
||||
await fetchAlertas(user); // Refresca el estado global
|
||||
} catch (error) {
|
||||
console.error(`Error al marcar grupo ${tipoAlerta}/${idEntidad} como leído:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
const logout = useCallback(() => {
|
||||
localStorage.removeItem('authToken');
|
||||
setToken(null);
|
||||
setUser(null);
|
||||
setIsAuthenticated(false);
|
||||
setShowForcedPasswordChangeModal(false);
|
||||
setIsPasswordChangeForced(false);
|
||||
setAlertas([]);
|
||||
}, []);
|
||||
|
||||
const processTokenAndSetUser = useCallback((jwtToken: string) => {
|
||||
try {
|
||||
const decodedToken = jwtDecode<DecodedJwtPayload>(jwtToken);
|
||||
|
||||
// Verificar expiración (opcional, pero buena práctica aquí también)
|
||||
const currentTime = Date.now() / 1000;
|
||||
if (decodedToken.exp && decodedToken.exp < currentTime) {
|
||||
console.warn("Token expirado al procesar.");
|
||||
logout(); // Llama a logout que limpia todo
|
||||
return;
|
||||
logout(); return;
|
||||
}
|
||||
|
||||
let permissions: string[] = [];
|
||||
if (decodedToken.permission) {
|
||||
permissions = Array.isArray(decodedToken.permission) ? decodedToken.permission : [decodedToken.permission];
|
||||
}
|
||||
|
||||
const userForContext: UserContextData = {
|
||||
userId: parseInt(decodedToken.sub, 10),
|
||||
username: decodedToken.name,
|
||||
@@ -75,27 +111,23 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||
esSuperAdmin: decodedToken.role === "SuperAdmin" || (Array.isArray(decodedToken.role) && decodedToken.role.includes("SuperAdmin")),
|
||||
debeCambiarClave: decodedToken.debeCambiarClave?.toLowerCase() === 'true',
|
||||
idPerfil: decodedToken.idPerfil ? parseInt(decodedToken.idPerfil, 10) : 0,
|
||||
permissions: permissions,
|
||||
perfil: decodedToken.perfil || 'Usuario' // Asignar un valor por defecto si no existe
|
||||
permissions: Array.isArray(decodedToken.permission) ? decodedToken.permission : (decodedToken.permission ? [decodedToken.permission] : []),
|
||||
perfil: decodedToken.perfil || 'Usuario'
|
||||
};
|
||||
|
||||
setToken(jwtToken);
|
||||
setUser(userForContext);
|
||||
setIsAuthenticated(true);
|
||||
localStorage.setItem('authToken', jwtToken);
|
||||
localStorage.setItem('authUser', JSON.stringify(userForContext)); // Guardar el usuario procesado
|
||||
|
||||
// Lógica para el modal de cambio de clave
|
||||
if (userForContext.debeCambiarClave) {
|
||||
setShowForcedPasswordChangeModal(true);
|
||||
setIsPasswordChangeForced(true);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error al decodificar o procesar token:", error);
|
||||
logout(); // Limpiar estado si el token es inválido
|
||||
console.error("Error al decodificar token:", error);
|
||||
logout();
|
||||
}
|
||||
};
|
||||
}, [logout]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
@@ -104,20 +136,18 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||
processTokenAndSetUser(storedToken);
|
||||
}
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
}, [processTokenAndSetUser]);
|
||||
|
||||
const login = (apiLoginResponse: LoginResponseDto) => {
|
||||
processTokenAndSetUser(apiLoginResponse.token); // Procesar el token recibido
|
||||
};
|
||||
useEffect(() => {
|
||||
if (user && isAuthenticated) {
|
||||
fetchAlertas(user);
|
||||
const intervalId = setInterval(() => fetchAlertas(user), 300000); // Refresca cada 5 mins
|
||||
return () => clearInterval(intervalId);
|
||||
}
|
||||
}, [user, isAuthenticated, fetchAlertas]);
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem('authToken');
|
||||
localStorage.removeItem('authUser');
|
||||
setToken(null);
|
||||
setUser(null);
|
||||
setIsAuthenticated(false);
|
||||
setShowForcedPasswordChangeModal(false);
|
||||
setIsPasswordChangeForced(false);
|
||||
const login = (apiLoginResponse: any) => {
|
||||
processTokenAndSetUser(apiLoginResponse.token);
|
||||
};
|
||||
|
||||
const passwordChangeCompleted = () => {
|
||||
@@ -138,6 +168,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||
<AuthContext.Provider value={{
|
||||
isAuthenticated, user, token, isLoading,
|
||||
showForcedPasswordChangeModal, isPasswordChangeForced,
|
||||
alertas, marcarAlertaComoLeida, marcarGrupoDeAlertasLeido,
|
||||
setShowForcedPasswordChangeModal, passwordChangeCompleted,
|
||||
login, logout
|
||||
}}>
|
||||
|
||||
Reference in New Issue
Block a user