feat(directory) : refonte UI du Répertoire (LST-72) (#27)
Auto Tag Develop / tag (push) Successful in 9s

Améliorations frontend de la partie **Répertoire** (Client / Prospect / Prestataire). Onglet **Rapport** retravaillé en fin de parcours ; le reste de la logique métier inchangé.

## Navigation & liste
- Onglet actif conservé au retour liste ↔ fiche (flèche app **et** navigateur) via `history.state` (hors URL) — util `historyTab.ts`
- Colonne « Action » (entête alignée) + feedback hover sur les boutons d'action
- Conversion prospect → client : modal de confirmation
- Boutons « Ajouter » : label court + taille Malio standard ; barres d'outils à hauteur homogène (plus de saut entre onglets)

## Fiches (Info / Contact / Adresse)
- Style **plat** sans box-shadow (comme Starseed)
- Champs email/téléphone : `MalioInputEmail` / `MalioInputPhone`
- Grilles en **4 colonnes** (Info + blocs)
- Boutons « Nouveau contact/adresse » en secondary ; « Enregistrer » en taille Malio ; marge form↔bouton homogène
- Bouton retour **ghost** (`mdi:arrow-left-bold`)
- **Adresse** : flux CP → ville → rue (rue conditionnée au CP+ville, cascade de reset) ; titre du bloc = libellé saisi
- Suppression d'un bloc Contact/Adresse : **modal** de confirmation (centralisée dans `useDirectoryDetail`)
- Modals (suppression, conversion) basées sur `MalioModal` (design Starseed) avec nom en gras

## Onglet Rapport
- Bouton d'ajout en taille Malio (« Ajouter »)
- Suppression compte-rendu : `ConfirmModal` partagée (remplace l'ancienne modal maison)
- Suppression d'un document joint : ajout d'une modal de confirmation
- Upload via `MalioInputUpload` ; bouton supprimer document aligné (`mdi:delete-outline` ghost)

## Divers
- `fix(auth)` : cookie JWT renommé `BEARER_LESSTIME` (collision localhost avec d'autres apps Symfony)
- `fix(infra)` : target makefile `fix-uploads-perm` (volume `uploads_data` root → upload local OK)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #27
This commit was merged in pull request #27.
This commit is contained in:
2026-06-27 13:29:56 +00:00
parent 0ee164c302
commit bbd8a38c95
20 changed files with 590 additions and 361 deletions
@@ -14,6 +14,7 @@ type Owner = { client?: string, prospect?: string, prestataire?: string }
* tel quel par les deux pages.
*/
export function useDirectoryDetail(owner: Owner) {
const { t } = useI18n()
const contactService = useContactService()
const addressService = useAddressService()
@@ -59,6 +60,39 @@ export function useDirectoryDetail(owner: Owner) {
addresses.value.splice(index, 1)
}
// Confirmation de suppression d'un bloc (contact / adresse) : la corbeille du
// bloc ouvre une modal ; la suppression effective n'a lieu qu'à la confirmation.
const removeModalOpen = ref(false)
const pendingRemoval = ref<{ type: 'contact' | 'address', index: number } | null>(null)
const removeModalTitle = computed(() =>
pendingRemoval.value?.type === 'address'
? t('directory.addresses.deleteConfirmTitle')
: t('directory.contacts.deleteConfirmTitle'),
)
const removeModalMessage = computed(() =>
pendingRemoval.value?.type === 'address'
? t('directory.addresses.deleteConfirmMessage')
: t('directory.contacts.deleteConfirmMessage'),
)
function askRemoveContact(index: number): void {
pendingRemoval.value = { type: 'contact', index }
removeModalOpen.value = true
}
function askRemoveAddress(index: number): void {
pendingRemoval.value = { type: 'address', index }
removeModalOpen.value = true
}
async function confirmRemove(): Promise<void> {
const p = pendingRemoval.value
if (!p) return
if (p.type === 'contact') await removeContact(p.index)
else await removeAddress(p.index)
removeModalOpen.value = false
pendingRemoval.value = null
}
// Persistance au clic : met à jour les blocs existants, crée les nouveaux
// blocs renseignés. Les amorces vides (sans contenu) sont ignorées.
async function saveContacts(): Promise<void> {
@@ -117,5 +151,12 @@ export function useDirectoryDetail(owner: Owner) {
removeAddress,
saveAddresses,
load,
// Suppression de bloc avec confirmation (modal partagée contact/adresse).
removeModalOpen,
removeModalTitle,
removeModalMessage,
askRemoveContact,
askRemoveAddress,
confirmRemove,
}
}