Skip to content

feat(newsletter): Member subscription self management - #678

Closed
libby-correctiv wants to merge 37 commits into
mainfrom
feat/member-subscription-self-management
Closed

feat(newsletter): Member subscription self management#678
libby-correctiv wants to merge 37 commits into
mainfrom
feat/member-subscription-self-management

Conversation

@libby-correctiv

@libby-correctiv libby-correctiv commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Adds a "Subscriptions" tab to the account page where members can view and unsubscribe from individual newsletter groups. Also makes group updates safer against a narrow race condition where a group added on Mailchimp's side could get overwritten if the sync webhook is down or hasn't caught up yet.

Changes

Frontend

  • New tabbed layout on the account page (Contact Information / Security / Subscriptions)
  • New AccountNewsletterSubscriptions.vue component and locale strings
  • New GET/DELETE /contact/:id/newsletter-groups[/:groupId] endpoints + client methods
  • Added a small info message reading "Group names will be displayed to members in the subscription management tab of the Account page" to the Integrations tab in the Settings page

Backend

  • Replaced the boolean mergeGroups option with NewsletterGroupChange ('add' | 'remove' | 'replace') - add/remove now scope the Mailchimp interests payload to only the group(s) being changed, instead of reasserting the full list, to avoid overwriting a group Mailchimp already knows about that beabee's local DB hasn't caught up on yet
  • Updates without groups now omit interests from the Mailchimp payload entirely, instead of reaffirming the full list on unrelated updates
  • Add a retry limit to NewsletterService.upsertContact's invalid-group recovery - previously retried indefinitely if a group ID was permanently invalid (not just stale), silently hanging instead of surfacing an error

Testing

  • new mailchimp.test.ts covering the payload shape for add/remove/replace; newsletter.test.ts updated. yarn test passing.

Screenshots

Screenshot 2026-08-19 at 11 16 07 Screenshot 2026-08-19 at 11 16 18

Checklist before requesting a review

  • Done a self-review of my code
  • Run yarn check and addressed any problems
  • PR doesn't have merge conflicts

Checklist before merging

  • Translations for all new i18n strings

libby-correctiv and others added 30 commits August 4, 2026 13:35
bug fix - enable modal step 1 flashing up on close
bug fix - code input holes making disable button stay enabled on backspace
remove ualerts to keep input errors consistent
frontend-old must keep the pre-migration wording while apps/frontend
picks up the new copy, so changed values now live under a "-nuxt"
suffixed sibling key instead of overwriting the original. Also
restores mfa.result.successful/title and mfa.secretInput.desc, which
this branch had deleted but frontend-old still references.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nothing imports reka-ui directly; @nuxt/ui already depends on the
same version (2.9.9) transitively.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ContactUpdateAccount, SetupForm, reset-password, and the admin
contacts page are still 1:1 copies of their frontend-old counterparts
(not yet redesigned with Nuxt UI), so they should keep the original
wording like frontend-old rather than the new copy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extracts the inline copy-to-clipboard + checkmark-feedback logic in
SetMFA.vue into a reusable Nuxt UI component, mirroring AppCopyButton's
"just pass text" API. Replaces the @vueuse/core useClipboard usage,
so the dependency is no longer needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AppCodeInput's modelValue now stores raw number|undefined per box
instead of converting to strings, matching what UPinInput actually
emits. isCodeComplete (moved to utils/pin-input.ts) checks for holes
anywhere in the array, not just via .length, which previously let a
code with a backspaced middle digit pass as complete.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AppIconBadge is only used by AppSectionCard now, not modal titles;
AppModalActions' usage list was redundant elaboration. addressLine2
now matches the other delivery-address fields (plain '' default) since
none of them are unconditionally required.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…den loading state

Renames the enable-side identifiers (createMfa, createError, creating,
onCreateError, pin, showMFASettingsModal, etc.) to match the disable
side's naming (enableMfa, enableError, enabling, onEnableError,
enableToken, showEnableModal), and drops "Confirm" from the disable
modal's names to match the enable modal's shorter naming. Also wraps
the loading-state toggle in try/finally so it can't get stuck if
something unexpected throws.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Notes that the rule also applies to teleported UModal content, not
just the page root, so a future reader isn't left guessing why a
modal's <p>/<h2> picked up page-level sizing.
Replaces the two standalone refs bridged into a reactive() wrapper
(only to satisfy UForm's :state prop) with one reactive object as the
single source of truth, matching AccountForm's pattern.
@libby-correctiv
libby-correctiv requested a review from wpf500 August 19, 2026 09:31
@libby-correctiv
libby-correctiv force-pushed the feat/nuxt-ui-account-page branch from 586ed87 to 7624d96 Compare August 19, 2026 15:34
Base automatically changed from feat/nuxt-ui-account-page to main August 20, 2026 11:03
@libby-correctiv

Copy link
Copy Markdown
Contributor Author

Rebasing feat/nuxt-ui-account-page and merging it to main without rebasing this child branch caused it to show all feat/nuxt-ui-account-page's commits. Tried rebasing it onto main but was running into a lot of conflicts so I just cherry picked the relevant commits onto #679

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant