feat(directory) : conserve l'onglet actif au retour liste ↔ fiche (LST-72)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m23s
Pull Request — Quality gate / Frontend (build) (pull_request) Successful in 1m31s

Au retour depuis une fiche (flèche de l'app ou du navigateur), la liste
revenait toujours sur l'onglet Clients. L'onglet actif est désormais
transmis via history.state (hors URL), comme sur Starseed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-25 20:43:38 +02:00
parent 6d95f9e782
commit be079cdbe2
5 changed files with 56 additions and 6 deletions
@@ -192,7 +192,8 @@ async function saveInfo(): Promise<void> {
} }
function goBack(): void { function goBack(): void {
router.push('/directory') // Retour sur l'onglet Clients de la liste (via history.state, hors URL).
router.push({ path: '/directory', state: { tab: 'clients' } })
} }
onMounted(async () => { onMounted(async () => {
@@ -183,6 +183,7 @@ import type { Prospect, ProspectStatus } from '~/modules/directory/services/dto/
import { useProspectService } from '~/modules/directory/services/prospects' import { useProspectService } from '~/modules/directory/services/prospects'
import type { Prestataire } from '~/modules/directory/services/dto/prestataire' import type { Prestataire } from '~/modules/directory/services/dto/prestataire'
import { usePrestataireService } from '~/modules/directory/services/prestataires' import { usePrestataireService } from '~/modules/directory/services/prestataires'
import { readHistoryTab, stampHistoryTab } from '~/utils/historyTab'
definePageMeta({ middleware: ['admin'] }) definePageMeta({ middleware: ['admin'] })
@@ -201,6 +202,14 @@ const tabs = [
{ key: 'prospects', label: t('directory.tabs.prospects'), icon: 'mdi:account-search-outline' }, { key: 'prospects', label: t('directory.tabs.prospects'), icon: 'mdi:account-search-outline' },
{ key: 'prestataires', label: t('directory.tabs.prestataires'), icon: 'mdi:account-hard-hat-outline' }, { key: 'prestataires', label: t('directory.tabs.prestataires'), icon: 'mdi:account-hard-hat-outline' },
] ]
const tabKeys = tabs.map((tab) => tab.key)
// Avant d'ouvrir une fiche : on estampille l'entrée d'historique courante avec
// l'onglet actif → la flèche « précédent » du navigateur restaure le bon onglet.
function navigateToDetail(path: string): void {
stampHistoryTab(activeTab.value)
navigateTo(path)
}
// --- Clients --- // --- Clients ---
const clients = ref<Client[]>([]) const clients = ref<Client[]>([])
@@ -224,7 +233,7 @@ function openCreateClient() {
} }
function openEditClient(item: Record<string, unknown>) { function openEditClient(item: Record<string, unknown>) {
navigateTo(`/directory/clients/${(item as Client).id}`) navigateToDetail(`/directory/clients/${(item as Client).id}`)
} }
// --- Prospects --- // --- Prospects ---
@@ -282,7 +291,7 @@ function openCreateProspect() {
} }
function openEditProspect(item: Record<string, unknown>) { function openEditProspect(item: Record<string, unknown>) {
navigateTo(`/directory/prospects/${(item as Prospect).id}`) navigateToDetail(`/directory/prospects/${(item as Prospect).id}`)
} }
async function convertProspect(row: ProspectRow) { async function convertProspect(row: ProspectRow) {
@@ -319,7 +328,7 @@ function openCreatePrestataire() {
} }
function openEditPrestataire(item: Record<string, unknown>) { function openEditPrestataire(item: Record<string, unknown>) {
navigateTo(`/directory/prestataires/${(item as Prestataire).id}`) navigateToDetail(`/directory/prestataires/${(item as Prestataire).id}`)
} }
// --- Suppression (clients, prospects & prestataires) --- // --- Suppression (clients, prospects & prestataires) ---
@@ -392,6 +401,9 @@ async function confirmDelete() {
watch(statusFilter, loadProspects) watch(statusFilter, loadProspects)
onMounted(async () => { onMounted(async () => {
// Restaure l'onglet quitté lors d'un retour depuis une fiche (flèche app ou
// navigateur). `null` (deep link / reload) → onglet Clients par défaut.
activeTab.value = readHistoryTab(tabKeys) ?? 'clients'
await Promise.all([loadClients(), loadProspects(), loadPrestataires()]) await Promise.all([loadClients(), loadProspects(), loadPrestataires()])
}) })
</script> </script>
@@ -190,7 +190,8 @@ async function saveInfo(): Promise<void> {
} }
function goBack(): void { function goBack(): void {
router.push('/directory') // Retour sur l'onglet Prestataires de la liste (via history.state, hors URL).
router.push({ path: '/directory', state: { tab: 'prestataires' } })
} }
onMounted(async () => { onMounted(async () => {
@@ -226,7 +226,8 @@ async function saveInfo(): Promise<void> {
} }
function goBack(): void { function goBack(): void {
router.push('/directory') // Retour sur l'onglet Prospects de la liste (via history.state, hors URL).
router.push({ path: '/directory', state: { tab: 'prospects' } })
} }
onMounted(async () => { onMounted(async () => {
+35
View File
@@ -0,0 +1,35 @@
/**
* Onglet actif transmis d'une page à l'autre via l'état d'historique
* (`history.state`), SANS le mettre dans l'URL. Sert à préserver l'onglet courant
* du Répertoire (Clients / Prospects / Prestataires) lors de l'aller-retour
* liste ↔ fiche, dans les deux sens (flèche de l'app ET flèche du navigateur).
*
* On reste fidèle à la règle « état d'UI local, pas dans l'URL » : l'onglet
* voyage dans l'entrée d'historique de la navigation, l'URL ne change pas.
*/
/**
* Lit la clé d'onglet posée dans `history.state.tab` si elle fait partie des
* onglets valides. Retourne `null` sinon : navigation directe / deep link,
* rechargement de page, ou onglet inexistant.
*/
export function readHistoryTab(validKeys: string[]): string | null {
if (typeof window === 'undefined') {
return null
}
const tab = (window.history.state as Record<string, unknown> | null)?.tab
return typeof tab === 'string' && validKeys.includes(tab) ? tab : null
}
/**
* Estampille l'entrée d'historique COURANTE avec l'onglet actif, sans créer de
* nouvelle entrée ni changer l'URL. À appeler juste avant de naviguer vers une
* fiche : au retour via la flèche du navigateur (popstate), cette entrée
* « liste » est restaurée avec son onglet.
*/
export function stampHistoryTab(tab: string): void {
if (typeof window === 'undefined') {
return
}
window.history.replaceState({ ...window.history.state, tab }, '')
}