refactor: remove unnecessary React import in AuthButton component due to new JSX transform refactor: simplify imports in LanguageSelector component fix: remove unused AuthResponse type import in useAuth hook fix: access Vite environment variables in a type-safe manner in api utility
142 lines
3.6 KiB
TypeScript
142 lines
3.6 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import type { User, AuthTokens, LoginCredentials, RegisterData } from '@avanzacast/shared-types';
|
|
import {
|
|
saveTokens,
|
|
saveUser,
|
|
getTokens,
|
|
getUser,
|
|
clearAuth,
|
|
isAuthenticated as checkAuth
|
|
} from '@avanzacast/shared-utils';
|
|
import { apiClient } from '@avanzacast/shared-utils';
|
|
|
|
interface UseAuthReturn {
|
|
user: User | null;
|
|
tokens: AuthTokens | null;
|
|
isAuthenticated: boolean;
|
|
isLoading: boolean;
|
|
login: (credentials: LoginCredentials) => Promise<{ success: boolean; error?: string }>;
|
|
register: (data: RegisterData) => Promise<{ success: boolean; error?: string }>;
|
|
logout: () => void;
|
|
refreshAuth: () => Promise<void>;
|
|
}
|
|
|
|
/**
|
|
* Hook compartido para manejar autenticación en todos los módulos
|
|
*/
|
|
export function useAuth(): UseAuthReturn {
|
|
const [user, setUser] = useState<User | null>(null);
|
|
const [tokens, setTokens] = useState<AuthTokens | null>(null);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
// Cargar datos de autenticación al montar
|
|
useEffect(() => {
|
|
const loadAuth = () => {
|
|
const savedUser = getUser();
|
|
const savedTokens = getTokens();
|
|
|
|
if (savedUser && savedTokens && checkAuth()) {
|
|
setUser(savedUser);
|
|
setTokens(savedTokens);
|
|
}
|
|
setIsLoading(false);
|
|
};
|
|
|
|
loadAuth();
|
|
}, []);
|
|
|
|
// Login
|
|
const login = useCallback(async (credentials: LoginCredentials) => {
|
|
setIsLoading(true);
|
|
try {
|
|
const response = await apiClient.login(credentials);
|
|
|
|
if (response.success && response.data) {
|
|
const { user: userData, tokens: tokenData } = response.data;
|
|
setUser(userData);
|
|
setTokens(tokenData);
|
|
saveUser(userData);
|
|
saveTokens(tokenData);
|
|
return { success: true };
|
|
}
|
|
|
|
return {
|
|
success: false,
|
|
error: response.error?.message || 'Error al iniciar sesión'
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : 'Error desconocido'
|
|
};
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
// Register
|
|
const register = useCallback(async (data: RegisterData) => {
|
|
setIsLoading(true);
|
|
try {
|
|
const response = await apiClient.register(data);
|
|
|
|
if (response.success && response.data) {
|
|
const { user: userData, tokens: tokenData } = response.data;
|
|
setUser(userData);
|
|
setTokens(tokenData);
|
|
saveUser(userData);
|
|
saveTokens(tokenData);
|
|
return { success: true };
|
|
}
|
|
|
|
return {
|
|
success: false,
|
|
error: response.error?.message || 'Error al registrarse'
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : 'Error desconocido'
|
|
};
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
// Logout
|
|
const logout = useCallback(() => {
|
|
setUser(null);
|
|
setTokens(null);
|
|
clearAuth();
|
|
|
|
// Llamar al endpoint de logout en segundo plano
|
|
apiClient.logout().catch(console.error);
|
|
}, []);
|
|
|
|
// Refresh auth (actualizar datos del usuario)
|
|
const refreshAuth = useCallback(async () => {
|
|
if (!tokens) return;
|
|
|
|
try {
|
|
const response = await apiClient.getProfile();
|
|
if (response.success && response.data) {
|
|
setUser(response.data);
|
|
saveUser(response.data);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error refreshing auth:', error);
|
|
}
|
|
}, [tokens]);
|
|
|
|
return {
|
|
user,
|
|
tokens,
|
|
isAuthenticated: !!user && !!tokens,
|
|
isLoading,
|
|
login,
|
|
register,
|
|
logout,
|
|
refreshAuth,
|
|
};
|
|
}
|