Nicolas Cantu 61cec6f430 Sync ia_dev: token resolution via .secrets/<env>/ia_token, doc updates
**Motivations:**
- Align master with current codebase (token from projects/<id>/.secrets/<env>/ia_token)
- Id resolution by mail To or by API token; no slug

**Root causes:**
- Token moved from conf.json to .secrets/<env>/ia_token; env from directory name

**Correctifs:**
- Server and scripts resolve project+env by scanning all projects and envs

**Evolutions:**
- tickets-fetch-inbox routes by To address; notary-ai agents and API doc updated

**Pages affectées:**
- ai_working_help/server.js, docs, project_config.py, lib/project_config.sh
- projects/README.md, lecoffreio/docs/API.md, gitea-issues/tickets-fetch-inbox.py
2026-03-16 15:00:23 +01:00

1377 lines
82 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Documentation Frontend - LeCoffre.io
**Dernière mise à jour** : 2026-02-25
Ce document regroupe toute la documentation frontend : routes, pages, UI/UX, et gestion des collaborateurs.
---
## 📋 Table des Matières
1. [Routes et Navigation](#1-routes-et-navigation)
2. [Pages et Composants](#2-pages-et-composants)
3. [Corrections UI/UX](#3-corrections-uiux)
4. [Agrégation des Collaborateurs](#4-agrégation-des-collaborateurs)
5. [Build et Tests](#5-build-et-tests)
6. [Authentification IdNot et Logging](#6-authentification-idnot-et-logging)
7. [Interface Espace Notaire - Onglets et Tableaux](#7-interface-espace-notaire---onglets-et-tableaux)
8. [Consolidation évolutions et correctifs](#8-consolidation-évolutions-et-correctifs)
---
## 1. Routes et Navigation
### Routes de Dossiers
#### Routes Actives
- `/folders` - Liste des dossiers actifs
- `/folders/[folderUid]` - Détail d'un dossier actif
- `/folders/[folderUid]/add/clients` - Ajouter un client
- `/folders/[folderUid]/add/third-party` - Ajouter un tiers
- `/folders/[folderUid]/edit/informations` - Modifier les informations
- `/folders/[folderUid]/edit/clients/[customerUid]` - Modifier un client
- `/folders/[folderUid]/edit/collaborators` - Modifier les collaborateurs
- `/folders/[folderUid]/documents-reminder-history` - Historique des rappels
- `/folders/[folderUid]/send-documents` - Envoyer des documents
- `/folders/[folderUid]/documents/[documentUid]` - Détail d'un document
#### Routes Archivées
- `/folders/archived` - Liste des dossiers archivés
- `/folders/archived/[folderUid]` - Détail d'un dossier archivé
#### Routes Supprimées
- `/folders/deleted` - Liste des dossiers supprimés (soft delete)
### Détection des Pages de Détail
Le composant `FolderInformation` détecte automatiquement le type de route via la prop `isArchived`.
**Regex de détection** :
```typescript
/\/folders\/(archived\/)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i
```
**Format accepté** :
- `/folders/[uuid]` - Dossier actif
- `/folders/archived/[uuid]` - Dossier archivé
**Format rejeté** :
- `/folders` - Liste des dossiers
- `/folders/archived` - Liste des dossiers archivés
**Fichiers concernés** :
- `lecoffre-front-main/src/front/Components/Layouts/Folder/FolderInformation/index.tsx`
- `lecoffre-front-main/src/pages/folders/[folderUid]/index.tsx`
- `lecoffre-front-main/src/pages/folders/archived/[folderUid]/index.tsx`
---
## 2. Pages et Composants
### Pages Identifiées pour Migration Collaborateurs
#### UpdateFolderCollaborators ⚠️ PRIORITÉ HAUTE
**Fichier** : `lecoffre-front-main/src/front/Components/Layouts/Folder/UpdateFolderCollaborators/index.tsx`
**Action requise** : Utiliser l'endpoint `/api/v1/notary/users/aggregated` pour afficher tous les collaborateurs (avec et sans compte).
**Page concernée** : `/folders/[folderUid]/collaborators`
#### SubscriptionManageCollaborators ⚠️ PRIORITÉ HAUTE
**Fichier** : `lecoffre-front-main/src/front/Components/Layouts/Subscription/Manage/SubscriptionManageCollaborators/index.tsx`
**Action requise** : Utiliser l'endpoint agrégé et filtrer pour ne garder que ceux avec compte (car seuls les utilisateurs avec compte peuvent avoir un siège).
**Page concernée** : `/subscription/manage-collaborators`
#### DefaultCollaboratorDashboard ⚠️ PRIORITÉ MOYENNE
**Fichier** : `lecoffre-front-main/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/index.tsx`
**Action requise** : Utiliser l'endpoint agrégé et filtrer pour ne garder que ceux avec compte, ou afficher deux sections : "Avec compte" et "À inviter".
**Page concernée** : `/collaborators` (dashboard)
#### CreateFolder
**Fichier** : `lecoffre-front-main/src/front/Components/Layouts/Folder/CreateFolder/index.tsx`
**État** : Depuis novembre 2025, le formulaire de création ne gère plus l'ajout de collaborateurs, de confrères ou de tiers. Les stakeholders initiaux se limitent automatiquement au créateur.
---
## 3. Corrections UI/UX
### Boutons de Civilité Invisibles
**Date** : 2025-01-27
**Composant** : `AddClientToFolder`
**Page** : `/folders/[folderUid]/add/clients`
#### Problème
Les 3 boutons de sélection de civilité (Monsieur, Madame, Autre) apparaissaient vides/invisibles dans le formulaire "Créer un nouveau client".
#### Root Cause
Le CSS de la classe `.civility-option` ne définissait pas de couleur de texte par défaut. Seule la classe `.civility-option-active` (bouton sélectionné) avait une couleur définie.
#### Solution
Ajout d'une couleur de texte par défaut (`var(--color-neutral-700)`) et d'un fond blanc pour garantir la visibilité du texte.
**Fichiers modifiés** :
- `lecoffre-front-main/src/front/Components/Layouts/Folder/AddClientToFolder/classes.module.scss`
### Migration Sass : @import vers @use
**Date** : 2025-01-30
**Version** : 2.0.1+
#### Objectif
Éliminer les warnings de dépréciation Sass concernant l'utilisation de `@import` qui seront supprimés dans Dart Sass 3.0.0. Migrer tous les fichiers SCSS vers le système moderne `@use`/`@forward` de Sass.
#### Modifications
**Changement de syntaxe :**
- **Avant** : `@import "@Themes/constants.scss";`
- **Après** : `@use "@Themes/constants.scss" as *;`
**Fichiers migrés** : 138 fichiers SCSS dans `lecoffre-front-main/src/`
**Compatibilité** : L'utilisation de `as *` permet de conserver l'accès global aux variables Sass (`$screen-m`, `$screen-s`, `$color-*`) et aux variables CSS (`var(--...)`).
**Documentation complète** : Voir conventions Sass du projet (ARCHITECTURE, OPTIMIZATION_AXES).
### Bouton supprimer, parties rattachées, page add/clients (2026-01-28)
**Pages** : `/folders/[folderUid]/add/clients`, fiche dossier.
**Problèmes** : (1) Clic sur supprimer (X) à côté d'un client ne retire pas l'item ; (2) après validation, aucune partie sur la fiche dossier ; (3) après création dossier, add/clients reste sur « Dossier chargé mais données invalides » (GET folder sans `uid`).
**Root causes** : Clés React en index (`GenericExistingItemsList`) → réutilisation de nœuds ; `preventDefault`/`stopPropagation` sur IconButton ; options avec `id` vide exclus du payload ; `instanceToPlain` omet `uid` sur GET `/notary/folders/:uid`.
**Correctifs** : `getExistingItemKey` / `getPendingItemKey` stables (ex. `id`, `email`) ; `onClick` sans `preventDefault`/`stopPropagation` ; filtrage des clients `uid` non vide et collecte UIDs stricte dans `finalizePayloadHelpers` ; `OfficeFoldersGetOneByUidHydrationHelper` : forcer `plainFolder.uid = folderUid` après `instanceToPlain`. Textes retirés : « Rien n'est envoyé… », « Associez un ou plusieurs clients… ».
**Fichiers** : `AddClientToFolder` (sections, `GenericExistingItemsList`, `CustomersList`), `useCustomersManager`, `finalizePayloadHelpers`, `OfficeFoldersGetOneByUidHydrationHelper`.
### Invitation confrères validation avant envoi email (2026-03-12)
**Composant** : `AddClientToFolder` (onglet « Confrères »)
**Page** : `/folders/[folderUid]/add/clients`
**Problème** : Lors de lajout dun confrère par email, le partage et lemail dinvitation étaient créés immédiatement au clic sur « Ajouter ». Si lutilisateur cliquait ensuite « Annuler », le confrère restait invité et avait déjà reçu lemail.
**Root cause** : Le flux confrères appelait `shareFolder` directement au clic « Ajouter », contrairement aux clients et tiers qui sont mis en attente puis persistés uniquement au clic « Valider ».
**Correctifs** : Alignement sur le flux clients/tiers. Les confrères ajoutés sont stockés dans `pendingConfrereShares` ; lAPI `shareFolder` et lenvoi demail sont exécutés dans `addPendingConfrereShares` lors du `finalizeChanges`. Les confrères en attente sont affichés avec « Sera invité lors de la validation » et peuvent être retirés via `removePendingConfrere`.
**Fichiers** : `useConfreresManager`, `finalizeOperationsHelpers`, `useFinalizeHandler`, `ExistingConfreresList`, `ConfreresSection`, `SearchConfrereSection`, `StakeholdersContent`, `types`.
### Personne en charge du dossier ContactBox et écran collaborateurs (2026-03-12)
**Composant** : `ClientDashboard/ContactBox`, page « Modifier les collaborateurs »
**Pages** : Espace client/tiers (contact de loffice), `/folders/[folderUid]/edit/collaborators`
**Problème** : Dans lespace client/tiers, les contacts de loffice affichés (email, téléphone) ne correspondaient pas à la personne en charge du dossier : le composant choisissait le contact de façon arbitraire parmi les stakeholders (priorité au rôle « Notaire », sinon premier de la liste). Aucune notion de « personne en charge » ou « interlocuteur principal » nexistait dans le modèle.
**Root cause** : Pas de champ dédié dans le modèle de données ; ContactBox utilisait uniquement `stakeholders` (ordre non garanti).
**Évolution** : Ajout de `main_contact_uid` sur le dossier (optionnel, FK vers `users`). La personne en charge est obligatoirement parmi les collaborateurs du dossier (stakeholders). Par défaut = créateur du dossier. Elle est choisie/modifiée dans lécran « Modifier les collaborateurs » via un champ « Personne en charge » (liste = collaborateurs effectifs : tout loffice ou sélection). ContactBox affiche désormais : `main_contact` puis `created_by` puis notaire puis premier stakeholder.
**Fichiers** : Prisma `office_folders.main_contact_uid` + relation `main_contact` ; ressources Notary `OfficeFolder` ; backend DTO, `FolderHandler` (validation), `OfficeFoldersUpdateBuilder`, `OfficeFoldersRepository` (create/update), `OfficeFoldersGetOneByUidHydrationHelper` ; frontend `folderQueryBuilders`, `useFolderAndCustomer`, `ClientDashboard/ContactBox`, `UpdateFolderCollaborators` (loader, controller, vue avec SelectField), `commonUiI18nPart1` (mainContactLabel). Migration : `20260312120000_add_main_contact_uid_to_office_folders`.
### Autocomplétion Confrères clic suggestion non sélectionné (2026-02-22)
**Composant** : `AddClientToFolder` (onglet « Confrères »)
**Page** : `/folders/[folderUid]/add/clients`
**Problème** : Dans « Notaire (recherche annuaire) », cliquer une suggestion ferme la liste sans sélectionner le notaire.
**Root cause** : La fermeture des suggestions était pilotée par `onBlur` sur le wrapper : le `blur` se déclenchait aussi lors dun passage de focus interne (champ → suggestion), et la fermeture temporisée rendait lévénement de sélection non fiable (clic) et cassait le parcours clavier.
**Correctifs** : `SearchConfrereSection` ferme les suggestions uniquement lorsque le focus sort réellement du wrapper (`relatedTarget` non contenu), et ferme aussi laffichage des résultats côté hook via `setShowSuggestionsFromSearch(false)`.
**Fichiers** :
- `lecoffre-front-main/src/front/Components/Layouts/Folder/AddClientToFolder/sections/ConfreresSection/SearchConfrereSection.tsx`
- Correctif autocomplétion Confrères : voir [README.md](./README.md#consolidation-operationnelle-ex-operationsmd) (clic suggestion non sélectionné).
### Création dossier membres rattachés n'apparaissent pas (2026-01-28)
**Problème** : Après création d'un dossier avec collaborateurs, la section « Gestionnaire du projet » est vide sur add/clients et fiche dossier.
**Root cause** : Les requêtes GET folder ne demandaient ni `stakeholders` ni `created_by`.
**Correctifs** : Dans `buildFolderQueryParams` (FolderInformation / `useFolderDataFetch`) et dans le loader add/clients (`useFolderDataInitialization`), ajouter `created_by` et `stakeholders` avec includes `contact`, `office_role`, `seats` / `subscription` / `office`.
### Création dossier reste sur « Chargement du dossier… » (2026-01-28)
**Problème** : Après création et redirection vers `/folders/:uid/add/clients`, la page reste bloquée sur chargement.
**Causes** : (1) GET dossier sans timeout ; (2) `folderUid` absent au premier rendu (`router.query` pas encore à jour après `router.push`).
**Correctifs** : Timeout 30 s sur le chargement (Promise.race) ; si timeout → toast, redirection `/folders`. Fallback `folderUid` : extraction par regex sur `router.asPath` (`/\/folders\/([^/]+)\/add\/clients/`) quand `query["folderUid"]` vide. Nettoyage des logs debug.
**Fichiers** : `useFolderDataInitialization`, `useManageFolderStakeholdersController`, `createFolderSubmitHelpers`.
### Dossier membres absents sur la page détail (2026-01-28)
**Problème** : Dossier créé avec client/tiers/notaire invité, mais page détail affiche « Ajouter des clients » (NoClientView) au lieu des onglets participants.
**Root cause** : `instanceToPlain` peut omettre `customers` et `folder_sharings` ; `doesFolderHaveClient` reste faux.
**Correctifs** : Dans `OfficeFoldersGetOneByUidHydrationHelper`, après `instanceToPlain`, forcer `customers` et `folder_sharings` dans le plain lorsqu'ils sont présents sur l'entité brute mais absents ou vides dans le plain (même logique que `uid`).
**Correctif frontend (2026-03-09)** : voir `docs/fixKnowledge/2026-03-09-folder-detail-participants-hidden-without-customers.md`.
### Création dossier validation failure (2026-01-27 / 2026-01-28)
**Problème** : « Dossier chargé mais données invalides », `uid` manquant en POST ou GET.
**Root causes** : POST retournait une instance de classe au lieu d'un plain ; `instanceToPlain` pouvait omettre `uid`. GET idem.
**Correctifs backend** : `OfficeFoldersCreationHelper` : `instanceToPlain` puis **toujours** `plainFolder.uid = officeFolderEntity.uid`. `OfficeFoldersGetOneByUidHydrationHelper` : forcer `uid` (et `customers` / `folder_sharings` / `notes` / `folder_number` si omis). Stripe 404 : `StripeController` + `StripeService.isStripeNotFoundError()` pour ne pas traiter 404 comme erreur utilisateur.
**Correctifs frontend** : Logs debug dans `useFolderDataInitialization` et `createFolderSubmitHelpers` ; délai 2000 ms avant redirection. Vérifier en déploiement que le correctif `plainFolder.uid = officeFolderEntity.uid` est bien présent dans le build.
### Notes membres (notaires / collaborateurs) non affichées dans les onglets (2026-01-29)
**Problème** : Les notes n'apparaissent pas dans les onglets clients / notaires invités / tiers, mais sont visibles dans le formulaire de modification.
**Root cause** : `instanceToPlain` peut omettre le tableau `notes` ; seul le forçage de `customers` et `folder_sharings` existait.
**Correctifs** : Dans `OfficeFoldersGetOneByUidHydrationHelper`, forcer `plainFolder.notes = rawNotes` lorsque l'entité brute a des notes mais le plain les omet. Étendre `FilteredEntityForPostProcess` avec `notes`. Log « notes forcés (instanceToPlain les avait omis) ».
### Supprimer un dossier modale ne s'affiche pas / champ confirmation (2026-01-28)
**Problème** : Clic « Supprimer le dossier » (menu ⋮) : modale semble ne pas s'ouvrir ou menu se ré-affiche par-dessus. Champ de confirmation : label « Confirmation » alors qu'il faut saisir le numéro de dossier → bouton grisé. Si `folder_number` absent, rien en gras.
**Root causes** : (1) Clic sur l'item déclenche `onClose` puis `onClick` ; l'événement remonte au root du Menu → `toggle` ré-ouvre le menu. (2) Items sans `link` avaient `key={undefined}` → clés dupliquées. (3) Label et `expectedValue` du champ de confirmation peu clairs. (4) `folder_number` parfois omis par `instanceToPlain`.
**Correctifs** : `MenuItem` : après `onClose` / `onClick` / navigation, appeler `e.stopPropagation()` si le clic est traité. Menu : clé stable `item.link ?? \`${item.text}-${index}\``. DeleteModal : label « Numéro du dossier (répétez cidessus) », `expectedValue` = numéro, `errorMessage` explicite ; si numéro vide, pas de `requireConfirmation`. ConfirmModal : si `expectedValue` vide, afficher « La valeur à saisir n'est pas disponible. Actualisez la page puis réessayez. » et garder le bouton désactivé. Backend : forcer `folder_number` dans `OfficeFoldersGetOneByUidHydrationHelper` quand omis.
**Fichiers** : `MenuItem`, `Menu`, `DeleteModal`, `ConfirmModal`, `OfficeFoldersGetOneByUidHydrationHelper`.
### Stripe 404 bannière abonnement (2026-01-29)
**Problème** : `GET /api/v1/admin/stripe/:id` en 404 (abonnement absent chez Stripe) → Toast « L'élément demandé n'existe pas », warn « Unable to load subscription banner » à chaque chargement.
**Root cause** : Aucune distinction 404 (ressource absente, cas acceptable) vs erreur technique ; `onError` systématique.
**Correctifs** : `StripeFactory.getStripeSubscriptionByUid` : en catch, si `http_status === 404`, ne pas appeler `onError`, puis rejeter. `Header` / `useSubscriptionLoader` : en catch, si 404, retourner sans logger.
**Fichiers** : `StripeFactory`, `Header/index.tsx`.
### Demander les documents configuration du type de document non chargée
**Page** : « Demander des documents ».
**Problème** : Aucun type de document à sélectionner ; configuration deed / deed_type non chargée ou non exploitée.
**Root causes** : Backend : `instanceToPlain` peut omettre `deed` (et `deed.document_types`) ; aucun forçage de `deed`. Front : utilisation uniquement de `deed.document_types`, sans `deed_type.document_types` ni fallback lorsque toutes les sources sont vides.
**Correctifs** : Backend (`OfficeFoldersGetOneByUidHydrationHelper`) : forcer `deed` (et `document_types`) dans la réponse lorsquils sont présents sur lentité brute mais omis par `instanceToPlain`. Front (`useAskDocumentsFolderData`) : inclure `deed_type` avec `document_types` dans le `q` du fetch ; priorité `deed_type.document_types` → `deed.document_types` → types déduits des documents existants ; si tout vide, fallback `DocumentTypes.getInstance().get({})` ; log lorsque le fallback est utilisé.
**Fichiers** : `OfficeFoldersGetOneByUidHydrationHelper`, `useAskDocumentsFolderData`.
---
## 4. Agrégation des Collaborateurs
### Vue d'Ensemble
La fonctionnalité d'agrégation des collaborateurs retourne les **comptes utilisateurs existants** d'un office (créés lors de la première connexion OAuth IdNot).
### API Endpoint
#### `GET /api/v1/notary/users/aggregated`
**Authentification** : Requise (JWT)
**Permissions** : `authHandler`, `ruleHandler`
**Description** : Retourne les collaborateurs de l'office disposant d'un compte utilisateur.
**Réponse** :
```json
[
{
"uid": "uuid-user-1",
"idNot": "123456",
"contact": {
"uid": "uuid-contact-1",
"email": "notaire@example.com",
"first_name": "Jean",
"last_name": "Dupont",
"phone": "+33123456789",
"civility": "M."
},
"_metadata": {
"source": "users",
"has_user_account": true
}
}
]
```
---
## 11. Gestion des Documents
### Visibilité et Affichage
#### Documents Déposés (DEPOSITED)
- **Pour le déposant** (Client, Tiers, Notaire Invité) :
- Le fichier **n'est pas affiché** (pas d'icône "œil", pas de téléchargement).
- Seule la ligne avec la date de dépôt est visible.
- Le module de dépôt n'est plus éditable pour empêcher la modification.
- Accès direct URL : Message "En attente de validation..." sans contenu.
- **Pour le notaire en charge** :
- Accès complet (visualisation, validation, refus).
#### Dépôt côté déposant (Client / Tiers / Notaire invité)
- La section **Documents à envoyer** utilise le même module d'ajout que **Documents supplémentaires (facultatif)** : ouverture via **Ajouter un document**, gestion de la sélection locale (ajout/retrait), puis envoi explicite via **Déposer le document**.
- Le dépôt n'est plus déclenché au glisser-déposer : le glisser-déposer alimente uniquement la sélection locale dans la modale.
- Après validation du dépôt, le rafraîchissement garde le comportement de ligne existant dans le tableau (mise à jour de statut/date selon le document).
- Les libellés de dépôt sont centralisés par contexte (`generic`, `modal`, `otherDocuments`, `rib`) dans `DesignSystem/helpers/fileUploadUiI18n.ts`, et les CTA communs de modales (`Annuler`, `Confirmer`) sont centralisés dans `DesignSystem/helpers/commonUiI18n.ts`.
- Les libellés d'actions métier de modales/layouts (`Valider`, `Supprimer`, `Enregistrer`, `Créer`, `Ajouter`, `Continuer`, `Quitter`) sont regroupés dans les namespaces dédiés de `DesignSystem/helpers/commonUiI18n.ts` et réutilisés dans les modales existantes.
- Les libellés métier composés sont regroupés par domaine dans `DesignSystem/helpers/commonUiI18n.ts` (`folder`, `subscription`, `member`, `role`) pour éviter les chaînes actionnelles locales dans les vues et menus.
- Les CTA et labels de tests SuperAdmin sont aussi centralisés dans `commonUiI18n.ts` via les namespaces `health` et `adminTools`, y compris les libellés de titres secondaires d'actions (boutons détails, liens utilitaires, titres de consultation).
- Les textes descriptifs non actionnels sont centralisés dans les namespaces `healthMessages`, `folderMessages`, `demoMessages`, `subscriptionMessages`, `userMessages`, `usersMessages` et `documentMessages` de `commonUiI18n.ts` (cartes de test SuperAdmin, modales d'archive/suppression dossier, sections de démonstration du DesignSystem, écrans abonnement, écrans utilisateurs et viewer documentaire).
- Les placeholders et libellés de formulaires métier longs sont centralisés dans `formMessages` (`commonUiI18n.ts`) pour les flux de préparation de dossier (tiers, confrères) et d'envoi documentaire.
- Les messages dynamiques sont composés par des helpers dédiés dans `DesignSystem/helpers/commonUiMessageBuilders.ts` pour éviter la concaténation dans les composants (`votes` SuperAdmin, message de dépôt en attente dans le viewer).
- Les écrans dossier hors scope upload initial (`AddThirdParty`, `AskDocuments`, `Folder` landing, sections NoClient, modales de suppression client/document) sont alignés sur `folderMessages`/`formMessages` et réutilisent les helpers de composition pour les messages conditionnels de permissions/chargement.
- Les messages "chargement dossier / droits insuffisants" passent par un helper dédié à objet de configuration (`buildFolderPermissionOrLoadingMessage`) et les modales de suppression mutualisent leurs feedbacks succès/erreur via des helpers dédiés.
- Les flux de suppression utilisent des payload helpers dédiés par domaine : `buildDocumentDeleteModalPayload` (documents), `buildCustomerDeleteModalPayload` (client de dossier), `buildFolderDeleteModalPayload` (suppression dossier soft/hard), `buildThirdPartyDeleteModalPayload` (tiers du dossier), `buildRibDeleteModalPayload` (RIB) et `buildDeedTypeDeleteModalPayload` (type d'acte), avec centralisation de `title/message/confirmLabel` et des messages d'erreur.
- La confirmation de suppression avec saisie du numéro de dossier est factorisée via `buildFolderDeleteRequireConfirmationPayload` pour éviter la duplication `label/placeholder/errorMessage` dans les modales.
- Les anciens `alert()` des flux de téléchargement documents/certificats et création de dossier (helpers `FolderInformation`/`InvitedView`/`CreateFolder`) sont migrés vers `ToasterService` avec messages centralisés dans `commonUiI18n.ts` et composition d'erreur agrégée via `buildAggregatedCertificateErrorMessage`.
- Le flux de désarchivage dossier n'utilise plus `confirm()`: il passe désormais par une `ConfirmModal` dédiée pilotée via `useFolderModals` (`unarchiveModal`) et payload `buildUnarchiveFolderConfirmPayload`.
- Les erreurs de téléchargement ZIP/certificat sont unifiées via le helper global `showDownloadErrorToast` (`Utils/documentDownloadHelpers.ts`) et réutilisées dans `Folder` et `ClientDashboard`.
- Les flux `SuperAdmin/SiteTexts` (create/update/publish/archive/load) n'utilisent plus `alert()/confirm()` : feedback via `ToasterService` + modale de confirmation d'archivage.
- Les toasts de succès de téléchargement sont aussi centralisés via `showDownloadSuccessToast` dans `Utils/documentDownloadHelpers.ts` et réutilisés par les flux `Folder`, `ClientDashboard`, `singleFileDownloadHelper` et `DocumentDownloadService`.
- Les toasts de succès métier hors téléchargement (create/update/publish/archive) sont harmonisés via `showBusinessSuccessToast` (`Utils/businessOperationToastHelpers.ts`) avec payload centralisé (`buildBusinessSuccessToastPayload`).
- Les erreurs métier hors téléchargement sont harmonisées via `showBusinessErrorToast` (`Utils/businessOperationToastHelpers.ts`) avec payload builders par domaine (`collaboratorMessages`, `clientDashboardMessages`, `folderMessages`) pour éviter les descriptions codées en dur.
- Les warnings métier hors téléchargement sont harmonisés via `showBusinessWarningToast` (`Utils/businessOperationToastHelpers.ts`) avec payload builders de domaine (`subscriptionMessages`, `folderMessages`) pour homogénéiser les flux dinformation/validation.
- Les flux `Folder/AskDocuments`, `Folder/SendDocuments` et `Folder/AddClientToFolder` utilisent désormais les mêmes helpers `showBusinessErrorToast`/`showBusinessWarningToast` et des builders dédiés `commonUiMessageBuilders.ts` pour supprimer les `ToasterService.getInstance().warn/error` métier locaux.
- Les builders `folderMessages` sont regroupés par sous-domaines (`parameterDocuments`, `askDocuments`, `sendDocuments`, `stakeholders`) via `DesignSystem/helpers/folderToastMessageBuilders.ts` et exposés par `commonUiMessageBuilders.ts`.
- Les builders non-folder sont aussi extraits par domaine pour limiter la croissance de `commonUiMessageBuilders.ts` :
- `DesignSystem/helpers/clientDashboardMessageBuilders.ts`
- `DesignSystem/helpers/clientDashboardToastMessageBuilders.ts`
- `DesignSystem/helpers/collaboratorToastMessageBuilders.ts`
- `DesignSystem/helpers/createCustomerNoteToastMessageBuilders.ts`
- `DesignSystem/helpers/siteTextsMessageBuilders.ts`
- `DesignSystem/helpers/siteTextsToastMessageBuilders.ts`
- `DesignSystem/helpers/subscriptionToastMessageBuilders.ts`
- `DesignSystem/helpers/deedTypesToastMessageBuilders.ts`
- `DesignSystem/helpers/folderInformationToastMessageBuilders.ts`
- `DesignSystem/helpers/folderViewDocumentsToastMessageBuilders.ts`
- `DesignSystem/helpers/toastPayloadBuilderHelpers.ts` : helper générique partagé pour construire les payloads error/warning/success (évite la répétition dans chaque `*ToastMessageBuilders`).
- `DesignSystem/helpers/toastMessageBuilders/index.ts` centralise le pattern de re-export des builders `*ToastMessageBuilders.ts`.
- `commonUiMessageBuilders.ts` conserve un re-export de compatibilité.
- Les écrans `ClientDashboard/ViewDocumentSent`, `ClientDashboard/ViewDocumentsNotary` et `Folder/ViewDocuments` nutilisent plus de `ToasterService.getInstance().error` inline pour les erreurs métier de chargement/validation.
- Les layouts métier ciblés `Folder`, `ClientDashboard` et `DeedTypes` nutilisent plus de `ToasterService.getInstance().warn/error` direct : les flux sont alignés sur `showBusinessErrorToast` / `showBusinessWarningToast` avec payloads centralisés.
- Les succès métier peuvent aussi être injectés via payload (`title` + `description`) dans `showBusinessSuccessToast`, ce qui permet daligner `Folder/ViewDocuments` et `DeedTypes` sans libellés inline dans les hooks.
- Les flux `subscription-plans` n'utilisent plus `alert()/confirm()` : confirmations via `ConfirmModal` + payload helpers (`buildSubscriptionPlanSetDefaultConfirmPayload`, `buildSubscriptionPlanDeleteConfirmPayload`) et feedback centralisé.
- Les derniers usages résiduels de `alert()/confirm()` côté front ont été retirés, y compris dans la section de démonstration `ButtonIconMenuSection` et le fallback technique `ToasterHelper`.
#### Documents Envoyés (SENT)
- **Tableau "Documents envoyés"** : La colonne "Type de document" est renommée **"Nom du document"**.
- **Notaire Invité** :
- Les documents de type "Document notaire" (envoyés par le notaire gestionnaire) sont **exclus** de la section "Documents à envoyer".
- Ils apparaissent uniquement dans "Documents reçus".
- L'encart de notification ("X documents reçus") est aligné avec le nombre réel de documents affichés (excluant les doublons techniques).
#### Visualisation (Viewer)
- **Sélection du fichier** : En cas de multiples fichiers (ex: refus puis re-dépôt), le viewer affiche par défaut le **plus récent** (tri par `created_at` desc), et non le premier de la liste (souvent l'ancien refusé).
- **Batch** : L'affichage d'un document issu d'un batch (ex: pièce d'identité) ne montre que les fichiers de **ce document spécifique** (`docUid`), sans fusionner avec les autres documents du même batch.
### Téléchargement
#### Logique ZIP vs Fichier Unique
- **Alignement** : La logique de téléchargement utilise le même dédoublonnage que l'affichage (`getUniqueFiles` dans `fileHelpers.ts`).
- **Comportement** :
- Si **1 seul fichier unique** (après dédoublonnage par nom) : Téléchargement direct du fichier.
- Si **> 1 fichiers uniques** : Téléchargement d'un ZIP.
- Évite de créer un ZIP inutile pour un document qui n'a qu'une seule version pertinente visible.
### Refactoring & Helpers
- **`fileHelpers.ts`** : Centralise la logique de dédoublonnage (`getUniqueFiles`, `getFileDisplayName`) partagée entre l'affichage (`tableColumnHelpers`) et le téléchargement (`documentDownloadHelpers`).
- **`documentFilterHelpers.ts`** : Centralise les statuts (`DOCUMENTS_TO_SEND_STATUSES`, etc.) pour garantir la cohérence entre les vues Client, Tiers et Invité.
---
## 5. Build et Tests
- `npm run build` exécute désormais `npm run typecheck` puis `node ./scripts/run-next-build.cjs`. Ce script Node applique les variables d'environnement requises (`TURBOPACK_ROOT`, `NEXT_TELEMETRY_DISABLED`) avant d'invoquer `next build` via `next/dist/bin/next`. Cette approche garantit un comportement identique sous Windows (où les affectations `VAR=value` n'étaient pas interprétées par `cmd.exe`) et sous Linux/macOS.
- Le fichier `lecoffre-front-main/scripts/run-next-build.cjs` est responsable du lancement de `next build`. Il doit être conservé à jour si des arguments supplémentaires sont nécessaires.
### Convention de typage JSX (React 19)
- Les composants fonctionnels utilisent `React.JSX.Element` (ou `React.JSX.Element | null` pour un rendu conditionnel).
- Les composants de classe utilisent `render(): React.ReactNode`.
- Les props de contenu (`children`, `title`, `text`, `icon`, `footer`, etc.) utilisent `React.ReactNode`.
- Le shim global `declare namespace JSX` n'est plus utilisé dans `custom.d.ts`.
- Les usages `JSX.Element` sont interdits dans le frontend pour éviter les incompatibilités de typage entre runtime JSX et React 19.
### Stratégie couche API (useApiClient vs BaseApiService)
- **useApiClient** (hook React) : cible pour tout appel API depuis un composant ou un hook. Gère le token, les erreurs et le base URL. Privilégier pour les nouveaux usages dans lUI.
- **BaseApiService / getInstance()** (services sous `LeCoffreApi/`) : utilisé par les factories (Folders, Documents, etc.) pour les appels hors composants (loaders, services partagés). Conservé pour compatibilité et contexte non-React.
- **Déduplication** : réutiliser les builders de paramètres de requête (`@Front/Utils/folderQueryBuilders`, `documentQueryBuilders` dans ClientDashboard) pour éviter des `q` / `include` divergents entre écrans.
- **Règle** : nouveau code dans un composant ou hook → préférer `useApiClient` ; code dans un service/factory existant → garder BaseApiService tant que la migration nest pas planifiée.
**Appliqué (dossiers notary)** : les appels API dossiers notary passent par `useApiClient` via le hook `useNotaryFoldersApi` et les helpers `@Front/Utils/notaryFoldersApiEndpoints` et `@Front/Utils/folderQueryBuilders`. Migrés : liste et détail (`useFolderListData`, `useFolderDataFetch`), mise à jour / suppression / création (`UpdateFolderMetadata`, `DeleteModal`, `DeleteFolderModal`, `createFolderSubmitHelpers`, `finalizePayloadHelpers`), chargement dossier (`useFolderDataInitialization`, `useAskDocumentsFolderData`), archive / unarchive / restore (`ArchiveModal`, `folderInformationControllerCallbacksHelpers` onUnarchive, `ArchiveAlertWarning`), collaborateurs et participants (`useFolderCollaboratorsLoader`, `useUpdateFolderCollaboratorsController`, `useParticipantDeletions`), envoi documents et invités (`dataLoaders` SendDocuments, `useInvitedCustomerFolders`), validation numéro dossier (`useFolderNumberValidation`), redirection auto (`useFolderAutoRedirect`), documents reçus invité (`useInvitedReceivedDocumentsController`), page corbeille (`pages/folders/deleted` : liste supprimés + restauration), en-tête client dossier (`UserFolderHeader`, refactor classe → FC). **Appliqué (dossiers customer)** : les appels API dossiers customer (clients, tiers, notaires invités) passent par `useApiClient` via le hook `useCustomerFoldersApi` et les helpers `@Front/Utils/customerFoldersApiEndpoints`. Migrés : liste et détail (`useCustomerFolders`, `useOfficeChangeRedirect`, `folderLoaders` SelectFolder), chargement dossier et client (`useFolderAndCustomer` ClientDashboard et ReceivedDocuments, `useClientAccountLoader`), notes (`useNoteLoaderUnified`), CreateCustomerNote (`loadFolderWithIncludes`, `useFolderAndCustomerLoader`, `loadAndProcessFolder`).
### Utilisation Frontend
#### Ancien Code
```typescript
const userQuery: IGetUsersParams = {
include: {
contact: {
select: {
first_name: true,
last_name: true,
},
},
},
};
const availableCollaborators = await Users.getInstance().get(userQuery);
```
#### Nouveau Code
```typescript
// Utiliser le nouvel endpoint aggregated
const response = await axios.get('/api/v1/notary/users/aggregated', {
headers: { Authorization: `Bearer ${token}` }
});
const availableCollaborators = response.data;
// Les collaborateurs sont déjà au bon format
const selectOptions = availableCollaborators.map(collaborator => ({
label: `${collaborator.contact?.first_name} ${collaborator.contact?.last_name}`,
id: collaborator.uid,
// Optionnel : afficher une indication visuelle pour les collaborateurs sans compte
badge: collaborator._metadata?.has_user_account ? null : 'Pas de compte'
}));
```
### Points d'Attention
#### UID des Collaborateurs sans Compte
Les collaborateurs sans compte ont un `uid` au format `sync:{idnot}`.
**Important** : Ne jamais utiliser cet UID pour créer des enregistrements en base.
```typescript
// ❌ MAUVAIS
await createStakeholder({
user_uid: collaborator.uid, // Si c'est "sync:123", ça va échouer
folder_uid: folderUid,
});
// ✅ BON
if (collaborator._metadata?.has_user_account) {
await createStakeholder({
user_uid: collaborator.uid,
folder_uid: folderUid,
});
} else {
// Créer le compte d'abord OU afficher un message
alert('Ce collaborateur doit d\'abord créer un compte');
}
```
#### Gestion des Sièges d'Abonnement
Les collaborateurs sans compte **ne peuvent pas** avoir de siège d'abonnement.
Filtrer les collaborateurs pour n'afficher que ceux avec compte dans la gestion des sièges.
### Migration Progressive
L'ancien endpoint `/api/v1/notary/users` reste disponible pour assurer la compatibilité.
La migration peut se faire progressivement composant par composant :
1. `UpdateFolderCollaborators`
2. `SubscriptionManageCollaborators`
3. `CreateFolder`
4. Autres composants utilisant la sélection de collaborateurs
### Service API Frontend Recommandé
**Fichier** : `lecoffre-front-main/src/front/Api/CollaboratorsService.ts`
```typescript
import { apiClient } from './ApiClient';
export class CollaboratorsService {
static getInstance(): CollaboratorsService {
// Singleton pattern
}
async getAggregated(): Promise<AggregatedCollaborator[]> {
const response = await apiClient.get('/api/v1/notary/users/aggregated');
return response.data;
}
async getWithAccounts(): Promise<AggregatedCollaborator[]> {
const all = await this.getAggregated();
return all.filter(c => c._metadata.has_user_account === true);
}
async getWithoutAccounts(): Promise<AggregatedCollaborator[]> {
const all = await this.getAggregated();
return all.filter(c => c._metadata.has_user_account === false);
}
}
```
---
## 5. Architecture Technique
### Wrapper jwt-decode
**Date** : 2025-11-24
**Version** : 2.0.1+
**Dernière mise à jour** : 2025-11-24
#### Problème
Deux problèmes principaux ont été rencontrés avec `jwt-decode` v4 :
1. **Turbopack (bundler Next.js 16)** : Détecte statiquement que `jwt-decode` v4 n'a pas d'export par défaut dans le build ESM, causant l'erreur :
```text
Export default doesn't exist in target module
The export default was not found in module [project]/node_modules/jwt-decode/build/esm/index.js
```
2. **Environnement de build** : En build de production, TypeScript résout `jwt-decode` comme un module CJS (`/repo/lecoffre-front-main/node_modules/jwt-decode/build/cjs/index`), et détecte statiquement que la propriété `default` n'existe pas, causant l'erreur :
```text
Property 'default' does not exist on type 'typeof import("/repo/lecoffre-front-main/node_modules/jwt-decode/build/cjs/index")'
```
#### Solution
Un wrapper a été créé pour gérer les différences entre ESM et CJS, avec des assertions de type explicites pour garantir la sécurité TypeScript :
**Fichier** : `lecoffre-front-main/src/front/Utils/jwtDecodeWrapper.ts`
```typescript
import * as jwtDecodeModule from "jwt-decode";
// Type pour gérer les différentes formes d'export de jwt-decode
type JwtDecodeFunction = (token: string) => unknown;
// Type pour le module jwt-decode avec toutes ses formes possibles
type JwtDecodeModuleType = JwtDecodeFunction | { default?: JwtDecodeFunction; jwtDecode?: JwtDecodeFunction } | Record<string, unknown>;
// Type assertion pour gérer les différences entre ESM et CJS
const jwtDecodeModuleAny = jwtDecodeModule as unknown as JwtDecodeModuleType;
// Vérification à l'exécution pour déterminer comment accéder à la fonction
// Utilisation de if/else explicites pour une meilleure inférence de type
let jwtDecodeFunction: JwtDecodeFunction;
if (typeof jwtDecodeModuleAny === "function") {
jwtDecodeFunction = jwtDecodeModuleAny as JwtDecodeFunction;
} else {
const moduleObj = jwtDecodeModuleAny as Record<string, unknown>;
const defaultExport = moduleObj["default"];
const namedExport = moduleObj["jwtDecode"];
if (typeof defaultExport === "function") {
jwtDecodeFunction = defaultExport as JwtDecodeFunction;
} else if (typeof namedExport === "function") {
jwtDecodeFunction = namedExport as JwtDecodeFunction;
} else {
// Fallback: essayer d'utiliser le module directement
jwtDecodeFunction = jwtDecodeModuleAny as JwtDecodeFunction;
}
}
export const jwtDecode = jwtDecodeFunction as <T = unknown>(token: string) => T;
```
**Points clés de l'implémentation :**
- Utilisation d'assertions de type explicites (`as JwtDecodeFunction`) pour garantir la sécurité TypeScript
- Vérification à l'exécution (runtime) avec `typeof` avant les assertions pour garantir la sécurité
- Utilisation de `if/else` explicites pour une meilleure inférence de type TypeScript
- Support de plusieurs formats d'export :
- Fonction directe (CJS)
- Export default (ESM)
- Export nommé `jwtDecode`
- Fallback sur le module entier
#### Utilisation
**Avant** :
```typescript
import jwtDecode from "jwt-decode";
const decoded = jwtDecode(token);
```
**Après** :
```typescript
import { jwtDecode } from "@Front/Utils/jwtDecodeWrapper";
const decoded = jwtDecode(token);
```
#### Fichiers Modifiés
- `lecoffre-front-main/src/front/Api/BaseApiService.ts`
- `lecoffre-front-main/src/front/Services/TokenRefreshService/TokenRefreshService.ts`
- `lecoffre-front-main/src/proxy.ts`
- `lecoffre-front-main/src/front/Stores/ActiveOfficeStore.ts`
#### Avantages
- ✅ Compatible avec Turbopack (Next.js 16)
- ✅ Gère automatiquement les différences ESM/CJS
- ✅ Fonctionne en build de production (résolution CJS)
- ✅ Évite les erreurs TypeScript statiques grâce à `as any`
- ✅ Vérification à l'exécution pour déterminer le format d'export
- ✅ Type-safe avec TypeScript (casting final)
---
## 6. Authentification IdNot et Logging
### Logging des Données API IdNot au Login
**Date** : 2025-01-XX
**Version** : 2.0.1+
#### Vue d'Ensemble
Des logs détaillés ont été ajoutés dans la console du navigateur pour tracer les données API reçues d'IdNot lors du processus d'authentification, permettant de diagnostiquer les problèmes d'authentification et de suivre le flux complet.
#### Logs Disponibles
**Tous les environnements** :
- Logs de la présence des tokens (hasAccessToken, hasRefreshToken) sans jamais logger les valeurs
- Logs du JWT décodé avec informations utilisateur (userId, officeId, role, règles)
- Logs des erreurs avec contexte détaillé
#### Fichiers Concernés
- `lecoffre-front-main/src/front/Api/Auth/IdNot/index.ts` : Service d'authentification IdNot avec logs
- `lecoffre-front-main/src/front/Components/Layouts/LoginCallback/hooks/helpers/idNotAuthHelpers.ts` : Échange code → tokens (sans log des valeurs de tokens)
- `lecoffre-front-main/src/front/Components/Layouts/LoginCallback/index.tsx` : Callback de login avec logs détaillés
#### Exemples de Logs
```text
[Front] 🔄 [IdNot] Exchanging authorization code for JWT tokens
[Front] ✅ [LoginCallback] IdNot tokens received, connecting user { hasAccessToken: true, hasRefreshToken: true }
[Front] ✅ [LoginCallback] JWT decoded successfully { userId: "...", officeId: "...", role: "admin", hasRules: true, rulesCount: 15 }
```
#### Sécurité
- ✅ Tokens (accessToken, refreshToken) jamais loggés, quel que soit l'environnement (risque de fuite via agrégation de logs)
- ✅ Seuls les 10 premiers caractères du code d'autorisation sont loggés
- ✅ Uniquement des indicateurs booléens (hasAccessToken, hasRefreshToken) sont loggés après réception des tokens
**Documentation complète** : Voir ARCHITECTURE (Types dutilisateurs, connexion IdNot) et logs IdNot au login.
### Nettoyage silencieux des sessions expirées sur les pages publiques
- Les appels publics (`BasePublic` → `SiteTextsApi`, `IncidentReportApi`) n'imposent plus de redirection vers `https://qual-connexion.idnot.fr/` quand un `leCoffreAccessToken` expiré est présent mais que le refresh token a disparu.
- `BaseApiService.checkJwtToken()` détecte toujours le flag IdNot, mais `BasePublic` surcharge désormais `shouldEnforceIdNotLogoutOnExpiredSession()` pour renvoyer `false`. Le SDK se contente alors de supprimer les cookies locaux au lieu de forcer une navigation.
- Toutes les API privées continuent de déclencher la redirection Id.Not dès que l'utilisateur tente d'appeler un endpoint protégé avec un token expiré ou invalide.
- Cette séparation évite la "redirection instantanée" depuis `/` tout en conservant la synchronisation stricte des sessions sur les pages authentifiées.
### Rafraîchissement automatique des sessions (2025-12)
- Nouveau service `SessionRefreshService` démarré depuis `_app.tsx`
- Lit en continu le refresh token (`leCoffreRefreshToken`) pour calculer sa date d'expiration (`exp`)
- Programme un rafraîchissement 2 minutes avant l'expiration (fallback toutes les 10 minutes)
- S'appuie sur `TokenRefreshService` (qui reçoit désormais un refresh token *rotated* à chaque appel)
- Ré-écoute les événements `UserStore` / `CustomerStore` (`onConnect` / `onDisconnect`) pour relancer ou arrêter les timers quand un utilisateur change d'état
- Empêche les expirations silencieuses malgré une activité continue dans l'UI, tout en journalisant les succès / échecs côté front
---
## 7. Interface Espace Notaire - Onglets et Tableaux
### Refonte des onglets membres et tableaux documents
**Date** : 2025-01-XX
**Version** : 2.0.1+
**Page** : `/folders/[folderUid]` - Vue ClientView
#### Vue d'Ensemble
Refonte complète de l'interface des onglets des membres et des tableaux de documents dans l'espace notaire pour améliorer la clarté et la conformité des documents.
#### Modifications des Onglets Membres
**Composants modifiés** :
- `ClientView/ThirdPartyBox/index.tsx`
- `ClientView/ClientBox/index.tsx`
- `ClientView/SharedNotaryBox/index.tsx`
**Changements** :
1. **ThirdPartyBox** :
- ❌ Suppression du bouton "Renvoyer l'invitation"
- ❌ Suppression du bouton "Supprimer"
- ✅ Bouton unique "Modifier la note" (remplace le menu)
2. **ClientBox** :
- ✅ Texte du bouton de note changé en "Modifier la note" (au lieu de "Rajouter/modifier une note")
3. **SharedNotaryBox** :
- ✅ Texte du bouton de note changé en "Modifier la note"
- ✅ Menu conservé avec option "Modifier les informations" (si disponible)
#### Modifications des Tableaux de Documents
**Composants modifiés** :
- `ClientView/DocumentTables/index.tsx`
- `ClientView/DocumentTables/useDocumentTablesController.ts`
- `ClientView/DocumentTables/hooks/useDocumentRows.tsx`
- `ClientView/DocumentTables/helpers/tableHeaders.ts`
- `ClientView/DocumentTables/helpers/documentConformity.ts`
- `ClientView/DocumentTables/components/DocumentTablesHeader.tsx`
- `ClientView/DocumentTables/components/ValidatedDocumentsSection.tsx`
**Nouvelle fonctionnalité : Vérification de conformité**
Un nouveau helper `documentConformity.ts` vérifie la conformité des documents :
- **Lien IPFS** : Présence de `watermarked_s3_key` ou `file_path` dans les fichiers
- **Ancrage** : Présence de `document_anchor`
- **Données d'ancrage** : Présence de `document_anchor.proof_data`
Si l'un de ces éléments manque, le statut du document devient **"NON CONFORME"**.
**⚠️ Exception importante : Documents demandés (ASKED)**
Les documents avec le statut `ASKED` (demandés mais pas encore déposés) ne sont **jamais vérifiés pour la conformité** car :
- Ils n'ont pas encore de fichier déposé
- Ils ne peuvent donc pas avoir de filigrane, d'ancrage ou de métadonnées
- La vérification de conformité ne s'applique qu'aux documents déposés (`DEPOSITED`)
Les documents ASKED affichent toujours le statut "DEMANDE" et jamais "NON CONFORME".
**Nouveaux tableaux** :
1. **"Documents demandés"** (sans nombre entre parenthèses) :
- **Statuts** : DEMANDES, A VALIDER, NON CONFORME
- **Colonnes** : Type de document, Statut, Déposé le, Action (voir)
- **Note** : Pas de colonne "Nom du document" car les documents ASKED n'ont pas encore de fichiers déposés
- **Note** : Pas de case à cocher pour les documents ASKED et DEPOSITED
- **Note** : Vérification de conformité uniquement pour les documents DEPOSITED (les documents ASKED affichent toujours "DEMANDE")
- **Fichier** : `useAskedDocumentsRows()` - Combine ASKED et DEPOSITED avec vérification conformité uniquement pour DEPOSITED
- **DEPOSITED (À VALIDER)** : L'icône « voir » (œil) est affichée pour le notaire afin de visualiser et valider le document. Pour le déposant (client/tiers/notaire invité), la ligne avec la date de dépôt reste visible mais le fichier n'est pas affiché ni modifiable sur la page de visualisation.
2. **"Documents validés"** (sans nombre entre parenthèses) :
- **Statuts** : VALIDE, TELECHARGE, NON CONFORME
- **Colonnes** : case à cocher, Nom du document, Type de document, Déposé le, Action (télécharger, voir)
- **Boutons** : Télécharger ZIP et Télécharger Certificat (selon les coches)
- **Fichier** : `useValidatedDocumentsRows()` - Combine VALIDATED et DOWNLOADED avec vérification conformité
3. **"Documents envoyés"** (sans nombre entre parenthèses) :
- **Statuts** : ENVOYE, NON CONFORME
- **Colonnes** : case à cocher, Nom du document, Statut, Déposé le, Action (télécharger, supprimer)
- **Boutons** : Télécharger ZIP et Télécharger Certificat (selon les coches)
- **Fichier** : `useSentDocumentsRows()` - Filtre SENT avec vérification conformité
**Homogénéisation Documents envoyés (2026-03)** : Le notaire envoie de la même façon aux clients, tiers et notaires invités (emails différents selon le type). Affichage centralisé via `getSentDocumentsForTab()` : clients=DocumentsNotary, tiers=Documents(third_party_depositor), invités=Documents(shared_to_office). Envoi unifié via POST /notary/documents_notary/send (un appel par destinataire).
**Modifications techniques** :
- Suppression du compteur de progression dans `DocumentTablesHeader`
- Suppression des nombres entre parenthèses dans les titres des sections
- Ajout de cases à cocher pour la sélection multiple dans les tableaux "Documents validés" et "Documents envoyés"
- **Homogénéisation récupération données** : `useDocumentTablesData` orchestre Documents et DocumentsNotary avec paramètres centralisés par onglet
- **Centralisation onglets (2026-03)** : `useDocumentRowsData` extrait dans `hooks/useDocumentRowsData.ts` ; `filterDocumentsForTabMember` mutualise Asked/Refused ; `filterAndDeduplicateDocumentsByStatus` mutualise Validated (ClientView, InvitedView, ClientDashboard) ; `buildParticipantTab` factory pour participant tabs ; `filterOutDeletedDocuments` mutualise le filtrage des documents soft-deleted ; `hasDocumentWithDownloadableFile`/`filterDocumentsWithDownloadableFile` mutualise le filtrage documents avec fichier ; `deduplicateDocuments` déplacé vers module partagé ; `getDocumentNameFromFirstFile` mutualise l'extraction du nom ; `buildValidatedDocumentRow` factorise les 3 contextes (ClientView, InvitedView, ClientDashboard) ; renommage `documentFilterTabMemberHelpers` et `documentFilterToSendHelpers` pour clarifier les deux fichiers documentFilterHelpers
- **Sélections indépendantes** : `selectedValidatedDocuments` et `selectedSentDocuments` pour éviter que la sélection dans une section n'affecte l'autre
- Intégration de la vérification de conformité dans les hooks de génération de lignes (uniquement pour les documents avec fichiers)
- Support des documents `DocumentNotary` avec statut DOWNLOADED dans "Documents validés"
- **Colonnes conditionnelles** : Pas de colonne "Nom du document" pour "Documents demandés" (documents ASKED sans fichiers)
- **Cases à cocher conditionnelles** : Pas de case à cocher pour les documents ASKED et DEPOSITED dans "Documents demandés"
**Fichiers créés** :
- `ClientView/DocumentTables/helpers/documentConformity.ts` : Fonctions de vérification de conformité
**Fichiers modifiés** :
- `ClientView/DocumentTables/index.tsx` : Réorganisation des sections, ajout des boutons pour documents envoyés, sélections indépendantes
- `ClientView/DocumentTables/useDocumentTablesController.ts` : Ajout de deux sélections séparées (`selectedValidatedDocuments`, `selectedSentDocuments`)
- `ClientView/DocumentTables/hooks/useDocumentRows.tsx` : Refonte complète des hooks pour les nouveaux tableaux avec colonnes conditionnelles
- `ClientView/DocumentTables/hooks/useDocumentRowsData.ts` : Orchestration des lignes (Asked, Validated, Sent, Refused) et calcul progression
- `ClientView/DocumentTables/helpers/documentFilterHelpers.ts` : `filterDocumentsForTabMember` pour Asked/Refused
- `ClientView/DocumentTables/helpers/documentFilterStatusHelpers.ts` : `filterAndDeduplicateDocumentsByStatus` pour Validated
- `ClientView/DocumentTables/helpers/documentFilterDeletionHelpers.ts` : `filterOutDeletedDocuments` pour documents soft-deleted (documentsDataLoader, receivedDocumentsLoaderHelpers)
- `ClientView/DocumentTables/helpers/documentFilterFilesHelpers.ts` : `hasDocumentWithDownloadableFile`, `filterDocumentsWithDownloadableFile`
- `ClientView/DocumentTables/helpers/documentDeduplicationHelpers.ts` : `deduplicateDocuments`
- `ClientView/DocumentTables/helpers/documentFilterTabMemberHelpers.ts` : `filterDocumentsForTabMember`, `filterDocumentByActiveMember` (ex-documentFilterHelpers)
- `ClientDashboard/helpers/documentFilterToSendHelpers.ts` : `filterDocumentsToSend`, constantes statuts (ex-documentFilterHelpers)
- `ClientView/helpers/participantTabsHelpers.tsx` : `buildParticipantTab` factory
- `ClientView/DocumentTables/helpers/tableHeaders.ts` : Mise à jour des en-têtes de tableaux
- `ClientView/DocumentTables/components/DocumentTablesHeader.tsx` : Suppression du compteur
- `ClientView/DocumentTables/components/ValidatedDocumentsSection.tsx` : Suppression du nombre dans le titre
---
## 8. Consolidation évolutions et correctifs
Cette section consolide les éléments issus des documents de travail intégrés dans la documentation frontend pérenne.
### Upload, contexte utilisateur et tables
- Le module d'upload “Ajouter un document” est unifié entre documents à envoyer et documents supplémentaires avec sélection locale avant envoi explicite.
- Helpers clés : `Utils/documentUploadByRoleHelper.ts`, `Utils/userContextResolver.ts`, `Hooks/useResolvedUserContext.ts`, `DesignSystem/DepositOtherDocument`.
- Le routage des uploads par rôle est centralisé (`customer`, `third_party`, `invited_notary`) et les contrats de dépôt sont typés.
- La résolution de contexte utilisateur (dashboard, vues document, sélection de dossier) est mutualisée via des helpers/hook dédiés.
- Les wrappers legacy ont été alignés sur des composants partagés pour réduire les branches spécifiques par rôle.
- Les textes et colonnes des tableaux de documents reçus sont construits via des builders mutualisés.
- L'identité des onglets membres (`customer`/`third_party`/`shared notary`) est unifiée avec helpers dédiés pour navigation et sélection.
### Téléchargements et nommage
- Le téléchargement des documents demandés côté notaire est aligné sur un flux PDF unique (et non ZIP par défaut).
- Le dédoublonnage des noms de fichiers est renforcé (normalisation Unicode + normalisation extension `.pdf`) pour stabiliser la décision ZIP/PDF.
- Le nommage ZIP multi-téléchargement suit le format dossier/tableau (`<folder_number>.<nom du tableau>.(validé).zip`).
- Les fichiers validés téléchargés (tableau Documents validés, page visualisation, côté tiers/clients/notaire invité) ont le suffixe ` (validé)` avant lextension (ex. `document (validé).pdf`). Sapplique aux statuts VALIDATED, SENT, DOWNLOADED.
### Correctifs de fiabilité frontend
- Migration des signatures JSX vers les conventions React 19 (`React.JSX.Element`, `React.ReactNode`) et suppression de la dépendance au shim global JSX.
- Nettoyage des `console.log` oubliés au profit de `LoggerService`.
- Suppression du code mort ID360 (routes, composants, API front inutilisés).
### Upload : fusion systématique et page de métadonnées
Tous les uploads (1 ou plusieurs fichiers) sont fusionnés et incluent la page de métadonnées (hash des fichiers originaux) dans le PDF filigrané. FileUploadHelper, ThirdPartyUploadService, GuestNotaryDocumentService, RIB, POST /notary/documents_notary : toujours fusion via FileMergeService. Module Deposit unifié : DepositContent partagé, configs par scope (documents, rib, sendDocuments).
### Retour sur l'onglet membre après modification
Après validation ou annulation lors de la modification des informations d'un membre (client, tiers, notaire invité), le backwardPath inclut les paramètres d'onglet (customerUid, thirdPartyUid, shareUid) pour que useParticipantTabs sélectionne le bon onglet. Fichiers : participantTabNavigationHelpers.appendQueryParam, useUpdateClientController, useUpdateSharedNotaryController, updateThirdPartyFormHelpers.
### Restriction téléchargement/visualisation tableaux notaires
Dans les onglets clients/tiers/notaires invités du dossier (vue notaire propriétaire) : documents DEPOSITED (À VALIDER) affichent l'icône œil pour que le notaire puisse visualiser et valider ; documents REFUSED n'affichent pas d'icône œil. Documents VALIDATED et SENT conservent téléchargement et visualisation. Page ViewDocuments : showDownload limité aux documents VALIDATED, SENT, DOWNLOADED. Espaces clients, tiers, notaires invités non impactés.
### Centralisation aperçu fichiers (file preview)
Helpers centralisés dans `@Front/Utils/filePreviewHelpers.ts` : FilePreviewState, createFilePreviewState, revokeFileUrl, loadFilePreviewDocumentNotary, loadFilePreviewDocument. ViewDocumentsNotary et ViewDocumentSent utilisent ces helpers. Variables SCSS : $document-preview-min-height, $document-file-container-min-height dans @Themes/constants.scss.
## 8. Opérations Batch Frontend
### Envoi Batch Documents
**Frontend** :
- **Page** : `/folders/[folderUid]/send-documents`
- **Composant** : `SendDocuments`
- **Fonctionnalités** : Sélection multiple + progression
### Filtres Avancés
**Frontend** :
- **Page** : `/folders/select` (sélection avec filtres)
- **Autocomplétion** : Recherche via appels API (IdNot/Annuaire) et dans `third_parties`
### Certificat Agrégé Documents
**Frontend** :
- Bouton "Télécharger Certificat" dans les tableaux de documents
- Disponible pour les documents validés et les documents envoyés
- Vérification que tous les documents sélectionnés sont ancrés
**ZIP** :
- Les ZIP téléchargés incluent automatiquement le certificat agrégé si des documents ancrés sont présents
- Support séparé pour Documents et DocumentsNotary (deux certificats si nécessaire)
---
## 9. Envoi de Documents par Notaires Invités
**Statut** : ✅ 100% | **Version** : 2.0.1
### Vue d'Ensemble
Les modifications permettent aux notaires invités de créer des documents avec `shared_to_office_uid` pointant vers l'office du notaire propriétaire (au lieu de leur propre office). Ces documents ont le statut `DEPOSITED` et sont visibles par le notaire propriétaire.
### ClientView - DocumentTables (Notaire propriétaire)
**Impact** : ✅ Géré
- Les documents créés par les notaires invités avec `shared_to_office_uid` pointant vers l'office du notaire propriétaire apparaissent maintenant dans les onglets des membres du dossier
- Modification dans `useDocumentTablesController.ts` : ajout de la condition `shared_to_office: { uid: folderOfficeUid }` dans la clause OR
### InvitedView (Notaire invité)
**Impact** : ✅ Géré
- Nouvelle section "Documents à envoyer" pour les documents ASKED
- Nouvelle section "Documents supplémentaires" pour créer des documents "Autres documents"
- Les documents créés apparaissent dans la section appropriée
### Points de Vigilance
#### Distinction entre documents envoyés PAR et envoyés AU notaire invité
Les documents avec `shared_to_office_uid` peuvent être :
- **Envoyés PAR le notaire propriétaire AU notaire invité** : `shared_to_office_uid` = office invité, statut SENT, pas de depositor
- **Envoyés PAR le notaire invité AU notaire propriétaire** : `shared_to_office_uid` = office propriétaire, statut DEPOSITED, pas de depositor
**Impact** : La logique de filtrage doit distinguer ces deux cas selon le contexte (InvitedView vs ClientView)
#### Documents "Autres documents" créés par les notaires invités
Les documents créés via "Documents supplémentaires" ont :
- Type : "Autres documents"
- Statut : DEPOSITED
- `shared_to_office_uid` : office du notaire propriétaire
**Impact** : Ces documents doivent être visibles par le notaire propriétaire dans les onglets des membres, mais pas dans les onglets des notaires invités
### Emails et Notifications
**Comportement** : ✅ Pas d'impact (comportement attendu)
- `sendDocumentEmails()` ne gère que les statuts ASKED, REFUSED (VALIDATED désactivé)
- **Documents DEPOSITED** : Les documents créés par les notaires invités pour le notaire propriétaire ont le statut DEPOSITED et **ne génèrent pas d'email**
- **Raison** : Le notaire gestionnaire du dossier verra le document dans son interface sans avoir besoin d'une notification par email
---
## 10. Mutualisation des Espaces Client / Tiers / Dossiers Invités
**Statut** : ✅ COMPLÉTÉ | **Version** : 2.0.0
### Vue d'Ensemble
Réduction de la duplication de code entre les trois espaces utilisateurs tout en préservant leurs spécificités fonctionnelles.
### Résultats
- **5 composants/services/helpers génériques** créés
- **7 fichiers** refactorisés
- **~1190 lignes** de code dupliqué → **~980 lignes** mutualisées
- **~82% de réduction** du code dupliqué
- **0 régression** : tous les comportements préservés
### Mutualisations Implémentées
#### Phase 1 : Composants UI
**1. GenericDocumentsToSendSection**
- **Fichier** : `components/GenericDocumentsToSendSection.tsx`
- **Réduction** : ~290 lignes → ~15 lignes par wrapper
- **Utilisation** : ClientDashboard, InvitedView
- **Spécificités** : Exclusion "Document notaire", gestion refusedDocuments, styles personnalisés
**2. GenericReceivedDocumentsPage**
- **Fichier** : `components/GenericReceivedDocumentsPage.tsx`
- **Réduction** : ~300 lignes → ~60 lignes par wrapper
- **Utilisation** : ClientDashboard, InvitedView
- **Spécificités** : Colonnes configurables, tracking personnalisé, routes flexibles
**2.b. ReceivedDocumentsNotification**
- **Fichier** : `ClientDashboard/components/ReceivedDocumentsNotification.tsx`
- **Utilisation** : ClientDashboardHeader, InvitedViewContent
- **Spécificités** : même composant, seul le texte métier (votre notaire / confrère) change selon l'espace
**2.c. Legacy ReceivedDocuments wrapper alignment**
- **Fichier** : `ClientDashboard/ReceivedDocumentsSection.tsx`
- **Utilisation** : wrapper legacy aligné sur les helpers partagés du centre
- **Spécificités** : calcul des documents reçus/counters délégué à `ClientDashboard/helpers/receivedDocumentsCenterHelpers.ts`
**2.d. Received labels builder**
- **Fichiers** :
- `DesignSystem/helpers/commonUiI18n.ts`
- `DesignSystem/helpers/commonUiMessageBuilders.ts`
- **Utilisation** : `ClientDashboardHeader`, `InvitedViewContent`, `ReceivedDocumentsSection`
- **Spécificités** : textes "documents envoyés par ..." centralisés via builders selon le contexte (`notary` / `peerNotary`)
**2.e. ReceivedDocumentsTextContext**
- **Fichier** : `DesignSystem/helpers/commonUiMessageBuilders.ts`
- **Type** : `ReceivedDocumentsTextContext`
- **Spécificités** :
- contexte explicite (`sender`) pour la source métier,
- stratégie de grammaire (`pluralStrategy`) pour singular/plural (`strict`/`inclusive`),
- réutilisé pour notifications, titres de pages "Documents reçus" et noms de ZIP.
**2.f. Table Presets Builder**
- **Fichier** : `Layouts/helpers/tablePresetsBuilder.ts`
- **Utilisation** :
- Wrappers reçus: `ClientDashboard/ReceivedDocuments/index.tsx`, `InvitedView/ReceivedDocuments/index.tsx`
- Tables dossier: `DocumentTables/helpers/tableHeaders.ts`, `DocumentsReminderHistory/index.tsx`
- Sections non-dossier: `Layouts/DesignSystem/sections/TableSection.tsx`, `Layouts/SuperAdmin/SiteTexts/constants.ts`
- **Spécificités** :
- source unique des intitulés partagés `Nom`, `Type de document`, `Statut`, `Envoyé le`, `Action`
- presets de colonnes prêts à lemploi : `buildReceivedDocumentsColumnTitles()`, `buildDefaultReceivedDocumentsColumns()`, `buildDetailedReceivedDocumentsColumns()`, `buildDocumentTypeStatusActionHeaders()`, `buildDocumentTypeStatusSentAtActionHeaders()`, `buildNameStatusSentAtActionHeaders()`, `buildDocumentTypeStatutHeaders()`, `buildStatusActionHeaders()`.
#### Phase 2 : Services
**3. DocumentDownloadService**
- **Fichier** : `Services/DocumentDownloadService/DocumentDownloadService.ts`
- **Réduction** : ~400 lignes dupliquées → service centralisé (~350 lignes)
- **Utilisation** : ClientDashboard, InvitedView, tous les téléchargements
- **Fonctionnalités** :
- Téléchargement individuel et groupé
- Marquage comme "vu" selon contexte
- Gestion d'erreurs et toasts uniforme
- Support de tous les types de documents
- Dépôt multi-fichiers (ClientDashboard) : envoi batch unique par document pour client, tiers et notaire invité afin de déclencher la fusion backend en un PDF unique
- Dispatch dupload unifié par rôle via `Utils/documentUploadByRoleHelper.ts` (réutilisé par ClientDashboard et DepositOtherDocument)
- Un dépôt multi-fichiers sur un document produit un unique PDF fusionné actif côté backend (les anciens fichiers actifs du document sont archivés)
- Les formulaires HTML génériques utilisent un helper dextraction dédié `DesignSystem/Form/helpers/formValueExtractionHelpers.ts` (source unique pour la collecte des valeurs `FormData`)
- La couche legacy `BaseApiServiceRequests` est supprimée : le socle API transite désormais via `BaseApiServiceFactory` et ses helpers partagés
- Les query params complexes (`q`, objets sérialisés) sont centralisés via `Api/helpers/queryParamHelpers.ts` et réutilisés dans les builders dendpoints dossiers notary/customer
- Les payloads fichiers/téléchargements (download multiple, aggregated certificate, send documents) sont centralisés via `Api/LeCoffreApi/helpers/fileRequestPayloadHelpers.ts`
- Les payloads JSON métier récurrents (hors fichiers) sont centralisés via `Api/LeCoffreApi/helpers/businessRequestPayloadHelpers.ts` et réutilisés par les modules Documents, Customers, FolderSharing et DocumentReminders
- Lharmonisation est étendue aux modules SuperAdmin (`SiteTexts`, `Health`, `Folders`) avec réutilisation des builders partagés `buildEmptyPayload`, `buildPayloadOrEmpty` et `buildStatusUpdatePayload`
- Les builders CRUD typés par domaine (`documents`, `folders`, `users`) sont appliqués aux factories `Admin/SuperAdmin` restantes (`DocumentsFactory`, `UsersFactory`) pour homogénéiser les payloads create/update
- Les builders CRUD typés sont étendus aux domaines `deeds`, `deedTypes`, `documentTypes`, `roles`, `customers` et appliqués uniformément dans les factories/helpers `Admin`, `Notary`, `SuperAdmin`
- Les domaines restants `officeRoles`, `stripe`, `files`, `notifications`, `health`, `liveVotes` sont aussi alignés via des builders dédiés dans `Api/LeCoffreApi/helpers/businessRequestPayloadHelpers.ts` (suppression des payloads inline restants dans leurs factories/helpers)
- Une convention transversale de suppression par identifiant est ajoutée via `buildDeletePayloadByUid(...)`, puis déclinée en wrappers métier (`buildLiveVotesDeletePayload(...)`) pour compléter la convention CRUD (`create/update/archive/restore/delete`)
- La vérification des helpers UI/API récemment touchés est exécutée (lint + typecheck), sans régression de signature détectée
**3.b. Office RIB consultation hook**
- **Fichier** : `ClientDashboard/hooks/useOfficeRibDownload.ts`
- **Utilisation** : `ClientDashboard/ContactBox`, `Folder/FolderInformation/InvitedView/InvitedViewContent`
- **Spécificités** : chargement et téléchargement RIB unifiés pour client, tiers et notaire invité
#### Phase 3 : Helpers
**4. documentFilterHelpers**
- **Fichier** : `ClientDashboard/helpers/documentFilterHelpers.ts`
- **Constantes (source unique)** :
- `DOCUMENTS_TO_SEND_STATUSES` : ASKED, REFUSED, VALIDATED (« Documents à envoyer » ; DEPOSITED, SENT, DOWNLOADED exclus).
- `DOCUMENT_STATUSES_RECEIVED_FROM_NOTARY` : SENT, DOWNLOADED (table documents).
- `DOCUMENT_NOTARY_STATUSES_RECEIVED_FROM_NOTARY` : SENT, DOWNLOADED (table documents_notary).
- **Fonction exportée** :
- `statusUpper(s)` : normalise le statut en majuscules (comparaisons API).
- **Fonctions** :
- `filterDocumentsToSend` : Filtrage « Documents à envoyer » (utilise DOCUMENTS_TO_SEND_STATUSES).
- `filterValidThirdPartyDocuments` : Filtrage documents tiers valides par customerUid.
- `deduplicateDocuments` : Suppression doublons par uid.
- **Autres filtres (autres fichiers)** : `filterDocuments` dans `DocumentTables/helpers/documentTablesDataHelpers.ts` ; `filterReceivedDocuments` dans `InvitedView/ReceivedDocuments/helpers/receivedDocumentsFilterHelpers.ts` et `InvitedView/helpers/filterReceivedDocuments.ts`.
- **Visualisation documents envoyés (tiers)** : en « Documents reçus », le clic œil ouvre la page de visualisation du Document (table documents) pour les tiers ; route `ClientDashboard.ViewDocument` → `/client-dashboard/[folderUid]/document/[documentUid]` ; composant `ViewDocumentSent` (Documents.getByUid, Files.download, DocumentViewer, markAsViewed). Les clients restent sur ViewDocumentsNotary (DocumentNotary).
**5. documentQueryBuilders**
- **Fichier** : `ClientDashboard/helpers/documentQueryBuilders.ts`
- **Builders** :
- `buildCustomerDocumentsQuery` : Requêtes ClientDashboard (client et tiers) ; utilise `DOCUMENTS_TO_SEND_STATUSES` pour « Documents à envoyer ».
- `buildDocumentsInclude` : Construction clauses include (files, document_anchor, document_history, document_type, depositor/third_party_depositor, folder).
**6. Validated documents shared wrapper**
- **Fichier** : `ClientDashboard/components/ValidatedDocumentsListWrapper.tsx`
- **Utilisation** : `ClientDashboard/components/ValidatedDocumentsSection.tsx`, `Folder/FolderInformation/InvitedView/components/InvitedDocumentsSection.tsx`
- **Spécificités** : source unique de filtrage `VALIDATED` + normalisation `uid` avant rendu `ValidatedDocumentsListSection`
**7. Received counters source unique**
- **Fichier** : `ClientDashboard/helpers/receivedDocumentsCenterHelpers.ts`
- **Utilisation** : `ClientDashboard/ReceivedDocumentsSection.tsx` et `ClientDashboard/useClientDashboardDocuments.ts`
- **Spécificités** : total + unread calculés via le même helper pour client et tiers
**8. Received ZIP naming builder**
- **Fichiers** :
- `DesignSystem/helpers/commonUiMessageBuilders.ts`
- `Layouts/Folder/FolderInformation/ClientView/DocumentTables/helpers/zipDownloadHelpers.ts`
- `Services/DocumentDownloadService/DocumentDownloadService.ts`
- **Spécificités** : nommage ZIP centralisé et aligné au contexte (`notary` / `peerNotary`) au lieu de chaînes inline.
**9. Extended contextual document labels**
- **Fichier** : `DesignSystem/helpers/clientDashboardMessageBuilders.ts`
- **Builders** :
- `buildAdditionalDocumentsDescription(...)`
- `buildAskDocumentsPageTitle(...)`
- `buildReceivedDocumentsTransferLabel(...)`
- **Utilisation** :
- `ClientDashboard/AdditionalDocumentsSection.tsx`
- `InvitedView/components/InvitedAdditionalDocumentsSection.tsx`
- `Folder/AskDocuments/hooks/useAskDocumentsPermissions.ts`
- `DocumentTables/helpers/documentTablesDownloadHelpers.ts`
**10. Design identique partie centrale (client / tiers / notaires invités)**
- **Objectif** : Aligner la présentation et lordre des sections dans les espaces client, tiers et notaires invités.
- **Ordre unifié** : Documents envoyés par le notaire (encart) → RIB → Documents à envoyer (incl. refusés) → Documents validés → Documents supplémentaires (facultatif).
- **Fichiers modifiés** :
- `ClientDashboard/index.tsx` : ValidatedDocumentsSection affiché pour client et tiers (plus seulement tiers).
- `ClientDashboard/DocumentsToSendSection.tsx` : `excludeValidated={true}` pour client et tiers (documents validés dans section dédiée).
- `InvitedView/components/InvitedViewContent.tsx` : ordre des sections (ReceivedDocumentsNotification avant RIB).
- `InvitedView/classes.module.scss` : classes `.documents`, `.content`, `.rib-actions`, `.deposit-documents` alignées sur ClientDashboard.
- `InvitedView/components/InvitedDocumentsToSendSection.tsx` : `wrapperClassName`/`contentClassName` identiques à ClientDashboard.
- `InvitedView/components/InvitedAdditionalDocumentsSection.tsx` : `showWrapper={false}`, typo par défaut pour cohérence.
- **Documents validés** : même présentation (ValidatedDocumentsListSection) pour client, tiers et notaires invités.
### Bénéfices Obtenus
#### Maintenabilité
- Logique centralisée : modifications futures plus faciles
- Moins de duplication : moins de risques d'incohérences
- Code plus lisible : structure claire et organisée
#### Cohérence
- Comportement uniforme entre les espaces
- Gestion d'erreurs standardisée
- Logging et toasts cohérents
#### Flexibilité
- Configuration via props/options
- Spécificités préservées par contexte
- Extensibilité facilitée
---
## 📚 Références
- [ARCHITECTURE.md](./ARCHITECTURE.md) - Architecture rôles et permissions
- [API.md](./API.md) - API Annuaire
- Évolutions espace client : voir section « documentFilterHelpers » ci-dessus (visualisation documents envoyés tiers).
---
**Dernière mise à jour** : 2026-02-25
---
## 7. Interface Espace Notaire - Onglets et Tableaux
### Refonte des onglets membres et tableaux documents
**Date** : 2025-01-XX
**Version** : 2.0.1+
**Page** : `/folders/[folderUid]` - Vue ClientView
#### Vue d'Ensemble
Refonte complète de l'interface des onglets des membres et des tableaux de documents dans l'espace notaire pour améliorer la clarté et la conformité des documents.
#### Modifications des Onglets Membres
**Composants modifiés** :
- `ClientView/ThirdPartyBox/index.tsx`
- `ClientView/ClientBox/index.tsx`
- `ClientView/SharedNotaryBox/index.tsx`
**Changements** :
1. **ThirdPartyBox** :
- ❌ Suppression du bouton "Renvoyer l'invitation"
- ❌ Suppression du bouton "Supprimer"
- ✅ Bouton unique "Modifier la note" (remplace le menu)
2. **ClientBox** :
- ✅ Texte du bouton de note changé en "Modifier la note" (au lieu de "Rajouter/modifier une note")
3. **SharedNotaryBox** :
- ✅ Texte du bouton de note changé en "Modifier la note"
- ✅ Menu conservé avec option "Modifier les informations" (si disponible)
#### Modifications des Tableaux de Documents
**Composants modifiés** :
- `ClientView/DocumentTables/index.tsx`
- `ClientView/DocumentTables/hooks/useDocumentRows.tsx`
- `ClientView/DocumentTables/helpers/tableHeaders.ts`
- `ClientView/DocumentTables/helpers/documentConformity.ts`
- `ClientView/DocumentTables/components/DocumentTablesHeader.tsx`
- `ClientView/DocumentTables/components/ValidatedDocumentsSection.tsx`
**Nouvelle fonctionnalité : Vérification de conformité**
Un nouveau helper `documentConformity.ts` vérifie la conformité des documents :
- **Lien IPFS** : Présence de `watermarked_s3_key` ou `file_path` dans les fichiers
- **Ancrage** : Présence de `document_anchor`
- **Données d'ancrage** : Présence de `document_anchor.proof_data`
Si l'un de ces éléments manque, le statut du document devient **"NON CONFORME"**.
**⚠️ Exception importante : Documents demandés (ASKED)**
Les documents avec le statut `ASKED` (demandés mais pas encore déposés) sont **toujours considérés comme conformes** car :
- Ils n'ont pas encore de fichier déposé
- Ils ne peuvent donc pas avoir de filigrane, d'ancrage ou de métadonnées
- La vérification de conformité ne s'applique qu'aux documents déposés (`DEPOSITED`)
La fonction `isDocumentConform()` retourne automatiquement `true` pour tous les documents en statut `ASKED`, garantissant qu'ils s'affichent toujours avec le statut "DEMANDE" et jamais "NON CONFORME".
**Nouveaux tableaux** :
1. **"Documents demandés"** (sans nombre entre parenthèses) :
- **Statuts** : DEMANDES, A VALIDER, NON CONFORME
- **Colonnes** : Type de document, Statut, Déposé le, Action (voir)
- **Fichier** : `useAskedDocumentsRows()` - Combine ASKED et DEPOSITED avec vérification conformité
- **Note** : Pas de colonne "Nom du document" car les documents ASKED n'ont pas encore de fichiers déposés
- **Note** : Pas de case à cocher pour les documents ASKED et DEPOSITED
- **Note** : Les documents `ASKED` ne sont jamais vérifiés pour la conformité et affichent toujours "DEMANDE"
2. **"Documents validés"** (sans nombre entre parenthèses) :
- **Statuts** : VALIDE, TELECHARGE, NON CONFORME
- **Colonnes** : case à cocher, Nom du document, Type de document, Déposé le, Action (télécharger, voir)
- **Boutons** : Télécharger ZIP et Télécharger Certificat (selon les coches)
- **Fichier** : `useValidatedDocumentsRows()` - Combine VALIDATED et DOWNLOADED avec vérification conformité
3. **"Documents envoyés"** (sans nombre entre parenthèses) :
- **Statuts** : ENVOYE, NON CONFORME
- **Colonnes** : case à cocher, Nom du document, Statut, Déposé le, Action (télécharger, supprimer)
- **Boutons** : Télécharger ZIP et Télécharger Certificat (selon les coches)
- **Fichier** : `useSentDocumentsRows()` - Filtre SENT avec vérification conformité
**Homogénéisation Documents envoyés (2026-03)** : Le notaire envoie de la même façon aux clients, tiers et notaires invités (emails différents selon le type). Affichage centralisé via `getSentDocumentsForTab()` : clients=DocumentsNotary, tiers=Documents(third_party_depositor), invités=Documents(shared_to_office). Envoi unifié via POST /notary/documents_notary/send (un appel par destinataire).
**Modifications techniques** :
- Suppression du compteur de progression dans `DocumentTablesHeader`
- Suppression des nombres entre parenthèses dans les titres des sections
- Ajout de cases à cocher pour la sélection multiple dans tous les tableaux
- Intégration de la vérification de conformité dans tous les hooks de génération de lignes
- Support des documents `DocumentNotary` avec statut DOWNLOADED dans "Documents validés"
**Fichiers créés** :
- `ClientView/DocumentTables/helpers/documentConformity.ts` : Fonctions de vérification de conformité
**Fichiers modifiés** :
- `ClientView/DocumentTables/index.tsx` : Réorganisation des sections et ajout des boutons pour documents envoyés
- `ClientView/DocumentTables/hooks/useDocumentRows.tsx` : Refonte complète des hooks pour les nouveaux tableaux
- `ClientView/DocumentTables/helpers/tableHeaders.ts` : Mise à jour des en-têtes de tableaux
- `ClientView/DocumentTables/components/DocumentTablesHeader.tsx` : Suppression du compteur
- `ClientView/DocumentTables/components/ValidatedDocumentsSection.tsx` : Suppression du nombre dans le titre
### Unification identité onglets membres (2026-02-26)
**Page** : `/folders/[folderUid]` (vue notaire gestionnaire, `ClientView`)
**Objectif** : unifier lidentité des onglets membres (`customer`, `third_party`, `shared_notary`) et centraliser la résolution didentité pour la sélection donglet, la synchronisation URL et la validation des onglets.
**Root cause** : longlet `shared_notary` utilisait selon les zones soit lidentité de partage (`sharing.uid`), soit lUID doffice invité (`shared_to_office.uid`). Cette divergence pouvait créer des collisions didentité donglets et des comportements non homogènes.
**Correctifs** :
- Centralisation de lidentité membre dans un helper dédié :
- `FolderInformation/ClientView/helpers/participantTabIdentityHelpers.ts`
- `getParticipantTabMemberUid(...)` pour lidentité de sélection/navigation.
- `getSharedNotaryOfficeUid(...)` pour le contexte de fetch des documents.
- Centralisation de la construction des paramètres de navigation donglet :
- `FolderInformation/ClientView/helpers/participantTabNavigationHelpers.ts`
- `buildParticipantTabNavigationParams(...)` pour construire `tabNavigationParams`.
- `buildParticipantTabQueryPatch(...)` pour la mise à jour `router.query` sans logique locale dupliquée.
- `buildParticipantTabLogKey(...)` pour la construction unique des clés de logs par onglet (`client-*`, `thirdparty-*`, `shared-*`).
- `normalizeParticipantTabNavigationParams(...)` pour produire un objet stable mutualisé (plus de normalizer local dans les hooks de data loading).
- sappuie sur `Utils/participantTabNavigationHelpers.ts` pour mutualiser extraction query, patch query, sérialisation URL et log key.
- Alignement de la sélection et du query param `shareUid` :
- `FolderInformation/ClientView/helpers/participantTabsSelectionHelpers.ts`
- `shareUid` est désormais écrit avec lidentité membre (`sharing.uid`/`id`).
- compatibilité maintenue pour anciens liens `shareUid=<shared_to_office.uid>` en lecture.
- sur les futurs flux de navigation donglets membres, utiliser systématiquement `extractParticipantTabNavigationParamsFromQuery(...)` + `appendParticipantTabQueryToPath(...)` (interdiction de mapping local `customerUid/thirdPartyUid/shareUid`).
- flux migrés : `ClientDashboard/ViewDocumentsNotary/helpers/navigationHelpers.ts`, `Folder/ViewDocuments/helpers/viewDocumentsBackUrlHelpers.ts`, `Folder/AskDocuments/hooks/helpers/askDocumentsNavigationHelpers.ts`.
- Alignement de la validation donglets :
- `FolderInformation/ClientView/helpers/participantTabsValidationHelpers.tsx`
- détection UID manquant/dupliqué basée sur le helper didentité central.
- Alignement du rendu des tableaux documents :
- `FolderInformation/ClientView/components/ParticipantDocumentTables.tsx`
- clé de rendu shared notary basée sur lidentité membre.
- `tabNavigationParams.shareUid` basé sur lidentité membre.
- contexte de fetch conservé sur lUID doffice invité (`shared_to_office.uid`).
- les modules `DocumentTables/*` réutilisent désormais le type partagé `ParticipantTabNavigationParams` au lieu de signatures inline.
### Retour sur l'onglet membre après modification (2026-02-27)
**Objectif** : Après validation ou annulation lors de la modification des informations d'un membre (client, tiers, notaire invité), revenir sur l'onglet du membre concerné.
**Correctifs** :
- `backwardPath` des pages d'édition (UpdateClient, UpdateThirdParty, UpdateSharedNotary) inclut désormais les paramètres de requête d'onglet (`customerUid`, `thirdPartyUid`, `shareUid`) via `appendParticipantTabQueryToPath`.
- Ajout de `appendQueryParam(path, key, value)` dans `Utils/participantTabNavigationHelpers.ts` pour gérer correctement l'ajout de `refresh` lorsque l'URL contient déjà des paramètres.
- Documentation : section « Retour sur l'onglet membre après modification » dans ce document.
---
### Correctifs flux invité notaire et ZIP validés (2026-03-02)
**Contexte invité notaire (téléchargement document validé)** :
- Le flux invité notaire pouvait appeler l'API notaire (`/v1/notary/files/download`) au lieu du chemin client/guest, ce qui provoquait un 401/403 et une déconnexion côté front.
- Le paramétrage est aligné pour traiter l'invité notaire comme un flux client/tiers sur le téléchargement de document validé :
- `InvitedView/documentTableHelpers.tsx` : `downloadValidatedDocument(..., { isCustomerOrThirdParty: true })`
- `InvitedView/InvitedDocumentsSection.tsx` : `ValidatedDocumentsListWrapper` avec `isCustomerOrThirdParty={true}`
- `ClientView/DocumentTables/hooks/useValidatedDocumentsRows.ts` : `resolvedContext.isInvitedNotary` inclus dans `isCustomerOrThirdParty`
**Contexte ZIP documents validés** :
- Le suffixe ` (validé)` pouvait être dupliqué dans certains noms de fichiers ZIP (ex: `... (validé).aplc (validé).pdf`).
- La normalisation du suffixe est centralisée et mutualisée :
- réutilisation de `addValidatedSuffixToFileName()` depuis `src/front/Utils/zipValidatedSuffixHelper.ts`
- suppression de la logique locale redondante dans `src/front/Utils/zipDownloadHelpers/zipStructureHelpers.ts`
- Règle unique : ne pas réappliquer un suffixe déjà normalisé (`... (validé).aplc.pdf`).
---