Commit Graph

4 Commits

Author SHA1 Message Date
louispaulb
5327112717 fix(campaigns/templates): clearer prorata phrasing — "mois restants" / "remaining months"
Iterating on the prorata disclaimer per user feedback. The previous
version ("tu rembourses le prorata non utilisé (20 $/mois)") still
read ambiguously — "non utilisé" could mean "the portion you haven't
spent" which is conceptually confusing for a one-time gift card, and
the hardcoded "$20/month" tied the template to the specific
$60/3-month campaign.

New phrasing makes the math explicit: refund only for the months
you're NOT staying.

FR:
  before — "Si tu résilies avant {{commitment_months}} mois,
            tu rembourses le prorata non utilisé (20 $/mois)."
  after  — "Si tu annules avant {{commitment_months}} mois,
            tu rembourses seulement au prorata des mois restants."

EN:
  before — "If you cancel before {{commitment_months}} months,
            you refund the unused pro-rated amount ($20/month)."
  after  — "If you cancel before {{commitment_months}} months,
            you only refund the prorated amount for the remaining months."

Wins:
  • Subject ("tu" / "you") explicit — no ambiguity on who refunds
  • Logic clarified — refund == months NOT STAYED, not "unused
    portion of money" (which doesn't quite map to a one-time gift)
  • Generic over campaign params — no hardcoded "$20/month" so the
    template works at any gift amount + commitment combination
  • "annules" (more common in QC consumer-facing) instead of
    "résilies" (slightly more formal/legal-sounding)

Applied via direct find/replace on .html + .json (FR + EN). Live
test-send queued to confirm rendering.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 07:50:51 -04:00
louispaulb
f37b1d2803 fix(campaigns/templates): clarify who refunds whom for early cancellation
User feedback: the prorata disclaimer was semantically wrong — both FR
("le prorata du montant est remboursable") and EN ("we'll refund the
pro-rated amount") read as if TARGO would refund the customer, when
actually the customer needs to refund the unused portion of the gift
they received if they cancel within the commitment period.

Plus: add the explicit per-month rate ($20/month at $60 / 3 months) so
the customer knows exactly what they'd owe at any cancellation date.

FR:
  before — "🪂 En cas de départ avant {{commitment_months}} mois,
            le prorata du montant est remboursable."
  after  — "🪂 Si tu résilies avant {{commitment_months}} mois,
            tu rembourses le prorata non utilisé (20 $/mois)."

EN:
  before — "🪂 If you decide to leave before {{commitment_months}}
            months, we'll refund the pro-rated amount."
  after  — "🪂 If you cancel before {{commitment_months}} months,
            you refund the unused pro-rated amount ($20/month)."

Both changes:
  • Subject clarified: customer refunds, not TARGO
  • Added explicit per-month value for transparency
  • Kept warm tone (informal "tu" / "you")
  • Mustache {{commitment_months}} preserved

Applied directly to .html + .json via string substitution (preserves
the Unlayer design tree intact except for that one phrase). The
"$20/month" figure is hardcoded for the current $60/3-month campaign;
a future {{monthly_prorata}} computed variable would generalize but
isn't needed yet.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 07:39:01 -04:00
louispaulb
d716e69ef6 feat(campaigns/templates): mirror user's FR edits to EN + drop legacy .mjml
User edited gift-email-fr in the Unlayer editor with richer marketing
copy (loyalty thanks, brand manifesto, 3.5 Gbit/s upsell, helpful CTA).
Mirror those edits to the EN template via a one-shot translation script
so the bilingual pair stays in sync for the next campaign send.

Translation strategy: plain-string find/replace mapping with FR
phrases in longest-first order to avoid partial matches. Applied to
BOTH the rendered .html (what the recipient sees) AND the .json
(Unlayer design tree — so re-opening the EN editor preserves the
matching structure).

Mapping coverage:
  • Intro paragraphs (greeting, gift announcement, loyalty thanks,
    brand manifesto, speed upsell, "we're around the corner")
  • Offer info pill (amount, instant activation, commitment)
  • CTA button labels (Activer → Redeem, Choisir → Pick)
  • Prorata refund disclaimer
  • Option 2 "do nothing" text
  • Signature ("Merci de faire rouler" → "Thanks for helping...thrive")
  • Footer contact info + "Tous droits réservés" → "All rights reserved"
  • <html lang="fr"> → <html lang="en">

23/28 translation rules matched; the 5 unused ones were for legacy
phrasing not present in the user's latest save (e.g. the old "Tu
choisis local" line that was replaced by the current intro).

Also: drop the obsolete .mjml source files. Now that Unlayer is the
canonical editor, the MJML→HTML compile pipeline is no longer used
on save (Unlayer outputs HTML directly). The .mjml files were stale
copies from the previous MJML-based editor. Removed from disk on
prod and from git history; rollback via git revert if needed.

Verified live: GET /campaigns/templates/gift-email-en returns the
translated content (9 EN markers detected in HTML). Test-send to
louis@targo.ca queued via Mailjet for visual QA.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 07:07:05 -04:00
louispaulb
448e62177e feat(campaigns): convert existing HTML templates to Unlayer JSON designs
Solve the "editor starts blank" problem by writing a one-time converter
that wraps each compiled .html template into a minimal Unlayer design
JSON (one Custom HTML block containing the entire body content). On
next editor load, Unlayer reads .json and renders the template in the
canvas — instant visual fidelity without manual reconstruction.

Strategy choice: Unlayer's "Import HTML" is a Pro-only feature. Building
a real HTML→Unlayer-blocks parser is several days of work. The minimal-
viable conversion (1 row + 1 Custom HTML block) gets the user 90% there
immediately:

  • Canvas shows the template visually (Unlayer renders the HTML)
  • Variables ({{firstname}}, {{gift_url}}, etc.) preserved as text
  • User can edit the HTML directly via the block's side panel
  • User can incrementally REPLACE the HTML block with native Unlayer
    blocks (Text, Image, Button) for any section they want decomposed —
    on their own schedule, not blocking the campaign send

New file: services/targo-hub/scripts/convert-html-to-unlayer.js
  • CLI: node scripts/convert-html-to-unlayer.js <template-name>
  • Reads templates/<name>.html, extracts <body> inner content, detects
    preheader from a hidden <div style="display:none">, builds Unlayer
    design JSON with brand-appropriate body.values (Targo Green link
    color #00C853, Plus Jakarta Sans font, F5FAF7 page background).
  • Backs up existing .json before overwriting.

Generated outputs (committed):
  templates/gift-email-fr.json — 34 KB (30 KB inner HTML + Unlayer chrome)
  templates/gift-email-en.json — 33 KB

Live verification: GET /campaigns/templates/gift-email-fr now returns
{ design: {...Unlayer JSON...} } alongside html. The editor's
onReady() callback in TemplateEditorPage detects data.design and calls
editor.loadDesign(design) → canvas populated immediately.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 06:22:47 -04:00