diff --git a/src/stores/auth.ts b/src/stores/auth.ts new file mode 100644 index 0000000..45da8f9 --- /dev/null +++ b/src/stores/auth.ts @@ -0,0 +1,73 @@ +import { defineStore } from 'pinia'; +import { ref, computed } from 'vue'; +import { api } from '@/api/client'; +import type { User } from '@/api/generated/main'; + +export const useAuthStore = defineStore('auth', () => { + const user = ref(null); + const loading = ref(false); + const error = ref(null); + + const isAuthenticated = computed(() => !!user.value); + const isAdmin = computed(() => user.value?.roles?.includes('admin') ?? false); + + async function login(email: string, password: string) { + loading.value = true; + error.value = null; + + try { + const response = await api.login({ email, password }); + if (response.error) { + error.value = response.error; + return false; + } + await fetchMe(); + return true; + } catch (err) { + error.value = err instanceof Error ? err.message : 'Login failed'; + return false; + } finally { + loading.value = false; + } + } + + async function fetchMe() { + loading.value = true; + try { + const response = await api.getMe(); + if (response.error) { + error.value = response.error; + user.value = null; + } else if (response.user) { + user.value = response.user; + } + } catch (err) { + user.value = null; + throw err; + } finally { + loading.value = false; + } + } + + async function logout() { + await api.logout(); + user.value = null; + error.value = null; + } + + function hasRole(role: string): boolean { + return user.value?.roles?.includes(role) ?? false; + } + + return { + user, + loading, + error, + isAuthenticated, + isAdmin, + login, + fetchMe, + logout, + hasRole, + }; +});