feat(core) : footer sidebar — compte connecté + déconnexion inline + version

Déconnexion déplacée du menu vers le footer (compte connecté au survol +
version). useLogout() appelle clearSession() (reset des stores singletons via
onAuthSessionCleared) puis redirige vers /login, sans page /logout intermédiaire.
This commit is contained in:
2026-06-29 10:24:57 +02:00
parent d5bbe8afd9
commit d6a40e4843
10 changed files with 120 additions and 62 deletions
@@ -11,8 +11,9 @@
* la recharger a chaque ouverture du drawer.
*
* State singleton au niveau module : reset automatique au logout via
* `onAuthSessionCleared` (cf. CLAUDE.md regle frontend.md), et reset
* explicite via `resetCategoriesAdmin()` appele depuis logout.vue.
* `onAuthSessionCleared` (cf. CLAUDE.md regle frontend.md), declenche par
* `clearSession()` (logout volontaire `useLogout` ou intercepteur 401).
* `resetCategoriesAdmin()` reste expose pour un reset manuel/tests.
*/
import { ref } from 'vue'
import type { CategoryType } from '~/modules/catalog/types/category'
@@ -38,10 +39,9 @@ function resetCategoriesAdminState(): void {
error.value = null
}
// Auto-enregistrement singleton : purge le state sur 401/clearSession
// pour eviter qu'un user suivant (connecte sur le meme onglet) voie le
// referentiel de l'ancien tenant. Le logout volontaire (page logout.vue)
// appelle directement `resetCategoriesAdmin()` ci-dessous.
// Auto-enregistrement singleton : purge le state sur clearSession() (logout
// volontaire via useLogout, ou intercepteur 401) pour eviter qu'un user suivant
// (connecte sur le meme onglet) voie le referentiel de l'ancien tenant.
onAuthSessionCleared(resetCategoriesAdminState)
export function useCategoriesAdmin() {
@@ -73,9 +73,9 @@ export function useCategoriesAdmin() {
}
/**
* Reset explicite — appele depuis `logout.vue` apres `auth.logout()`
* pour garantir que la prochaine session reparte sur un state propre
* meme si `clearSession()` n'a pas ete declenche (cas logout volontaire).
* Reset explicite expose pour un reset manuel (tests, ou appel cible).
* Au logout, le reset est deja garanti par `onAuthSessionCleared`
* (declenche par `clearSession()` dans `auth.logout()`).
*/
function resetCategoriesAdmin(): void {
resetCategoriesAdminState()
-35
View File
@@ -1,35 +0,0 @@
<template>
<div class="flex h-full items-center justify-center">
<p class="text-neutral-500">{{ $t('auth.logout') }}...</p>
</div>
</template>
<script setup lang="ts">
definePageMeta({ layout: 'auth' })
const auth = useAuthStore()
const { resetSidebar } = useSidebar()
const { resetModules } = useModules()
const { resetCurrentSite } = useCurrentSite()
const { resetAuditLog } = useAuditLog()
const { resetCategoriesAdmin } = useCategoriesAdmin()
onMounted(async () => {
try {
await auth.logout()
} finally {
// Les resets sont garantis meme si auth.logout() rejette : eviter
// qu'un user suivant (connecte sur le meme onglet) voie l'etat de
// l'ancien. Toutes les fonctions reset sont synchrones et ne
// peuvent pas throw (juste des assignations reactives).
// navigateTo est dans le finally pour garantir la redirection
// meme si auth.logout() lance une exception (ex: reseau coupé).
resetSidebar()
resetModules()
resetCurrentSite()
resetAuditLog()
resetCategoriesAdmin()
await navigateTo('/login')
}
})
</script>
@@ -6,8 +6,8 @@
* rollback si la requete PATCH `/api/me/current-site` echoue.
*
* Garantie d'unicite : le flag `switching` bloque les double-clicks
* concurrents. Le reset explicite est appele au logout
* (voir `modules/core/pages/logout.vue`).
* concurrents. Le state est purge au logout via `onAuthSessionCleared`
* (declenche par `clearSession()`, cf. `useLogout` et l'intercepteur 401).
*
* Auto-select : aucun. Le backend (`UserRbacProcessor::ensureCurrentSiteConsistency`)
* garantit deja l'invariant "user avec sites non vide => currentSite non null"
@@ -30,8 +30,8 @@ const availableSites = ref<Site[]>([])
const switching = ref(false)
// Enregistrement unique au niveau module (singleton) : quand clearSession()
// est appelee par l'intercepteur 401 de useApi, le state local est purgé
// de la meme facon qu'au logout explicite (logout.vue).
// est appelee (logout volontaire via useLogout, ou intercepteur 401 de useApi),
// le state local est purgé.
onAuthSessionCleared(() => {
currentSite.value = null
availableSites.value = []