import { defineStore } from 'pinia' import { computed, ref } from 'vue' import { type User } from '@/api/generated/crabs/evening_detective_server' import { buildClient } from '@/api/generated/crabs/evening_detective_server/client' export const useAuthStore = defineStore('auth', () => { // ===== STATE ===== const accessToken = ref(null) const refreshToken = ref(null) const user = ref(null) const isLoading = ref(false) const error = ref(null) // ===== GETTERS ===== const isAuthenticated = computed(() => !!accessToken.value) const username = computed(() => user.value?.username || '') const userRoles = computed(() => user.value?.roles || []) // ===== ACTIONS ===== // Инициализация из localStorage при загрузке function initFromStorage() { const token = localStorage.getItem('accessToken') const refresh = localStorage.getItem('refreshToken') if (token) { accessToken.value = token refreshToken.value = refresh // Получаем данные пользователя fetchUser() } } function getToken(): string | null { return accessToken.value } // Получение данных пользователя async function fetchUser() { if (!accessToken.value) return try { const client = buildClient(getToken) const response = await client.GetMe({}) if (response.error) { error.value = response.error return } if (response.user) { user.value = response.user } } catch (err) { console.error('Failed to fetch user:', err) // Если 401 — токен протух if (err instanceof Error && err.message.includes('401')) { await logout() } } } // Логин async function login(email: string, password: string) { isLoading.value = true error.value = null try { const client = buildClient(getToken) const response = await client.Login({ email, password }) if (response.error) { error.value = response.error return false } // Сохраняем токены if (response.accessToken) { accessToken.value = response.accessToken refreshToken.value = response.refreshToken || null // Сохраняем в localStorage localStorage.setItem('accessToken', response.accessToken) if (response.refreshToken) { localStorage.setItem('refreshToken', response.refreshToken) } // Получаем данные пользователя await fetchUser() return true } return false } catch (err) { error.value = err instanceof Error ? err.message : 'Login failed' return false } finally { isLoading.value = false } } // Обновление токена async function refreshTokenAction() { if (!refreshToken.value) return false try { const client = buildClient(getToken) const response = await client.Refresh({ refreshToken: refreshToken.value, }) if (response.error || !response.accessToken) { return false } // Обновляем токены accessToken.value = response.accessToken refreshToken.value = response.refreshToken || null localStorage.setItem('accessToken', response.accessToken) if (response.refreshToken) { localStorage.setItem('refreshToken', response.refreshToken) } return true } catch { return false } } // Регистрация async function signup(username: string, email: string) { isLoading.value = true error.value = null try { const client = buildClient(getToken) const response = await client.Signup({ username, email }) if (response.error) { error.value = response.error return false } return true } catch (err) { error.value = err instanceof Error ? err.message : 'Signup failed' return false } finally { isLoading.value = false } } // Восстановление пароля async function refreshPassword(email: string) { isLoading.value = true error.value = null try { const client = buildClient(getToken) const response = await client.RefreshPassword({ email }) if (response.error) { error.value = response.error return false } return true } catch (err) { error.value = err instanceof Error ? err.message : 'Password reset failed' return false } finally { isLoading.value = false } } // Выход async function logout() { accessToken.value = null refreshToken.value = null user.value = null error.value = null localStorage.removeItem('accessToken') localStorage.removeItem('refreshToken') } // Проверка ролей function hasRole(role: string): boolean { return userRoles.value.includes(role) } function hasAnyRole(roles: string[]): boolean { return roles.some((role) => userRoles.value.includes(role)) } // ===== RETURN ===== return { // State accessToken, refreshToken, user, isLoading, error, // Getters isAuthenticated, username, userRoles, // Actions initFromStorage, getToken, login, signup, refreshPassword, logout, fetchUser, refreshTokenAction, hasRole, hasAnyRole, } })