import { ApiResponse } from './api'; import { PUBLIC_API_URL } from './api'; // Интерфейс для запроса входа interface LoginCredentials { username: string; password: string; } // Интерфейс для ответа с токеном interface TokenResponse { access_token: string; token_type: string; } // Интерфейс для пользователя interface User { id: number; email: string; first_name: string; last_name: string; is_admin: boolean; role?: string; } // Константа для ключа в localStorage // Используем только один ключ 'token' для хранения токена const TOKEN_KEY = 'token'; // API для аутентификации export const authApi = { // Вход в систему login: async (email: string, password: string): Promise> => { try { // Создаем FormData для отправки данных в формате x-www-form-urlencoded const formData = new URLSearchParams(); formData.append('username', email); formData.append('password', password); console.log(`Попытка входа на ${PUBLIC_API_URL}/auth/login с email: ${email}`); // Выполняем запрос напрямую через fetch const response = await fetch(`${PUBLIC_API_URL}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: formData.toString(), }); const data = await response.json(); console.log('Ответ сервера при входе:', data); // Обрабатываем ответ if (!response.ok) { console.error('Ошибка входа, код', response.status, data); return { success: false, error: data.detail || 'Ошибка при авторизации', message: 'Не удалось войти в систему', }; } // Проверяем, содержит ли ответ токен if (!data.access_token) { console.error('Ответ не содержит access_token'); return { success: false, error: 'Неверный формат ответа от сервера', message: 'Ответ сервера не содержит токен доступа', }; } // Сохраняем токен в localStorage с явным преобразованием в строку try { localStorage.setItem(TOKEN_KEY, String(data.access_token)); console.log('Токен сохранен в localStorage:', String(data.access_token).substring(0, 20) + '...'); // Проверяем, что токен действительно сохранился const savedToken = localStorage.getItem(TOKEN_KEY); console.log('Проверка сохранения токена:', savedToken ? 'токен сохранен' : 'токен НЕ сохранен'); // Удаляем устаревший ключ, если он есть if (localStorage.getItem('auth_token')) { localStorage.removeItem('auth_token'); console.log('Устаревший ключ auth_token удален'); } } catch (storageError) { console.error('Ошибка при сохранении токена в localStorage:', storageError); } return { success: true, data: { access_token: data.access_token, token_type: data.token_type } }; } catch (error) { console.error('Ошибка при входе:', error); return { success: false, error: error instanceof Error ? error.message : 'Ошибка при авторизации', message: 'Не удалось войти в систему' }; } }, // Получение профиля текущего пользователя getProfile: async (): Promise => { try { const token = localStorage.getItem(TOKEN_KEY); console.log('Получение профиля с токеном:', token ? token.substring(0, 20) + '...' : 'нет токена'); if (!token) { console.log('Токен отсутствует, профиль не запрашиваем'); return null; } console.log(`Запрос профиля на ${PUBLIC_API_URL}/users/me`); const response = await fetch(`${PUBLIC_API_URL}/users/me`, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, }); if (!response.ok) { const errorText = await response.text(); console.error(`Ошибка получения профиля: HTTP ${response.status}:`, errorText); throw new Error(`Ошибка при получении профиля: ${response.status}`); } const responseData = await response.json(); console.log('Полный ответ с профилем пользователя:', responseData); // Защита от неожиданных форматов ответа if (!responseData) { console.error('Ответ от сервера пуст'); return null; } // Обрабатываем вложенную структуру - пользователь может быть в поле 'user' const userData = responseData.user || responseData; console.log('Данные пользователя после обработки:', userData); // Проверяем, что полученный объект содержит необходимые поля if (!userData || typeof userData !== 'object' || !('id' in userData)) { console.error('Полученные данные не содержат необходимых полей пользователя'); return null; } // Если у пользователя нет явного признака администратора, // но он имеет роль "admin", устанавливаем is_admin = true const userWithAdminCheck = { ...userData }; if (userData.role === 'admin' && userData.is_admin === undefined) { userWithAdminCheck.is_admin = true; console.log('Установлен флаг is_admin=true на основе роли admin'); } // Убедимся, что is_admin является булевым значением if (typeof userWithAdminCheck.is_admin !== 'boolean') { userWithAdminCheck.is_admin = Boolean(userWithAdminCheck.is_admin); console.log('Преобразовали is_admin в булево значение:', userWithAdminCheck.is_admin); } return userWithAdminCheck as User; } catch (error) { console.error('Ошибка при получении профиля:', error); return null; } }, // Выход из системы logout: (): void => { try { localStorage.removeItem(TOKEN_KEY); // Удаляем устаревший ключ, если он есть if (localStorage.getItem('auth_token')) { localStorage.removeItem('auth_token'); } console.log('Токен удален из localStorage'); } catch (error) { console.error('Ошибка при удалении токена:', error); } }, // Проверка, авторизован ли пользователь isAuthenticated: (): boolean => { try { const token = localStorage.getItem(TOKEN_KEY); return !!token; } catch (error) { console.error('Ошибка при проверке токена:', error); return false; } } };