fix(sites-front) : refresh state apres switch/delete/401 + redirect logout
- logout.vue : navigateTo('/login') dans le finally, garanti meme si
auth.logout() rejette.
- auth.ts : systeme de callbacks onAuthSessionCleared appeles par
clearSession() (intercepteur 401 de useApi). Les composables modules
s'abonnent pour reset leur state sans que Shared n'importe depuis
modules/ (Option C validee par CLAUDE.md, module -> shared autorise).
- useCurrentSite.ts : enregistre un reset callback + apres un switch
reussi, rafraichit useSidebar().loadSidebar() + refreshNuxtData()
(sinon donnees de page obsoletes cote ancien site sous toast success).
- SiteSelector.vue : le court-circuit "tile deja active" est retire
pour permettre un PATCH de resync quand un autre onglet a bascule le
site entre temps. TODO cross-tab : ecouter un storage event dedie.
- sites.vue admin : auth.refreshUser() apres delete pour refleter le
ON DELETE SET NULL cote user.current_site_id.
- Specs vitest : stub useSidebar/refreshNuxtData, test "tile active"
retourne sur le nouveau contrat PATCH-toujours.
This commit is contained in:
@@ -3,6 +3,24 @@ 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,
|
||||
@@ -17,6 +35,10 @@ export const useAuthStore = defineStore('auth', {
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user