gigafibre-fsm/apps/ops/src
louispaulb 672188bab9 feat(ops/campaigns): explicit contact↔shortlink pairing review before approve
Step 2 of the new-campaign wizard previously dropped unpaired contacts
silently (Math.min(contacts, gifts) iteration) — if you uploaded 5
contacts and 3 gift links, you got 3 recipients in the table with no
visible signal that 2 contacts were left out. Step 1 only showed
"contacts skipped: N" in a small banner, easy to miss.

Surface the imbalance explicitly so the user can decide before sending:

Backend (POST /campaigns/parse):
- Return unpaired_contacts[] and unused_gifts[] arrays (with row_index
  for source-CSV cross-reference), in addition to the existing
  recipients[]. Old leftover_gifts / leftover_contacts counters kept
  for backward compat.

UI (CampaignNewPage Step 2):
- New columns in the recipients table:
  • # (row index from the source CSVs)
  • Lien-cadeau (truncated shortlink, clickable to verify)
  These let the user eyeball the contact↔link pairing line by line.
- New counter strip:
  Paires / À envoyer / Client lié / Sans client / Sans lien / Liens surplus
- "Sans lien" and "Liens surplus" counters appear only when relevant.
- Explicit warning banner explaining what unpaired/unused means
  (acquire more links and re-upload, or proceed knowing N won't get).
- Expansion panel listing each unpaired contact with their row_index +
  details, so the user can verify which specific contacts will be
  excluded before approving.
- Expansion panel listing each unused gift URL (extra capacity).
- "Approuver" button now shows the exact send count: "Approuver — N à
  envoyer". Disabled when 0. Step 3 recap also reflects sendableCount.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 20:31:44 -04:00
..
api feat(ops/campaigns): UI module for gift campaigns + GrapesJS template editor 2026-05-21 19:08:04 -04:00
boot feat: add ops app + CONTEXT.md, simplify URL to /ops/ 2026-03-30 22:41:58 -04:00
components feat(ops): Service Contract detail view + sub-delete redirects there 2026-04-23 14:46:34 -04:00
composables fix(ops/client): cancelled subs no longer inflate monthly total + Lieu link in-app 2026-05-08 11:21:18 -04:00
config feat(ops/campaigns): UI module for gift campaigns + GrapesJS template editor 2026-05-21 19:08:04 -04:00
css feat: contract → chain → subscription → prorated invoice lifecycle + tech group claim 2026-04-22 20:40:54 -04:00
data docs: reorganize into architecture/features/reference/archive folders 2026-04-22 11:51:33 -04:00
layouts feat(ops/campaigns): UI module for gift campaigns + GrapesJS template editor 2026-05-21 19:08:04 -04:00
modules feat(ops/campaigns): explicit contact↔shortlink pairing review before approve 2026-05-21 20:31:44 -04:00
pages fix(ops/client): cancelled subs no longer inflate monthly total + Lieu link in-app 2026-05-08 11:21:18 -04:00
router feat(ops/campaigns): UI module for gift campaigns + GrapesJS template editor 2026-05-21 19:08:04 -04:00
stores fix(ops/dispatch): surface customer + service-location links from a job + fix bad coords 2026-05-08 10:29:59 -04:00
utils refactor: extract composables from 5 largest files — net -1950 lines from main components 2026-04-08 17:57:24 -04:00
App.vue feat: add ops app + CONTEXT.md, simplify URL to /ops/ 2026-03-30 22:41:58 -04:00