fix: auth race condition on refresh, section edit dialog, time slot duplicate, autocomplete disable
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { apiClient } from '@/lib/axios'
|
||||
import { useOrganisationStore } from '@/stores/useOrganisationStore'
|
||||
import type { MeResponse, Organisation, User } from '@/types/auth'
|
||||
|
||||
@@ -11,8 +12,10 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
const organisations = ref<Organisation[]>([])
|
||||
const appRoles = ref<string[]>([])
|
||||
const permissions = ref<string[]>([])
|
||||
const isInitialized = ref(false)
|
||||
|
||||
const isAuthenticated = computed(() => !!token.value)
|
||||
// Requires both a token AND a validated user — token alone is not enough
|
||||
const isAuthenticated = computed(() => !!token.value && !!user.value)
|
||||
const isSuperAdmin = computed(() => appRoles.value?.includes('super_admin') ?? false)
|
||||
|
||||
const currentOrganisation = computed(() => {
|
||||
@@ -64,6 +67,40 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
orgStore.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once on app startup. If a token exists in localStorage,
|
||||
* validates it by calling GET /auth/me. On 401, clears everything.
|
||||
* Safe to call multiple times — subsequent calls return the same promise.
|
||||
*/
|
||||
let initializePromise: Promise<void> | null = null
|
||||
|
||||
function initialize(): Promise<void> {
|
||||
if (isInitialized.value) return Promise.resolve()
|
||||
if (!initializePromise) {
|
||||
initializePromise = doInitialize()
|
||||
}
|
||||
return initializePromise
|
||||
}
|
||||
|
||||
async function doInitialize(): Promise<void> {
|
||||
if (!token.value) {
|
||||
isInitialized.value = true
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await apiClient.get<{ success: boolean; data: MeResponse }>('/auth/me')
|
||||
setUser(data.data)
|
||||
}
|
||||
catch {
|
||||
// Token invalid/expired — clear everything
|
||||
logout()
|
||||
}
|
||||
finally {
|
||||
isInitialized.value = true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
token,
|
||||
user,
|
||||
@@ -71,11 +108,13 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
appRoles,
|
||||
permissions,
|
||||
isAuthenticated,
|
||||
isInitialized,
|
||||
isSuperAdmin,
|
||||
currentOrganisation,
|
||||
setToken,
|
||||
setUser,
|
||||
setActiveOrganisation,
|
||||
logout,
|
||||
initialize,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user