import { defineStore } from 'pinia' import { computed, ref } from 'vue' import { apiClient } from '@/lib/axios' import { getUserAbilityRules } from '@/utils/auth-ability' import type { Rule } from '@/plugins/casl/ability' import type { AuthUserCookie } from '@/composables/useOrganisationContext' interface MeResponse { id: string first_name: string last_name: string full_name: string email: string timezone: string locale: string avatar: string | null organisations: Array<{ id: string name: string slug: string role: string }> app_roles: string[] permissions: string[] } export const useAuthStore = defineStore('auth', () => { const user = ref(null) const abilityRules = ref([]) const isInitialized = ref(false) const isAuthenticated = computed(() => !!user.value) function setUser(userData: AuthUserCookie, roles: string[]) { user.value = userData abilityRules.value = getUserAbilityRules(roles) } function clearState() { user.value = null abilityRules.value = [] } function handleUnauthorized() { clearState() // Do NOT reset isInitialized — the full page reload (below) resets all JS state. // Resetting it here causes a race condition: the async 401 interceptor fires // after doInitialize() sets isInitialized=true, putting the app back into // a loading state that never resolves. if (typeof window !== 'undefined') { const publicPaths = ['/login', '/forgot-password', '/reset-password', '/verify-email-change'] if (!publicPaths.some(p => window.location.pathname.startsWith(p))) { window.location.href = '/login' } } } async function logout() { try { await apiClient.post('/auth/logout') } catch { // Continue with logout even if API call fails } clearState() } let initializePromise: Promise | null = null function initialize(): Promise { if (isInitialized.value) return Promise.resolve() if (!initializePromise) { initializePromise = doInitialize() } return initializePromise } async function doInitialize(): Promise { try { const { data } = await apiClient.get<{ success: boolean; data: MeResponse }>('/auth/me') const me = data.data const roles = me.app_roles ?? [] setUser( { id: me.id, name: me.full_name, email: me.email, roles, organisations: me.organisations, }, roles, ) } catch { clearState() } finally { isInitialized.value = true } } return { user, abilityRules, isAuthenticated, isInitialized, setUser, clearState, logout, handleUnauthorized, initialize, } })