import { ref, computed } from 'vue'; import api from './services/api'; // Наш API сервис import router from './router'; // Vue Router для перенаправлений // Реактивные переменные для состояния пользователя и токена const user = ref(null); // Данные пользователя (или null, если не вошел) const token = ref(localStorage.getItem('userToken') || null); // Токен из localStorage или null const loading = ref(false); // Состояние загрузки для операций аутентификации // Вычисляемое свойство для проверки, аутентифицирован ли пользователь const isAuthenticated = computed(() => !!token.value && !!user.value); // Функция для установки токена и данных пользователя function setUserData(userData, userToken) { user.value = userData; token.value = userToken; localStorage.setItem('userToken', userToken); // Сохраняем токен в localStorage // Устанавливаем токен в заголовки Axios для последующих запросов (если не используется интерсептор) // Однако, наш интерсептор в api.js уже делает это, так что эта строка может быть избыточна, // но не повредит, если интерсептор по какой-то причине не сработает сразу. // api.defaults.headers.common['Authorization'] = `Bearer ${userToken}`; } // Функция для загрузки данных пользователя, если токен есть (например, при обновлении страницы) async function fetchUser() { if (token.value) { try { console.log('Пытаемся загрузить пользователя с токеном из localStorage...'); const response = await api.getMe(); // Используем наш API сервис console.log('Ответ от /auth/me:', response); // Проверяем структуру ответа if (!response.data) { throw new Error('Неверный формат ответа от сервера'); } // Добавляем дополнительное логирование для отладки console.log('Получены данные пользователя:', response.data); console.log('Значение isAdmin в ответе:', response.data.isAdmin); console.log('Статус блокировки:', response.data.blocked); // Проверяем, не заблокирован ли пользователь if (response.data.blocked) { console.log('[Auth] Пользователь заблокирован, выполняем принудительный выход'); // Показываем уведомление о блокировке const notificationEvent = new CustomEvent('show-toast', { detail: { message: `Ваш аккаунт заблокирован. ${response.data.blockReason || 'Обратитесь в поддержку.'}`, type: 'error', duration: 10000 } }); window.dispatchEvent(notificationEvent); // Выходим из системы await logout(); return; } // Сохраняем данные пользователя user.value = response.data; console.log('Пользователь успешно загружен:', user.value); console.log('isAuthenticated после загрузки пользователя:', isAuthenticated.value); console.log('Пользователь является администратором:', user.value.isAdmin ? 'Да' : 'Нет'); } catch (error) { console.error('Не удалось загрузить пользователя по токену:', error.response ? error.response.data : error.message); // Проверяем, не связана ли ошибка с блокировкой if (error.response && error.response.status === 403) { console.log('[Auth] Пользователь заблокирован согласно ответу сервера'); // Показываем уведомление о блокировке const notificationEvent = new CustomEvent('show-toast', { detail: { message: error.response.data.message || 'Ваш аккаунт заблокирован администратором.', type: 'error', duration: 10000 } }); window.dispatchEvent(notificationEvent); } // Если токен невалиден или пользователь заблокирован, очищаем его и данные пользователя await logout(); // Вызываем logout, чтобы очистить всё } } else { console.log('Токен не найден, пользователь не загружен.'); } } // Функция входа async function login(credentials) { try { loading.value = true; const response = await api.login(credentials); if (response?.data) { setUserData(response.data, response.data.token); router.push('/'); // Перенаправляем на главную после успешного входа return response.data; } } catch (error) { console.error('[Auth] Ошибка входа:', error); // Обработка специального случая блокировки аккаунта if (error.response?.status === 403 && error.response?.data?.blocked) { const errorData = error.response.data; console.log('[Auth] Аккаунт заблокирован:', errorData.message); // Просто перенаправляем на страницу входа с параметром блокировки router.replace({ path: '/login', query: { blocked: 'true' } }); } throw error; } finally { loading.value = false; } } // Функция регистрации async function register(userData) { try { const response = await api.register(userData); // response.data должен содержать { _id, name, email, token, message } const { token: userToken, ...newUserData } = response.data; setUserData(newUserData, userToken); // Обычно после регистрации мы либо сразу логиним пользователя, либо просим его войти. // Здесь мы его сразу "залогинили", сохранив токен и данные. router.push('/'); // Перенаправляем на главную (или на страницу подтверждения email, если бы она была) return true; } catch (error) { console.error('Ошибка регистрации:', error.response ? error.response.data : error.message); throw error.response ? error.response.data : new Error('Ошибка сети или сервера при регистрации'); } } // Функция выхода async function logout() { user.value = null; token.value = null; localStorage.removeItem('userToken'); // Удаляем токен из заголовков Axios (если устанавливали его напрямую) // delete apiClient.defaults.headers.common['Authorization']; // apiClient не экспортируется из api.js напрямую для этого // Наш интерсептор запросов в api.js перестанет добавлять токен, так как его не будет в localStorage. router.push('/login'); // Перенаправляем на страницу входа console.log('Пользователь вышел из системы.'); } // Функция обработки события блокировки аккаунта async function handleAccountBlocked(data) { console.log('[Auth] Получено уведомление о блокировке аккаунта:', data); try { // Показываем уведомление о блокировке const notificationEvent = new CustomEvent('show-toast', { detail: { message: data?.message || 'Ваш аккаунт был заблокирован администратором.', type: 'error', duration: 10000 } }); window.dispatchEvent(notificationEvent); // Выходим из системы await logout(); // Перенаправляем на страницу входа с параметром блокировки router.replace({ path: '/login', query: { blocked: 'true' } }); } catch (error) { console.error('[Auth] Ошибка при обработке блокировки аккаунта:', error); // В случае ошибки все равно выполняем logout и перенаправление try { await logout(); router.replace('/login?blocked=true'); } catch (logoutErr) { console.error('[Auth] Ошибка при выходе после блокировки:', logoutErr); // Принудительное перенаправление window.location.href = '/login?blocked=true'; } } } // Функция обработки события разблокировки аккаунта async function handleAccountUnblocked(data) { console.log('[Auth] Получено уведомление о разблокировке аккаунта:', data); // Показываем уведомление о разблокировке const notificationEvent = new CustomEvent('show-toast', { detail: { message: data?.message || 'Ваш аккаунт был разблокирован администратором.', type: 'success', duration: 5000 } }); window.dispatchEvent(notificationEvent); // Если пользователь уже на странице логина, добавляем параметр unblocked=true if (window.location.pathname === '/login') { router.replace({ path: '/login', query: { unblocked: 'true' } }); } else { // Перенаправляем на страницу входа с параметром разблокировки router.replace({ path: '/login', query: { unblocked: 'true' } }); } } // Экспортируем то, что понадобится в компонентах export function useAuth() { return { user, token, isAuthenticated, login, register, logout, fetchUser, // Эту функцию нужно будет вызвать при инициализации приложения handleAccountBlocked, // Добавляем функцию обработки блокировки аккаунта handleAccountUnblocked // Добавляем функцию обработки разблокировки аккаунта }; } // Экспортируем функции напрямую для использования в других частях приложения export { handleAccountBlocked, handleAccountUnblocked };