Story OP-016: Frontend — Annulation campagne (modale + cleanup)¶
Module: operator-console Slice: Architecture §11 OP-004a (frontend) Side: [OPERATOR] Version target: V0.0.3 Priority: 17 Depends on: OP-009 (vue ENVOYÉE), OP-012 (POST /cancel backend) Can develop concurrently with: OP-017, OP-018, OP-019 Merge order: After OP-012 + OP-009 Estimated complexity: S PRD User Stories: US-OP-07 AC1+AC2 (annulation), FR-OP-05 Wireframe: docs/wireframes/operator-console/OP-016/ (brief design §4.7 modale annulation)
Objective¶
Activer le bouton « ⋯ Annuler la campagne » (placeholder OP-009) sur la vue ENVOYÉE et la vue BROUILLON. Modale de confirmation avec compteur d'impact « X liens seront révoqués » (US-OP-07 AC1) ; sur confirmation, POST /cancel, toast succès, redirection vers liste.
Backend Scope¶
Consomme POST /api/operator/campaigns/{id}/cancel (OP-012). Pour calculer le compteur d'impact AVANT confirmation, consomme GET /campaigns/{id}/status (OP-006) et calcule nonTerminalCount = total - paye - regleHorsPlat - exclu - lienRevoque.
Frontend Scope¶
Components¶
Sous frontend-operator/src/features/campaigns/cancel/:
CancelCampaignButton.tsx— bouton kebab/dropdown item visible sirole==cabinet_adminETstatus ∈ {BROUILLON, ENVOYÉE}. Caché ailleurs.CancelCampaignModal.tsx— modale de confirmation :- Calcule
nonTerminalCountvia status. - Affiche : « {N} lien(s) seront révoqués. Les clients qui cliqueront sur leur lien verront : « Ce lien n'est plus valide. Veuillez contacter votre cabinet. » Cette action est irréversible. »
- Boutons :
[Non, garder](secondary) +[Oui, annuler](danger). - Sur confirm : POST /cancel ; spinner ; toast success « Campagne annulée. {N} lien(s) révoqués. » ; redirect vers
/campagnes+ invalidation queries. useCancelCampaign.ts— mutation React Query.
UI States¶
| State | Behavior | French Copy |
|---|---|---|
| Loading | Modale en spinner pendant POST | — |
| Empty | N/A | — |
| Error 502 (AUTH down) | InlineBanner rouge dans modale + retry | « Service d'authentification indisponible. La campagne n'a pas été annulée. [Réessayer] » |
| Error 400 | InlineBanner | message backend |
| Offline | Bouton « Oui, annuler » désactivé + tooltip | « Indisponible hors-ligne. » |
| Success | Toast 4s + redirect | « Campagne annulée. {N} lien(s) révoqués. » |
Responsive Behavior¶
- Modale centrée 480 px desktop, 90 % largeur tablet.
Interactions¶
- Esc ferme la modale (sans annuler la campagne).
- Focus trap.
- Bouton danger en rouge (token
--color-danger). - Modale block-listener empêche fermeture par click outside (action destructive).
Acceptance Criteria¶
AC-001: Modale affiche le compteur de liens à révoquer (US-OP-07 AC1)
Given une campagne ENVOYÉE avec 16 cc non-terminaux
When je clique "⋯ Annuler la campagne" → modale ouvre
Then la modale affiche "16 liens seront révoqués"
And le bouton "Oui, annuler" est en danger (rouge).
AC-002: Confirmation déclenche POST /cancel + redirect (US-OP-07 AC2)
Given la modale est ouverte avec 16 liens
When je clique "Oui, annuler"
Then POST /campaigns/{id}/cancel est appelé
And toast "Campagne annulée. 16 liens révoqués." s'affiche 4s
And je suis redirigé vers /campagnes
And la liste est mise à jour (statut ANNULÉE visible).
AC-003: Erreur 502 AUTH → message dédié, campagne intacte
Given AUTH down (mock)
When je confirme l'annulation
Then la modale affiche "Service d'authentification indisponible. La campagne n'a pas été annulée. [Réessayer]"
And aucune redirection
And la campagne reste ENVOYÉE.
AC-004: agency_operator ne voit pas le bouton
Given je suis agency_operator
When je charge /campagnes/{id} (ENVOYÉE)
Then aucun bouton "Annuler" n'apparait dans le header ni dans le kebab.
Compliance Rules¶
- FR-OP-05 + US-OP-07 : modale avec compteur d'impact, irréversible.
VÉRIFIÉ. - PRD design §4.7 : exact wording.
VÉRIFIÉ.
Standards & Conventions¶
docs/standards/design-system.md— Modal, Button danger variant.
Testing Requirements¶
Unit Tests¶
CancelCampaignModalTest: focus trap, Esc, danger button, RBAC visibility.
Integration Tests¶
- Playwright
cancel-flow.spec.tsAC-001..AC-004.
What QA Will Validate¶
- A11y : annonces SR sur ouverture modale.
- Rendu responsive.
Out of Scope¶
- Annulation côté backend → OP-012.
- Restauration campagne annulée → out-of-scope V1.
Definition of Done¶
- [ ] Bouton "Annuler" actif pour cabinet_admin sur BROUILLON+ENVOYÉE
- [ ] Modale conforme design §4.7
- [ ] AC-001..AC-004 passent
- [ ] 5 états UI implémentés
- [ ] Toast + redirect + invalidation
- [ ] Tests verts