feat(my-account): build v2 prototype modals (Phase 5)#4681
Merged
thomasguillot merged 4 commits intoApr 28, 2026
Conversation
…r.js Pre-Phase 5 cleanup. Newsletters / donations / subscriptions all carried identical copies of `ensureSnackbarContainer` + `snackbar`; Phase 5 modals make a third caller. Per the cross-phase devlog rule-of-three commitment, factor into `src/my-account/v2-demo/util/snackbar.js` and import from there. No behaviour change.
Five remaining modal flows from the brief, each as its own partial under `templates/v2-demo/partials/`: - cancel-subscription-modal.php — confirmation pattern (init + success). - renew-subscription-modal.php — transaction pattern + success state. - cancel-donation-modal.php — same shape as cancel-subscription. - restart-donation-modal.php — transaction pattern (no success state). - modify-donation-modal.php — frequency + amount editor with live totals. Detail templates load partials behind the same status guards their headers already branch on. The list-page renders the renew modal alongside any expiring sub in the active bucket so the inline 'renew now' anchor opens the modal once Phase 6 fixtures swap one in. donations.js / subscriptions.js trade the per-action snackbar switch for a slug-map dispatcher (`tryOpenModal` / `tryOpenDonationModal`); each opens `newspack-my-account__<slug>-<id>` and toggles `data-state` to 'open'. Confirmation modals reset to init via the `closeModal` event. Modify-donation recomputes totals declaratively as the amount changes. `update-payment-method` stays a stub snackbar — the brief lumps it with the v1 checkout flow, not a Phase 5 modal. Devlog Phase 5 entry + cross-phase decision log rows added.
…o Phase 7 Mid-Phase-5 scope addition: reproduce v1's `/my-account/payment-methods/` page byte-for-byte under the v2-demo flag, fed by fake data — no new design, no new components. Closes a credibility gap (the v1 surface exists today and readers see it; the prototype had no story there). Brief §3 grows from three to four primary surfaces (newsletters / donations / subscriptions / payment methods). Brief §10 gains a new Phase 6 entry; the previous Phase 6 (polish + scenario fixtures) becomes Phase 7. §12 definition-of-done updated to "five primary screens." Devlog adds the Phase 6 / Phase 7 stubs and a cross-phase decision row. Historical entries' Phase 6 references (scenario fixtures, polish, etc.) are left as-is; the decision row dates the renumbering so the timeline stays auditable.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR advances the My Account v2 demo prototype (Phase 5) by replacing remaining “stub snackbar” actions on donation/subscription detail screens with real, status-guarded modal flows, and by extracting a shared snackbar utility used across v2-demo screens.
Changes:
- Added Phase 5 modal partials for cancel/renew subscription and cancel/restart/modify donation flows, with JS wiring for step transitions and close/reset behavior.
- Refactored per-screen snackbar helpers into a shared
src/my-account/v2-demo/util/snackbar.jsutility and updated callers. - Updated prototype documentation/roadmap to introduce Phase 6 (Payment methods) and renumber subsequent phases.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/my-account/v2-demo/util/snackbar.js | New shared snackbar helper used by multiple v2-demo screens. |
| src/my-account/v2-demo/subscriptions.js | Reworked click handling into an action router; added modal wiring for cancel/renew flows; switched to shared snackbar. |
| src/my-account/v2-demo/donations.js | Added modal wiring for cancel/restart/modify donation; switched to shared snackbar. |
| src/my-account/v2-demo/newsletters.js | Switched to shared snackbar helper. |
| includes/.../templates/v2-demo/subscriptions.php | Renders renew-subscription modal(s) for expiring active list rows (forward-compat). |
| includes/.../templates/v2-demo/subscription-details.php | Loads cancel/renew modal partials based on subscription status guards. |
| includes/.../templates/v2-demo/donation-details.php | Loads modify/cancel/restart donation modal partials based on donation status guards. |
| includes/.../partials/renew-subscription-modal.php | New two-step renew subscription modal (init → success) with billing/payment markup. |
| includes/.../partials/cancel-subscription-modal.php | New two-step cancel subscription confirmation modal (init → success). |
| includes/.../partials/modify-donation-modal.php | New modify donation modal with segmented control and JS-driven totals recompute. |
| includes/.../partials/cancel-donation-modal.php | New two-step cancel donation confirmation modal (init → success). |
| includes/.../partials/restart-donation-modal.php | New restart donation transaction modal terminating on snackbar. |
| docs/my-account-v2-prototype-devlog.md | Added Phase 5 entry and roadmap renumbering notes. |
| docs/my-account-v2-prototype-brief.md | Updated scope/roadmap to include Payment methods as Phase 6 and adjust estimates/DoD. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Three issues flagged on PR #4681: - subscriptions.js: `handleActionClick` was unconditionally calling `preventDefault()` on any anchor with a `data-action`, which would break the list-page "Manage subscription" link (`<a data-action="manage-subscription" href=".../subscriptions/<id>/">`) by suppressing real navigation when no modal handler matches. Move `preventDefault()` inside the handled paths so unhandled actions let the trigger behave naturally. - modify-donation-modal.php: the amount input used `number_format_i18n()` for both `value` and `data-initial-amount`. In comma-decimal locales this produces "9,99", which JS `parseFloat` truncates to 9 — breaking the live totals math and confirm-button enable/disable. Switch to dot-decimal `number_format($amount, 2, '.', '')` for the machine-readable value (display-only strings keep i18n). - renew-subscription-modal.php / restart-donation-modal.php: the `<div id="payment">` would duplicate IDs when multiple modals render on the same page (the brief's forward-compat for Phase 6 fixtures puts more than one renew modal on the list view) and could collide with WC's own checkout markup elsewhere. Suffix with the resource id.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
All Submissions:
Changes proposed in this Pull Request:
Phase 5 of the My Account v2 prototype (umbrella tracker: #4679; targets
prototype/my-account-demo, nottrunk). Promotes the five remaining stub-snackbar triggers on the?v2-demo=1donation and subscription detail pages to real modals. Each modal lives at the bottom of its detail (or list) template behind a status guard, keyed by resource id, and matches the corresponding Figma frame:2636:46259→2636:46262.)2636:46276→2636:46269.)2636:46591→2636:46550.)2636:46530.)2636:46578.)The detail-page click handler in
donations.js/subscriptions.jsis rewritten as a small action-router (tryOpenModal(action, id, root)): it looks upnewspack-my-account__<slug>-<id>and togglesdata-state="open"if the modal exists, otherwise the click falls through to a snackbar fallback forupdate-payment-method(the only Phase 5 stub left — the brief lumps it with the v1 checkout flow). The same handler covers the inline "renew now" anchor inside the expiring-subscription notice on both list and detail pages.The shared snackbar helper that newsletters / donations / subscriptions all carried as identical copies has been extracted into
src/my-account/v2-demo/util/snackbar.jsper the cross-phase rule-of-three commitment. The refactor lands as its own no-op commit ahead of the modal code so the diff stays reviewable.This PR also updates the roadmap to insert a new Phase 6 — Payment methods (reproduce v1's
/my-account/payment-methods/byte-for-byte under the demo flag, fed by fake data — no new design); the previous Phase 6 (polish + scenario fixtures) becomes Phase 7. Brief §3 / §10 / §12 + devlog updated; historical Phase 6 references in earlier devlog entries are left in place because the new cross-phase decision row dates the renumbering, preserving the timeline.update-payment-methodis intentionally not a Phase 5 modal; building one would either duplicate the renew/restart payment forms or pretend to mutate state. Phase 6 / productisation will resolve.How to test the changes in this Pull Request:
?v2-demo=1to any/my-account/...URL./my-account/subscriptions/sub-001/?v2-demo=1. Open the More dropdown next to the page header. Click Cancel subscription: a small modal opens with "Are you sure?", an active-until date in bold ("March 16, 2027"), a destructive Cancel CTA, and a ghost "Keep subscription". Click Cancel: the modal flips to a success step (green check + "Your subscription has been successfully cancelled." + the reader's email in bold + a Done button). Close via Done, the X button, or the overlay. Re-open: it should show the init step again (state resets on close)./my-account/subscriptions/sub-cancelled/?v2-demo=1. Click Renew subscription: the modal shows a summary box ("Patron: $101.70 / year"), a Pay-now CTA, a billing-details readout (John Lewis address), and a Stripe-style payment form (radio + card/expiry/CVC inputs + cover-fees checkbox). Click Pay now: flips to a "Thank you" success step./my-account/subscriptions/sub-expiring/?v2-demo=1. Confirm the inline error notice's "renew now" anchor opens the same Renew modal as step 4 (instead of the previous stub snackbar). The header Renew subscription button does the same thing./my-account/donations/don-001/?v2-demo=1. Click Edit donation: a modal opens with a Frequency segmented control (Monthly / Annually preselect matches the donation's current frequency), an editable amount input, a "Cover transaction fees?" checkbox, and a Recurring totals box (Subtotal / VAT / Transaction fee / Recurring total + next-donation date). Edit the amount: subtotal/VAT/total all update live. Toggle the cover-fees checkbox: the transaction fee row flips between—and$X.XX. Switch to Annually: the unit suffix in the amount label and total flips to "/ year". Click Confirm donation: the modal closes and a "Donation modified." snackbar appears./my-account/donations/don-cancelled/?v2-demo=1. Click Restart donation: modal opens with "Donate Annually: $153.00" summary, a Restart donation CTA, billing readout, and the Stripe-style form. Click Restart: snackbar ("Donation restarted.") and the modal closes (no success step in Figma for restart).manage_options.npm run lint:php,npm run lint:js -- src/my-account/v2-demo/, andnpm run lint:scss -- 'src/my-account/v2-demo/**/*.scss'— all should pass.npm run build— should complete with no new errors.docs/my-account-v2-prototype-brief.mdand confirm §3 lists four primary surfaces (newsletters / donations / subscriptions / payment methods), §10 has Phase 6 (payment methods) before Phase 7 (polish), and §12 says "five primary screens".Other information: