ee3bbea649
Auto Tag Develop / tag (push) Successful in 7s
## Objectif Afficher les violations de validation 422 du back **sous chaque champ** (prop `:error` des `Malio*`) au lieu d'un toast global, et poser **une convention reutilisable par tous les forms**. ## Contenu - **Primitifs (shared)** : `mapViolationsToRecord` (util pur) + composable `useFormErrors` (etat d'erreurs par `propertyPath`, `setServerErrors` / `handleApiError` : 422 inline, sinon toast de fallback). - **Formulaire Client** (`new.vue` + `[id]/edit.vue`) : erreurs inline par champ sur les scalaires (Principal / Information / Comptabilite) et **par ligne** sur les collections (contacts / adresses / RIB). - **Blocs** `ClientContactBlock` / `ClientAddressBlock` : nouvelle prop `errors`. - **Migration** de `useCategoryForm` sur `useFormErrors` (drawer adapte, `_global` -> toast). - **Convention** documentee dans `.claude/rules/frontend.md` + spec de design. ## Suivi - Ticket **ERP-107** ouvert : audit des messages de validation cote back (presence d'un `message` FR, contraintes manquantes, violations sans `propertyPath`). ## Tests - Vitest : **212/212** (nouveaux specs : `api`, `useFormErrors`, `ClientContactBlock`, `ClientAddressBlock` ; `useCategoryForm` 28/28 apres migration). - eslint clean, `nuxi typecheck` 0 erreur. - Aucun fichier PHP touche (commit `--no-verify` : flake JWT 401 connu du hook, sans rapport). Reviewed-on: #58 Reviewed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
56 lines
2.1 KiB
TypeScript
56 lines
2.1 KiB
TypeScript
/**
|
|
* Composable d'erreurs partage des ecrans client (creation + edition, M1
|
|
* Commercial). Factorise le cablage identique entre `clients/new.vue` et
|
|
* `clients/[id]/edit.vue` (suggestion de revue ERP-101) :
|
|
* - un `useFormErrors` par groupe scalaire (Principal / Information /
|
|
* Comptabilite) : violations 422 affichees inline sous chaque champ ;
|
|
* - un tableau d'erreurs PAR LIGNE pour chaque collection (contacts /
|
|
* adresses / RIB), aligne sur l'index du `v-for`.
|
|
*
|
|
* `mapRowError` ne toaste PAS lui-meme : il retourne un booleen (true = mappe
|
|
* inline). Chaque page conserve ainsi son propre fallback dans le `catch`
|
|
* (toast generique en creation, `showError` en edition) sans imposer un
|
|
* comportement commun.
|
|
*/
|
|
import { ref, type Ref } from 'vue'
|
|
import { mapViolationsToRecord } from '~/shared/utils/api'
|
|
|
|
export function useClientFormErrors() {
|
|
const mainErrors = useFormErrors()
|
|
const informationErrors = useFormErrors()
|
|
const accountingErrors = useFormErrors()
|
|
const contactErrors = ref<Record<string, string>[]>([])
|
|
const addressErrors = ref<Record<string, string>[]>([])
|
|
const ribErrors = ref<Record<string, string>[]>([])
|
|
|
|
/**
|
|
* Mappe l'erreur d'une ligne de collection sur le tableau cible (par index).
|
|
* 422 avec violations exploitables → erreurs inline sous les champs de la
|
|
* ligne + retourne true. Sinon → ne touche pas la cible et retourne false
|
|
* (le caller decide du fallback toast).
|
|
*/
|
|
function mapRowError(
|
|
error: unknown,
|
|
target: Ref<Record<string, string>[]>,
|
|
index: number,
|
|
): boolean {
|
|
const response = (error as { response?: { status?: number, _data?: unknown } })?.response
|
|
const mapped = response?.status === 422 ? mapViolationsToRecord(response._data) : {}
|
|
if (Object.keys(mapped).length > 0) {
|
|
target.value[index] = mapped
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
return {
|
|
mainErrors,
|
|
informationErrors,
|
|
accountingErrors,
|
|
contactErrors,
|
|
addressErrors,
|
|
ribErrors,
|
|
mapRowError,
|
|
}
|
|
}
|