Aller au contenu

Story OP-017: Frontend — Bulk exclude (action bar) + modale hors-plateforme

Module: operator-console Slice: Architecture §11 OP-004b (frontend) Side: [OPERATOR] Version target: V0.0.3 Priority: 18 Depends on: OP-008 (BROUILLON vue + DataTable + Drawer), OP-009 (ENVOYÉE vue + MenuDropdown), OP-013 (bulk-exclude + mark-offplatform backend) Can develop concurrently with: OP-016, OP-018, OP-019 Merge order: After OP-013 Estimated complexity: M PRD User Stories: US-OP-04 AC4 (bulk exclude), US-OP-06 AC1+AC2+AC3 (HP), FR-OP-08 Wireframe: docs/wireframes/operator-console/OP-017/ (brief design §4.6 action bar + §4.7 HP modale)


Objective

Ajouter deux actions : 1. Sur la vue BROUILLON : action bar bottom qui apparait quand ≥ 1 row cochée, avec bouton « Exclure les {N} ». 2. Sur la vue ENVOYÉE : kebab menu item « Régler hors-plateforme » qui ouvre une modale (méthode, date, montant, référence), avec audit + flip status.


Frontend Scope

Components

Sous frontend-operator/src/features/campaigns/:

  • Bulk exclude (vue BROUILLON, étend OP-008) :
  • ContractsTable.tsx : active les Checkbox par row + checkbox header « tout sélectionner ».
  • BulkActionBar.tsxnouvelle ici — apparait sticky bottom quand selectedCount > 0 :
    • Texte : « {N} sélectionnés ».
    • Bouton « Exclure les {N} » → ouvre BulkExcludeModal.
    • Bouton « Désélectionner ».
  • BulkExcludeModal.tsx — confirme l'action :

    • Texte : « Exclure {N} contrat(s) ? Cette action retire les contrats de la campagne avant envoi. »
    • Champ optionnel : Raison (facultatif) textarea ≤ 500 chars.
    • Boutons : [Annuler] + [Exclure] (primary).
    • Sur confirm : POST /campaigns/{id}/contracts/bulk-exclude ; toast « {N} contrat(s) exclus. » ; refresh table.
  • Marquage hors-plateforme (vue ENVOYÉE, étend OP-009) :

  • ContractsSentTable.tsx : active item « Régler hors-plateforme » dans le kebab pour cc en statuts NOTIF_EN_ATTENTE/NOTIF_LIVRÉ/NOTIF_ÉCHOUÉ/LIEN_OUVERT/LIEN_EXPIRÉ/PAIEMENT_ÉCHOUÉ (TD-3).
  • HorsPlateformeModal.tsx — formulaire FR-OP-08 :

    • Radio buttons : Mobile Money | Espèces | Chèque | Virement.
    • DatePicker (réutilise OP-008) : date de paiement ≤ today.
    • Input montant XOF (entier) — validation client > 0 && integer.
    • Input référence (optionnel, ≤ 200 chars).
    • Info box : « Cette action est définitive et journalisée. »
    • Boutons : [Annuler] + [Enregistrer le paiement].
    • Sur confirm : POST /campaigns/{id}/contracts/{ccId}/mark-offplatform ; toast « Paiement hors-plateforme enregistré. » ; refresh row + KPI strip.
  • useBulkExclude.ts + useMarkOffPlatform.ts — mutations.

UI States

BulkActionBar : | State | Behavior | French Copy | |-------|----------|-------------| | Idle (0 selected) | Masquée | — | | Visible (N selected) | Slide-in 200ms bottom | « {N} sélectionnés » | | Loading | Boutons disabled + spinner | — | | Offline | Boutons grisés | « Indisponible hors-ligne. » | | Success | Slide-out + reset selection | toast |

HorsPlateformeModal : | State | Behavior | French Copy | |-------|----------|-------------| | Loading (submit) | Boutons disabled | — | | Error validation | InlineBanner sous champ | « Le montant doit être supérieur à 0. » / « Le montant doit être un entier (pas de décimale). » | | Error server | InlineBanner top | message backend | | Offline | Modale grisée | — | | Success | Toast 4s + close modale | « Paiement hors-plateforme enregistré. » |

Responsive Behavior

  • BulkActionBar : pleine largeur sous le contenu sur tous breakpoints.
  • HorsPlateformeModal : 480 px desktop, 90 % tablet.

Interactions

  • Bulk : sélection multiple avec Shift+click range select (UX standard).
  • Modale HP : Tab order radios → date → amount → reference → annuler → enregistrer.
  • Validation client AVANT submit (montant entier > 0).

Acceptance Criteria

AC-001: Action bar apparait avec 1+ sélection (US-OP-04 AC4)
Given je suis sur /campagnes/{id} BROUILLON avec 10 cc
When je coche 3 rows
Then la BulkActionBar apparait sticky bottom avec "3 sélectionnés" et bouton "Exclure les 3"
When je décoche toutes les rows
Then la BulkActionBar disparait.

AC-002: Bulk exclude flip statuts (US-OP-04 AC4)
Given 3 rows cochées
When je clique "Exclure les 3" puis "Exclure" dans la modale
Then POST bulk-exclude est appelé avec les 3 ccIds
And toast "3 contrat(s) exclus." s'affiche
And les 3 rows passent à statut EXCLU dans la table.

AC-003: Modale HP saisie complète + audit (US-OP-06 AC1+AC2)
Given un cc NOTIF_LIVRÉ
When kebab → "Régler hors-plateforme" → modale ouvre
And je sélectionne Mobile Money, date 22/05/2026, montant 85000, je confirme
Then POST mark-offplatform appelé
And toast "Paiement hors-plateforme enregistré."
And le cc passe à statut RÉGLÉ_HORS_PLATEFORME dans la table.

AC-004: Validation montant — float refusé client-side
Given je tape 85000.5 dans le champ montant
When je clique "Enregistrer le paiement"
Then InlineBanner "Le montant doit être un entier (pas de décimale)."
And aucun POST n'est émis.

AC-005: HP item disabled si statut interdit (US-OP-06 AC3 / TD-3)
Given un cc PAYÉ
When j'ouvre le kebab
Then "Régler hors-plateforme" est grisé avec tooltip "Action non disponible pour ce statut."

Compliance Rules

  • FR-OP-08 : précondition + champs + audit. VÉRIFIÉ.
  • US-OP-06 AC3 : disable si PAYÉ. VÉRIFIÉ.
  • Critical rule #2 : amount entier strict client+server. VÉRIFIÉ.

Standards & Conventions

  • docs/standards/design-system.md — BulkActionBar pattern, Modal tokens.
  • docs/standards/react-typescript-guidelines.md — React Hook Form + Zod.

Testing Requirements

Unit Tests

  • BulkActionBarTest : apparition conditionnelle.
  • HorsPlateformeModalTest : validation client, méthodes enum, DatePicker.

Integration Tests

  • Playwright bulk-exclude.spec.ts AC-001 + AC-002.
  • Playwright hors-plateforme.spec.ts AC-003..AC-005.

What QA Will Validate

  • Bulk : Shift+click range select fonctionne.
  • HP modale : Tab order conforme.
  • A11y : annonces SR sur ouverture/fermeture.

Out of Scope

  • Backend bulk-exclude + HP → OP-013.
  • Rappel + renvoi lien → V1.

Definition of Done

  • [ ] BulkActionBar + BulkExcludeModal mergés
  • [ ] HorsPlateformeModal merged
  • [ ] AC-001..AC-005 passent
  • [ ] Validation client montant entier > 0
  • [ ] HP item disabled selon TD-3
  • [ ] 5 états UI implémentés
  • [ ] Tests verts