Skip to content

feat: implement send email on release notes publish - #102

Merged
viv-helix merged 5 commits into
release-ulmofrom
feat/TNL2-584
Jun 11, 2026
Merged

feat: implement send email on release notes publish#102
viv-helix merged 5 commits into
release-ulmofrom
feat/TNL2-584

Conversation

@viv-helix

@viv-helix viv-helix commented Jun 4, 2026

Copy link
Copy Markdown
Member

Adds opt-in email notification support to the Release Notes publish flow. When a user with the appropriate permission publishes or edits a release note, they can now opt in to send an email notification to all course authors on the platform. This PR also introduces a token-based unsubscribe flow, allowing recipients to unsubscribe from future release note emails via a dedicated page.


Changes

Feature: Send Email on Publish

  • Added a sendEmail Formik field (default: false) to ReleaseNoteForm with a permission-gated checkbox (canSendReleaseNoteEmails).
  • The checkbox is labelled "Send email notification to all course authors" with supporting help text explaining its effect.
  • On submit (both create and edit), sendEmail is extracted from form data, stripped from the note payload, and remapped to send_email_on_publish before being sent to the API. Defaults to false when absent.

Data Layer: canSendReleaseNoteEmails Capability

  • The fetchReleaseNotesQuery thunk now reads canSendReleaseNoteEmails from the API response and includes it in the fetchReleaseNotesSuccess dispatch payload.
  • Redux slice (slice.js) initializes canSendReleaseNoteEmails: false and stores it on fetch success.
  • New selector getCanSendReleaseNoteEmails added to selectors.js.
  • useReleaseNotes hook updated to expose canSendReleaseNoteEmails via useSelector, and it is passed down through ReleaseNotes.jsx into ReleaseNoteForm.

Feature: Unsubscribe Page

  • New ReleaseNoteUnsubscribe component at src/release-notes/unsubscribe/ implementing a 4-state UI: idleloadingsuccess / error.
  • Token is read from the ?token= query param. If absent, an error alert is shown immediately without rendering the confirmation card.
  • On confirmation, calls unsubscribeFromReleaseNoteEmails(token) (new API helper) which issues an authenticated GET to /api/release_notes/v1/email/unsubscribe/?token=<encoded>.
  • Error state includes a retry button (outline-primary).
  • New route /release-notes/unsubscribe registered in src/index.jsx — intentionally outside the ENABLE_RELEASE_NOTES feature flag gate so unsubscribe links remain functional for all users regardless of flag state.
  • New i18n message keys added in unsubscribe/messages.js: title, confirmation prompt, button label, disclaimer, processing text, success heading/body, error heading/body, retry label.

API

  • New URL helper getUnsubscribeApiUrl() pointing to /api/release_notes/v1/email/unsubscribe/.
  • New exported function unsubscribeFromReleaseNoteEmails(token) — makes an authenticated GET with the token URL-encoded, returns a camelCased response object.

Notes

  • The unsubscribe route is not wrapped in the ENABLE_RELEASE_NOTES config gate, by design — email recipients need to be able to reach the unsubscribe page even if the release notes feature is toggled off for their instance.
  • sendEmail defaults to false on form initialization; it is a one-time flag per publish action and is not persisted back to the form on re-open.

JIRA: TNL2-584

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds opt-in email notifications when publishing release notes, and introduces a token-based unsubscribe flow for those emails. This extends the existing release-notes Redux/data layer and UI to support a “send email” flag and a new unsubscribe route/page.

Changes:

  • Add a “Send email notification…” checkbox to the release note publish/edit form (behind a permission flag) and include sendEmail in the submit payload.
  • Plumb a new canSendReleaseNoteEmails capability from the release-notes API response through Redux selectors/hooks into the UI.
  • Add /release-notes/unsubscribe route, page UI/state machine, API helper, and tests for token-based unsubscribe.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/release-notes/update-form/ReleaseNoteForm.test.jsx Adds checkbox rendering/toggling and submit-payload tests for sendEmail.
src/release-notes/update-form/ReleaseNoteForm.jsx Adds canSendReleaseNoteEmails prop, Formik sendEmail field, checkbox UI, and submit payload field.
src/release-notes/unsubscribe/ReleaseNoteUnsubscribe.test.jsx New tests covering token presence, success, failure + retry flows.
src/release-notes/unsubscribe/ReleaseNoteUnsubscribe.jsx New unsubscribe page component with idle/loading/success/error states.
src/release-notes/unsubscribe/messages.js New i18n strings for the unsubscribe page.
src/release-notes/ReleaseNotes.test.jsx Updates hook mock shape to include canSendReleaseNoteEmails.
src/release-notes/ReleaseNotes.jsx Passes canSendReleaseNoteEmails into ReleaseNoteForm.
src/release-notes/messages.js Adds i18n strings for the send-email checkbox label/help text.
src/release-notes/hooks.jsx Exposes canSendReleaseNoteEmails from Redux via selector.
src/release-notes/data/thunk.test.js Adds coverage for canSendReleaseNoteEmails and send_email_on_publish mapping behavior.
src/release-notes/data/thunk.js Reads canSendReleaseNoteEmails from fetch response; maps sendEmail to send_email_on_publish for create/edit.
src/release-notes/data/slice.js Adds canSendReleaseNoteEmails to state and stores it on fetch success.
src/release-notes/data/selectors.js Adds selector for canSendReleaseNoteEmails.
src/release-notes/data/api.test.js Adds API test for unsubscribeWithToken.
src/release-notes/data/api.js Adds unsubscribe endpoint URL + unsubscribeWithToken API helper.
src/index.jsx Adds route for /release-notes/unsubscribe.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 207 to 210
publishDate: initialValues.published_at ? moment(convertToDateFromString(initialValues.published_at)).format('YYYY-MM-DD') : '',
publishTime: initialValues.published_at ? moment(initialValues.published_at).format(TIME_FORMAT) : '',
sendEmail: false,
}}
Comment thread src/release-notes/data/api.js Outdated
Comment on lines +30 to +33
export async function unsubscribeWithToken(token) {
const url = `${getUnsubscribeApiUrl()}?token=${encodeURIComponent(token)}`;
const { data } = await getAuthenticatedHttpClient().get(url);
return camelCaseObject(data);
Comment on lines +84 to +88
actions={[
<Button variant="outline-primary" onClick={handleUnsubscribe}>
{intl.formatMessage(messages.unsubscribeRetry)}
</Button>,
]}
@viv-helix viv-helix changed the title feat: implement send email for release notes publish feat: implement send email on release notes publish Jun 11, 2026
@viv-helix
viv-helix merged commit 3caa2a2 into release-ulmo Jun 11, 2026
4 checks passed
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.

3 participants