Skip to content

Add the newsletter subscription to the user settings#4345

Open
elisescu wants to merge 1 commit intomainfrom
fix3202
Open

Add the newsletter subscription to the user settings#4345
elisescu wants to merge 1 commit intomainfrom
fix3202

Conversation

@elisescu
Copy link
Contributor

@elisescu elisescu commented Feb 13, 2026

Summary by CodeRabbit

  • New Features

    • Newsletter toggle in Email Notifications to subscribe/unsubscribe for "New Tournaments and Platform Updates".
    • Shows current subscription status and a loading indicator while changes are applied; status is fetched from the server.
  • Localization

    • Added translations for the new message key in English, Czech, Spanish, Portuguese, Simplified Chinese and Traditional Chinese.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a newsletter subscription toggle to account email settings, client helpers for checking/unsubscribing, Mailjet-backed subscribe/check/unsubscribe server methods, parallelized fetch of subscription status, and a new localization key across six locale files.

Changes

Cohort / File(s) Summary
Localization
front_end/messages/{cs,en,es,pt,zh-TW,zh}.json
Added settingsNewTournamentsAndPlatformUpdates translation key with localized strings in six locale files.
Email Notifications Component
front_end/src/app/(main)/accounts/settings/notifications/components/email_notifications.tsx
Added newsletter checkbox UI, local state newsletterSubscribed, handleNewsletterChange wired to client actions, loading spinner, and new prop isNewsletterSubscribed.
Notifications Page
front_end/src/app/(main)/accounts/settings/notifications/page.tsx
Parallelized data fetch (posts + newsletter status) using serverMiscApi.isNewsletterSubscribed, passing isNewsletterSubscribed to EmailNotifications.
Client Actions
front_end/src/app/(main)/actions.ts
Added authenticated helpers unsubscribeFromNewsletter() and checkNewsletterSubscription() to call server APIs.
Server API Integration
front_end/src/services/api/misc/misc.server.ts
Introduced isNewsletterSubscribed(email), unsubscribeFromNewsletter(email), refactored/added subscribeToNewsletter(email), and added getMailjetConfig() with improved error logging and Mailjet request handling.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as EmailNotifications
    participant Action as ClientAction
    participant Server as serverMiscApi
    participant Mailjet

    User->>UI: toggle newsletter checkbox
    UI->>Action: updateNewsletter / checkNewsletterSubscription
    Action->>Server: subscribeToNewsletter / unsubscribeFromNewsletter / isNewsletterSubscribed
    Server->>Mailjet: Mailjet REST API call (managecontact / getcontactslists)
    Mailjet-->>Server: response
    Server-->>Action: result (success/failure, status)
    Action-->>UI: update state / show spinner or error
    UI->>User: reflect subscription state
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • ncarazon
  • cemreinanc
  • lsabor

Poem

🐰 I hopped to settings, soft and bright,
A checkbox for tournaments came into sight,
I nudged Mailjet gently, add or unbind,
Spinners twirled while subscriptions aligned,
Six languages sang — a tiny joy, well-timed.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding newsletter subscription functionality to the user settings page.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix3202

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
front_end/src/services/api/misc/misc.server.ts (1)

74-134: Network-level fetch errors propagate with unhelpful messages in subscribe/unsubscribe.

If fetch itself throws (network failure, DNS error), the caller receives a raw TypeError instead of the descriptive "Failed to (un)subscribe from newsletter" message. Consider wrapping in try-catch to normalize the error.

Proposed fix (example for unsubscribe; apply same pattern to subscribe)
   async unsubscribeFromNewsletter(email: string) {
-    const { auth, listId } = this.getMailjetConfig();
-    const url = `https://api.mailjet.com/v3/REST/contactslist/${listId}/managecontact`;
-
-    const response = await fetch(url, {
+    try {
+      const { auth, listId } = this.getMailjetConfig();
+      const url = `https://api.mailjet.com/v3/REST/contactslist/${listId}/managecontact`;
+
+      const response = await fetch(url, {
         ...
-    });
-    ...
+      });
+      ...
+    } catch (err) {
+      console.error("Failed to unsubscribe from newsletter", err);
+      throw new Error("Failed to unsubscribe from newsletter");
+    }
   }

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In
`@front_end/src/app/`(main)/accounts/settings/notifications/components/email_notifications.tsx:
- Around line 33-46: The newsletter handler currently swallows API errors so
users get no feedback; wrap the logic inside handleNewsletterChange (the async
callback passed into useServerAction) in a try/catch and on failure call your UI
toast/error helper (e.g., toast.error or showErrorToast) to surface the Mailjet
error, only calling setNewsletterSubscribed(checked) on success; alternatively,
if useServerAction supports an onFinished/onError callback, pass a handler there
to show the error toast and keep the checkbox state unchanged — update the
references to handleNewsletterChange and the useServerAction invocation
accordingly.

In `@front_end/src/app/`(main)/accounts/settings/notifications/page.tsx:
- Around line 16-19: The Mailjet network error can throw inside Promise.all and
crash the notifications page; change the call so
serverMiscApi.isNewsletterSubscribed(currentUser.email) cannot throw—either
replace Promise.all with separate awaits and wrap the isNewsletterSubscribed
call in try/catch (defaulting to false on any exception) or use
Promise.allSettled and treat a rejected result for isNewsletterSubscribed as
false; update the logic around ServerPostsApi.getAllSubscriptions() and the
isNewsletterSubscribed handling so the posts fetch result still renders even if
the Mailjet call fails.

In `@front_end/src/app/`(main)/actions.ts:
- Around line 20-26: The server actions unsubscribeFromNewsletter,
checkNewsletterSubscription (and subscribeToNewsletter) currently accept a
client-supplied email which allows one user to act on another's account; change
them to ignore the passed email and instead fetch the authenticated user's email
server-side via ServerProfileApi.getMyProfile(), then call
serverMiscApi.unsubscribeFromNewsletter / serverMiscApi.isNewsletterSubscribed /
serverMiscApi.subscribeToNewsletter with that server-side email; ensure you
remove or ignore the function parameter and handle missing profile/email errors
appropriately.

In `@front_end/src/services/api/misc/misc.server.ts`:
- Around line 24-60: The isNewsletterSubscribed function assumes Mailjet returns
data.Data and calls data.Data.some(...) which will throw if Data is missing or
not an array; change the response handling to validate the shape before using
it: after parsing JSON (data) check that data && Array.isArray(data.Data) and
only then run the .some(...) predicate (using newsletterListId from parseInt as
before); if Data is missing or not an array, return false (optionally log the
unexpected response for debugging) so the function fails gracefully instead of
throwing.
🧹 Nitpick comments (2)
front_end/src/services/api/misc/misc.server.ts (2)

24-134: Extract repeated Mailjet auth boilerplate into a shared helper.

The API key retrieval, validation, and Base64 auth encoding are duplicated across isNewsletterSubscribed, unsubscribeFromNewsletter, and subscribeToNewsletter. This makes maintenance harder and increases the chance of inconsistencies (e.g., isNewsletterSubscribed silently returns false on missing config while the others throw).

Consider extracting a private helper like getMailjetConfig() that returns { auth, listId } or throws.

Example helper
private getMailjetConfig(): { auth: string; listId: string } {
  const apiKey = process.env.MAILJET_API_KEY;
  const secretKey = process.env.MAILJET_SECRET_KEY;
  const listId = process.env.MAILJET_NEWSLETTER_ID;

  if (!apiKey || !secretKey || !listId) {
    throw new Error(
      "Mailjet configuration is missing. Please set MAILJET_API_KEY, MAILJET_SECRET_KEY, and MAILJET_NEWSLETTER_ID environment variables."
    );
  }

  const auth = Buffer.from(`${apiKey}:${secretKey}`).toString("base64");
  return { auth, listId };
}

36-41: No timeout on external Mailjet API fetch calls.

All three Mailjet fetch calls lack timeouts. If Mailjet is slow or unresponsive, this will block the server-side render (for the page) or server action indefinitely. Consider adding an AbortSignal.timeout() or similar mechanism.

Example
     const response = await fetch(url, {
       method: "GET",
       headers: {
         Authorization: `Basic ${auth}`,
       },
+      signal: AbortSignal.timeout(10_000),
     });

Comment on lines 33 to 46
const handleNewsletterChange = useCallback(
async (checked: boolean) => {
if (checked) {
await subscribeToNewsletter(user.email);
} else {
await unsubscribeFromNewsletter(user.email);
}
setNewsletterSubscribed(checked);
},
[user.email]
);
const [updateNewsletter, isNewsletterPending] = useServerAction(
handleNewsletterChange
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

No error feedback to user when newsletter subscribe/unsubscribe fails.

If the Mailjet API call fails, useServerAction catches the error and logs it to the console, but the user sees only the spinner disappear with no indication that the action failed. The checkbox state correctly stays unchanged (since setNewsletterSubscribed won't execute), but a silent failure is a poor UX.

Consider adding an onFinished callback to useServerAction or a try/catch within handleNewsletterChange to show an error toast on failure.

🤖 Prompt for AI Agents
In
`@front_end/src/app/`(main)/accounts/settings/notifications/components/email_notifications.tsx
around lines 33 - 46, The newsletter handler currently swallows API errors so
users get no feedback; wrap the logic inside handleNewsletterChange (the async
callback passed into useServerAction) in a try/catch and on failure call your UI
toast/error helper (e.g., toast.error or showErrorToast) to surface the Mailjet
error, only calling setNewsletterSubscribed(checked) on success; alternatively,
if useServerAction supports an onFinished/onError callback, pass a handler there
to show the error toast and keep the checkbox state unchanged — update the
references to handleNewsletterChange and the useServerAction invocation
accordingly.

Comment on lines 20 to 26
export async function unsubscribeFromNewsletter(email: string) {
return await serverMiscApi.unsubscribeFromNewsletter(email);
}

export async function checkNewsletterSubscription(email: string) {
return await serverMiscApi.isNewsletterSubscribed(email);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Security: Server actions accept arbitrary email, enabling unsubscribing other users.

These server actions take email as a client-supplied parameter. Since "use server" functions are callable by any authenticated (or unauthenticated) client, a malicious user can call unsubscribeFromNewsletter with another user's email to unsubscribe them from the newsletter.

Instead, fetch the authenticated user's email server-side (e.g., via ServerProfileApi.getMyProfile()) and ignore the client-supplied email. This also applies to the pre-existing subscribeToNewsletter.

Proposed fix
+import ServerProfileApi from "@/services/api/profile/profile.server";
+
-export async function unsubscribeFromNewsletter(email: string) {
-  return await serverMiscApi.unsubscribeFromNewsletter(email);
+export async function unsubscribeFromNewsletter() {
+  const user = await ServerProfileApi.getMyProfile();
+  if (!user) throw new Error("Not authenticated");
+  return await serverMiscApi.unsubscribeFromNewsletter(user.email);
 }

-export async function checkNewsletterSubscription(email: string) {
-  return await serverMiscApi.isNewsletterSubscribed(email);
+export async function checkNewsletterSubscription() {
+  const user = await ServerProfileApi.getMyProfile();
+  if (!user) throw new Error("Not authenticated");
+  return await serverMiscApi.isNewsletterSubscribed(user.email);
 }

Apply the same pattern to subscribeToNewsletter as well.

🤖 Prompt for AI Agents
In `@front_end/src/app/`(main)/actions.ts around lines 20 - 26, The server actions
unsubscribeFromNewsletter, checkNewsletterSubscription (and
subscribeToNewsletter) currently accept a client-supplied email which allows one
user to act on another's account; change them to ignore the passed email and
instead fetch the authenticated user's email server-side via
ServerProfileApi.getMyProfile(), then call
serverMiscApi.unsubscribeFromNewsletter / serverMiscApi.isNewsletterSubscribed /
serverMiscApi.subscribeToNewsletter with that server-side email; ensure you
remove or ignore the function parameter and handle missing profile/email errors
appropriately.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

🚀 Preview Environment

Your preview environment is ready!

Resource Details
🌐 Preview URL https://metaculus-pr-4345-fix3202-preview.mtcl.cc
📦 Docker Image ghcr.io/metaculus/metaculus:fix3202-931c763
🗄️ PostgreSQL NeonDB branch preview/pr-4345-fix3202
Redis Fly Redis mtc-redis-pr-4345-fix3202

Details

  • Commit: b3e5bc35c847cb58a8d403f1be4eeeb88b9c8196
  • Branch: fix3202
  • Fly App: metaculus-pr-4345-fix3202

ℹ️ Preview Environment Info

Isolation:

  • PostgreSQL and Redis are fully isolated from production
  • Each PR gets its own database branch and Redis instance
  • Changes pushed to this PR will trigger a new deployment

Limitations:

  • Background workers and cron jobs are not deployed in preview environments
  • If you need to test background jobs, use Heroku staging environments

Cleanup:

  • This preview will be automatically destroyed when the PR is closed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@front_end/src/app/`(main)/actions.ts:
- Around line 17-19: The console.log in subscribeToNewsletter leaks raw email
PII; remove that logging and instead call
serverMiscApi.subscribeToNewsletter(email) directly (or if you need a log, log a
non-identifying event such as "newsletter subscription attempt" without the
email or log a hashed/anonymized value). Update the function
subscribeToNewsletter to eliminate the raw email output and use a non-PII log or
anonymization strategy if telemetry is required.

Comment on lines 17 to 19
export async function subscribeToNewsletter(email: string) {
console.log("subscribeToNewsletter", email);
return await serverMiscApi.subscribeToNewsletter(email);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove raw email logging (PII).
Server logs should not record user emails unless explicitly required and sanitized.

🩹 Suggested fix
 export async function subscribeToNewsletter(email: string) {
-  console.log("subscribeToNewsletter", email);
   return await serverMiscApi.subscribeToNewsletter(email);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function subscribeToNewsletter(email: string) {
console.log("subscribeToNewsletter", email);
return await serverMiscApi.subscribeToNewsletter(email);
export async function subscribeToNewsletter(email: string) {
return await serverMiscApi.subscribeToNewsletter(email);
}
🤖 Prompt for AI Agents
In `@front_end/src/app/`(main)/actions.ts around lines 17 - 19, The console.log in
subscribeToNewsletter leaks raw email PII; remove that logging and instead call
serverMiscApi.subscribeToNewsletter(email) directly (or if you need a log, log a
non-identifying event such as "newsletter subscription attempt" without the
email or log a hashed/anonymized value). Update the function
subscribeToNewsletter to eliminate the raw email output and use a non-PII log or
anonymization strategy if telemetry is required.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@front_end/src/services/api/misc/misc.server.ts`:
- Around line 36-63: The isNewsletterSubscribed function currently only handles
HTTP error responses but lets fetch-level network errors propagate; wrap the
fetch and subsequent response processing in a try-catch around the existing
logic (including the fetch(url, { method: "GET", headers: { Authorization:
`Basic ${auth}` } }), response handling, and JSON parsing) and on any thrown
error catch it and return false so network failures behave like HTTP errors and
do not bubble up to callers.
- Around line 93-99: The error logging in unsubscribeFromNewsletter (and
likewise in subscribeToNewsletter) may print Mailjet errorText containing user
emails; update both functions to redact email addresses before logging by
replacing any email-like patterns in errorText with a redaction token (e.g.,
"[REDACTED_EMAIL]") and then log the sanitized message; locate the
response/errorText handling in unsubscribeFromNewsletter and the analogous block
in subscribeToNewsletter and apply the same redaction step prior to calling
console.error and throwing the Error.

Comment on lines +36 to +63
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Basic ${auth}`,
},
});

if (!response.ok) {
if (response.status === 404) {
return false;
}
console.error(
`Failed to check newsletter subscription: ${response.status} ${response.statusText}`
);
return false;
}

const data = await response.json();
const newsletterListId = parseInt(listId, 10);

return (
Array.isArray(data?.Data) &&
data.Data.some(
(list: { ListID: number; IsUnsub: boolean }) =>
list.ListID === newsletterListId && !list.IsUnsub
)
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd front_end && find . -name "misc.server.ts" -type f | head -5

Repository: Metaculus/metaculus

Length of output: 101


🏁 Script executed:

cat -n front_end/src/services/api/misc/misc.server.ts | head -80

Repository: Metaculus/metaculus

Length of output: 3104


🏁 Script executed:

rg "isNewsletterSubscribed" front_end/src --type ts --type tsx -B 2 -A 2

Repository: Metaculus/metaculus

Length of output: 90


🏁 Script executed:

grep -n "unsubscribeFromNewsletter" front_end/src/services/api/misc/misc.server.ts

Repository: Metaculus/metaculus

Length of output: 116


🏁 Script executed:

rg "isNewsletterSubscribed" front_end/src -B 2 -A 2

Repository: Metaculus/metaculus

Length of output: 3578


🏁 Script executed:

cat -n front_end/src/services/api/misc/misc.server.ts | sed -n '65,110p'

Repository: Metaculus/metaculus

Length of output: 1991


Add error handling for fetch-level failures in isNewsletterSubscribed.

Network errors (DNS failures, timeouts) will throw and propagate to callers, while HTTP errors are gracefully handled and return false. Wrap the fetch in a try-catch block to return false on network errors, ensuring consistent behavior across all error scenarios.

🔧 Suggested fix
+    try {
       const response = await fetch(url, {
         method: "GET",
         headers: {
           Authorization: `Basic ${auth}`,
         },
       });

       if (!response.ok) {
         if (response.status === 404) {
           return false;
         }
         console.error(
           `Failed to check newsletter subscription: ${response.status} ${response.statusText}`
         );
         return false;
       }

       const data = await response.json();
       const newsletterListId = parseInt(listId, 10);

       return (
         Array.isArray(data?.Data) &&
         data.Data.some(
           (list: { ListID: number; IsUnsub: boolean }) =>
             list.ListID === newsletterListId && !list.IsUnsub
         )
       );
+    } catch (err) {
+      console.error("Failed to check newsletter subscription", err);
+      return false;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Basic ${auth}`,
},
});
if (!response.ok) {
if (response.status === 404) {
return false;
}
console.error(
`Failed to check newsletter subscription: ${response.status} ${response.statusText}`
);
return false;
}
const data = await response.json();
const newsletterListId = parseInt(listId, 10);
return (
Array.isArray(data?.Data) &&
data.Data.some(
(list: { ListID: number; IsUnsub: boolean }) =>
list.ListID === newsletterListId && !list.IsUnsub
)
);
}
try {
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Basic ${auth}`,
},
});
if (!response.ok) {
if (response.status === 404) {
return false;
}
console.error(
`Failed to check newsletter subscription: ${response.status} ${response.statusText}`
);
return false;
}
const data = await response.json();
const newsletterListId = parseInt(listId, 10);
return (
Array.isArray(data?.Data) &&
data.Data.some(
(list: { ListID: number; IsUnsub: boolean }) =>
list.ListID === newsletterListId && !list.IsUnsub
)
);
} catch (err) {
console.error("Failed to check newsletter subscription", err);
return false;
}
}
🤖 Prompt for AI Agents
In `@front_end/src/services/api/misc/misc.server.ts` around lines 36 - 63, The
isNewsletterSubscribed function currently only handles HTTP error responses but
lets fetch-level network errors propagate; wrap the fetch and subsequent
response processing in a try-catch around the existing logic (including the
fetch(url, { method: "GET", headers: { Authorization: `Basic ${auth}` } }),
response handling, and JSON parsing) and on any thrown error catch it and return
false so network failures behave like HTTP errors and do not bubble up to
callers.

Copy link
Contributor

@ncarazon ncarazon left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
front_end/src/services/api/misc/misc.server.ts (1)

74-103: ⚠️ Potential issue | 🔴 Critical

Critical security issue: subscribeToNewsletter accepts arbitrary email without authentication.

The method correctly integrates with Mailjet and redacts emails in error logs. However, a significant vulnerability exists: subscribeToNewsletter (lines 17–19 in actions.ts) accepts any email parameter without authentication, while unsubscribeFromNewsletter (lines 26–29) correctly requires authentication and fetches the user's email server-side.

In the authenticated settings context (email_notifications.tsx, line 36), this creates an abuse vector where an authenticated user could modify the client call to subscribe arbitrary email addresses to the newsletter. The explicit design comment (lines 21–25) acknowledges allowing unauthenticated subscriptions for public signup flows, but this does not require an arbitrary email parameter in authenticated contexts.

The fix aligns subscribeToNewsletter with the secure unsubscribeFromNewsletter pattern:

Suggested fix in actions.ts
-export async function subscribeToNewsletter(email: string) {
-  return await serverMiscApi.subscribeToNewsletter(email);
+export async function subscribeToNewsletter() {
+  const user = await ServerProfileApi.getMyProfile();
+  if (!user) throw new Error("Not authenticated");
+  return await serverMiscApi.subscribeToNewsletter(user.email);
 }

And update the call site in email_notifications.tsx:

-        await subscribeToNewsletter(user.email);
+        await subscribeToNewsletter();

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.

2 participants