generated from VLADIMIR/template_frontend
227 lines
5.5 KiB
TypeScript
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,
|
|
}
|
|
})
|