Lot de correctifs sur l'écran Client (M1), + un retrait de règle métier et une petite fonctionnalité. ## Formulaire client (création / édition) - Boutons « ajouter un bloc » (Adresse, RIB) désactivés tant que le dernier bloc n'est pas valide. - Onglet Information : bouton Valider désactivé si aucun champ rempli (création) ; onglet Contact accessible dès la création (Information facultatif). - Champs « Relation » (Distributeur/Courtier) et « Prestation de triage » masqués par défaut, révélés seulement si une catégorie ordinaire (≠ Distributeur/Courtier) est sélectionnée. - Bloc RIB affiché uniquement si le type de règlement est LCR (création, édition, consultation) ; plus de RIB fantôme soumis. - Alignement du bas du textarea « Description » sur les autres champs. ## Recherche d'adresse (BAN) - Une erreur de l'API ne bloque plus définitivement la recherche : chaque frappe réessaie (le mode dégradé restait verrouillé). - Garde minimum 3 caractères avant l'appel à l'API. ## Répertoire client - Titres de colonne en noir 16px, corps + tags de site en 14px. ## Navigation - L'onglet actif est conservé au passage consultation ↔ édition (via history.state, hors URL). ## Règle métier - Retrait de RG-1.04 : l'onglet Information n'est plus obligatoire pour le rôle Commerciale — facultatif pour tous (back + tests + docs). Tests : suites front (Vitest) et back (PHPUnit) vertes hormis flakes d'infra connus. Reviewed-on: #76 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #76.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest'
|
||||
import { readHistoryTab } from '../historyTab'
|
||||
|
||||
const KEYS = ['information', 'contact', 'address', 'accounting']
|
||||
|
||||
describe('readHistoryTab', () => {
|
||||
afterEach(() => {
|
||||
window.history.replaceState(null, '')
|
||||
})
|
||||
|
||||
it('retourne la cle d\'onglet quand elle est presente et valide', () => {
|
||||
window.history.replaceState({ tab: 'address' }, '')
|
||||
expect(readHistoryTab(KEYS)).toBe('address')
|
||||
})
|
||||
|
||||
it('retourne null quand l\'onglet n\'est pas dans les cles valides (ex: role sans Comptabilite)', () => {
|
||||
window.history.replaceState({ tab: 'accounting' }, '')
|
||||
expect(readHistoryTab(['information', 'contact', 'address'])).toBeNull()
|
||||
})
|
||||
|
||||
it('retourne null sans onglet dans l\'etat d\'historique (navigation directe / refresh)', () => {
|
||||
window.history.replaceState(null, '')
|
||||
expect(readHistoryTab(KEYS)).toBeNull()
|
||||
|
||||
window.history.replaceState({ foo: 'bar' }, '')
|
||||
expect(readHistoryTab(KEYS)).toBeNull()
|
||||
})
|
||||
|
||||
it('retourne null quand la valeur n\'est pas une chaine', () => {
|
||||
window.history.replaceState({ tab: 42 }, '')
|
||||
expect(readHistoryTab(KEYS)).toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Onglet actif transmis d'une page a l'autre via l'etat d'historique
|
||||
* (`history.state`), SANS le mettre dans l'URL. Sert a preserver l'onglet courant
|
||||
* au passage consultation <-> edition d'un client (dans les deux sens).
|
||||
*
|
||||
* On reste donc fidele a la regle « etat d'UI local, pas dans l'URL » : l'onglet
|
||||
* voyage dans l'entree d'historique de la navigation, l'URL ne change pas.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Lit la cle d'onglet posee par la page precedente (`history.state.tab`) si elle
|
||||
* fait partie des onglets valides pour l'utilisateur. Retourne `null` sinon :
|
||||
* navigation directe / deep link, rechargement de page, ou onglet inexistant
|
||||
* pour ce role (ex: Comptabilite sans la permission).
|
||||
*/
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user