feat(directory) : conserve l'onglet actif au retour liste ↔ fiche (LST-72)
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:
@@ -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 () => {
|
||||||
|
|||||||
@@ -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 }, '')
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user