Files
evening_detective_frontend/src/stores/auth.ts
T
2026-07-20 22:49:45 +07:00

227 lines
5.5 KiB
TypeScript

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<string | null>(null)
const refreshToken = ref<string | null>(null)
const user = ref<User | null>(null)
const isLoading = ref(false)
const error = ref<string | null>(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,
}
})