import { defineStore } from 'pinia' import type { UserData } from '~/shared/types/user-data' import type { Site } from '~/shared/types/sites' import { getCurrentUser, login, logout } from '~/shared/services/auth' /** * Callbacks enregistres par les composables singletons qui doivent * reinitialiser leur etat quand la session est invalidee (ex: expiration * JWT, logout depuis un intercepteur 401). Utilise le pattern * "callback registration" (Option C) pour eviter une dependance croisee * depuis shared/ vers modules/ — chaque composable s'auto-enregistre. */ const onSessionClearedCallbacks: Array<() => void> = [] /** * Enregistre un callback a invoquer lorsque clearSession() est appelee. * Typiquement invoque au setup-time du composable (module-level), donc * une seule fois par instance de composable singleton. */ export function onAuthSessionCleared(cb: () => void): void { onSessionClearedCallbacks.push(cb) } export const useAuthStore = defineStore('auth', { state: () => ({ user: null as UserData | null, isLoading: false, checked: false }), getters: { isAuthenticated: (state) => Boolean(state.user) }, actions: { clearSession() { this.user = null this.checked = true this.isLoading = false // Notifie les composables singletons (useCurrentSite, etc.) afin // qu'ils reinitialisation leur etat — necessaire quand la session // est invalidee par un intercepteur 401 sans passer par logout.vue. onSessionClearedCallbacks.forEach((cb) => cb()) }, async ensureSession() { if (this.checked) { return this.user } this.checked = true try { const me = await getCurrentUser() this.user = me return me } catch { this.user = null return null } }, async login(username: string, password: string) { this.isLoading = true try { await login(username, password) const me = await getCurrentUser() this.user = me this.checked = true return me } finally { this.isLoading = false } }, async logout() { this.isLoading = true try { await logout() } catch { // Ignore logout errors so we can still clear local auth state. } finally { this.user = null this.checked = true this.isLoading = false } }, async refreshUser() { try { const me = await getCurrentUser() this.user = me } catch { // Silently fail — user session might have expired } }, /** * Action dediee au switch du site courant (ticket 3 module Sites). * Utilisee par useCurrentSite apres la confirmation serveur, et en * rollback si la requete PATCH echoue apres une mutation optimistic. * Passer explicitement par une action plutot que muter user.currentSite * directement garantit la tracabilite Pinia (devtools). */ setCurrentSite(site: Site | null) { if (this.user) { this.user.currentSite = site } } } })