Dynavera/site/src/stores/userStore.ts

219 lines
6.9 KiB
TypeScript
Raw Normal View History

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { apiClient, isAxiosError, API } from '../router/api'
import type { User, SessionResponse } from '../types/user'
import type { Organization, Role } from 'src/types/organization'
const orgUuidKey = 'userSelectedOrganizationUuid'
export const useUserStore = defineStore('user', () => {
const isAuthenticated = ref(false)
const isAdmin = ref(false)
const isGeneralManager = computed(() => {
if (!isAuthenticated.value || !user.value) return false
return user.value.is_manager
})
const loading = ref(false)
const error = ref<string | null>(null)
const user = ref<User | null>(null)
const userJoinedOrganizations = ref<Organization[]>([])
const userSelectedOrganization = ref<Organization | null>(null)
const userJoinedRoles = ref<Role[]>([])
const displayName = computed(() => {
if (!user.value) return ''
return `${user.value.first_name} ${user.value.last_name}`
})
const setUser = (userData: User | null) => {
user.value = userData
isAuthenticated.value = !!userData
}
const setJoinedOrganizations = (organizations: Organization[]) => {
userJoinedOrganizations.value = organizations
if (organizations.length > 0) {
const stored = localStorage.getItem(orgUuidKey)
const matched = organizations.find((org) => org.uuid === stored)
if (matched) {
userSelectedOrganization.value = matched
return
}
userSelectedOrganization.value = organizations[0]
localStorage.setItem(orgUuidKey, organizations[0].uuid)
} else {
userSelectedOrganization.value = null
localStorage.removeItem(orgUuidKey)
}
}
const setSelectedOrganization = (organization: Organization | null) => {
userSelectedOrganization.value = organization
if (organization) {
localStorage.setItem(orgUuidKey, organization.uuid)
} else {
localStorage.removeItem(orgUuidKey)
}
}
const fetchSession = async (force = false) => {
if (isAuthenticated.value && !force) return user.value
loading.value = true
error.value = null
try {
const response = await apiClient.get<SessionResponse>(API.session())
if (response.data?.isAuthenticated) {
const userData = await apiClient.get<User>(API.me())
setUser(userData.data)
await fetchJoinedOrganizations()
} else {
setUser(null)
isAuthenticated.value = false
}
return user.value
} catch (err: unknown) {
if (isAxiosError(err)) {
error.value = err.response?.data?.detail || err.response?.data?.error || err.message
} else if (err instanceof Error) {
error.value = err.message
} else {
error.value = String(err)
}
setUser(null)
throw err
} finally {
loading.value = false
}
}
const fetchJoinedOrganizations = async () => {
if (!user.value) return
try {
const response = await apiClient.get<Organization[]>(API.organizations())
setJoinedOrganizations(response.data)
return response.data
} catch (err: unknown) {
console.error('Failed to fetch organizations', err)
setJoinedOrganizations([])
return []
}
}
const fetchJoinedRoles = async () => {
if (!user.value || !userSelectedOrganization.value) return
try {
const response = await apiClient.get<Role[]>(
API.organizationRoles(userSelectedOrganization.value.uuid),
)
setJoinedRoles(response.data)
return response.data
} catch (err: unknown) {
console.error('Failed to fetch role memberships', err)
setJoinedRoles([])
return []
}
}
const setJoinedRoles = (roles: Role[]) => {
userJoinedRoles.value = roles
}
const login = async (emailAddress: string, password: string) => {
loading.value = true
error.value = null
try {
const res = await apiClient.post<{
user: User
message?: string
}>(API.login(), { email_address: emailAddress, password })
setUser(res.data?.user ?? null)
return res.data
} catch (err: unknown) {
if (isAxiosError(err)) {
error.value = err.response?.data?.error || err.response?.data?.detail || err.message
} else if (err instanceof Error) {
error.value = err.message
} else {
error.value = String(err)
}
throw err
} finally {
loading.value = false
}
}
const register = async (payload: {
email_address: string
password: string
confirm_password?: string
first_name: string
last_name: string
date_of_birth?: string
manager: boolean
}) => {
loading.value = true
error.value = null
try {
await apiClient.post(API.signup(), payload)
await login(payload.email_address, payload.password)
} catch (err: unknown) {
if (isAxiosError(err)) {
error.value = err.response?.data?.detail || err.response?.data?.error || err.message
} else if (err instanceof Error) {
error.value = err.message
} else {
error.value = String(err)
}
throw err
} finally {
loading.value = false
}
}
const logout = async () => {
loading.value = true
error.value = null
try {
await apiClient.post(API.logout())
} catch (err: unknown) {
if (isAxiosError(err)) {
error.value = err.response?.data?.detail || err.response?.data?.error || err.message
} else if (err instanceof Error) {
error.value = err.message
} else {
error.value = String(err)
}
throw err
} finally {
setUser(null)
loading.value = false
}
}
return {
user,
displayName,
isAuthenticated,
isAdmin,
isGeneralManager,
loading,
error,
userJoinedOrganizations,
userSelectedOrganization,
userJoinedRoles,
setUser,
fetchSession,
setJoinedOrganizations,
setSelectedOrganization,
setJoinedRoles,
fetchJoinedOrganizations,
fetchJoinedRoles,
login,
register,
logout,
}
})