Skip to content

[UXIT-3791][filecoin.io V3] Hook up NewsletterForm [skip percy]#2181

Draft
barbaraperic wants to merge 2 commits intomainfrom
bp/newsletter-form
Draft

[UXIT-3791][filecoin.io V3] Hook up NewsletterForm [skip percy]#2181
barbaraperic wants to merge 2 commits intomainfrom
bp/newsletter-form

Conversation

@barbaraperic
Copy link
Collaborator

@barbaraperic barbaraperic commented Feb 19, 2026

📝 Description

This PR adds a functional newsletter subscription form that integrates with Mailchimp for the Filecoin site.

  • Type: Bug fix / New feature / Documentation / Refactor

🛠️ Key Changes

  • NewsletterForm.tsx - Refactored to use ControlledForm and ControlledFormInput for form handling
  • useNewsletterForm.ts - New custom hook that manages form state, validation, and submission logic with notification dialogs for success/error feedback
  • api/subscribe/route.ts - New API route that handles Mailchimp subscription requests with robust error handling for inconsistent API responses

Notes

  • The Mailchimp embedded form endpoint (post-json) can return HTML instead of JSON in certain cases (e.g., already subscribed emails). The API route includes error handling to gracefully handle these responses.
  • Requires MAILCHIMP_U and MAILCHIMP_LIST_ID environment variables to be set.

🧪 How to Test

  1. Enter a valid email in the newsletter form
  2. Verify success notification appears
  3. Test with an already-subscribed email to verify error handling

📸 Screenshots

…olledFormInput for improved form handling; update success message in useNewsletterForm hook; enhance Mailchimp subscription API error handling and response parsing.
@barbaraperic barbaraperic requested a review from Copilot February 19, 2026 16:05
@barbaraperic barbaraperic self-assigned this Feb 19, 2026
@vercel
Copy link

vercel bot commented Feb 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
filecoin-site Ready Ready Preview, Comment Feb 19, 2026 4:05pm
3 Skipped Deployments
Project Deployment Actions Updated (UTC)
ffdweb-site Skipped Skipped Feb 19, 2026 4:05pm
filecoin-foundation-site Skipped Skipped Feb 19, 2026 4:05pm
filecoin-foundation-uxit Skipped Skipped Feb 19, 2026 4:05pm

Request Review

@notion-workspace
Copy link

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a functional newsletter subscription flow to the Filecoin site by wiring the footer newsletter form to a new /api/subscribe endpoint that proxies Mailchimp’s embedded JSONP subscription endpoint, and centralizing client-side form handling in a custom hook.

Changes:

  • Added a Next.js route handler to submit newsletter signups to Mailchimp and normalize responses to JSON.
  • Introduced useNewsletterForm to own form validation + submission + notification dialog behavior.
  • Refactored NewsletterForm to use shared controlled form components and the new hook.

Reviewed changes

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

File Description
apps/filecoin-site/src/app/api/subscribe/route.ts New API route that calls Mailchimp subscribe endpoint and returns normalized JSON responses.
apps/filecoin-site/src/app/_hooks/useNewsletterForm.ts New hook for form schema, submission, and notification dialog interactions.
apps/filecoin-site/src/app/_components/Footer/NewsletterForm.tsx Refactor footer newsletter UI to use ControlledForm + useNewsletterForm + NotificationDialog.

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

Comment on lines +35 to +54
const message =
body?.message ?? (response.ok ? undefined : 'Subscription failed')

if (!response.ok) {
dialog.open({
message: message || 'Something went wrong. Please try again.',
duration: NOTIFICATION_DIALOG_ERROR_DURATION_MS,
icon: { component: XCircleIcon, color: 'error' },
})
return
}

dialog.open({
message: 'Check your email to confirm your subscription.',
icon: { component: CheckCircleIcon, color: 'success' },
})
} catch (err) {
dialog.open({
message: 'An error has occurred. Please try again.',
duration: NOTIFICATION_DIALOG_ERROR_DURATION_MS,
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

Several user-facing dialog strings are hardcoded in English (e.g., success and error messages, and the 'Subscription failed' fallback). Since this component already uses next-intl for the form label/placeholder, these messages should also come from translations so non-English locales get the correct UX.

Copilot uses AI. Check for mistakes.
const MAILCHIMP_JSONP_CALLBACK = 'handle_response'

export async function POST(request: NextRequest) {
const { email } = await request.json()
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

await request.json() can throw (e.g., empty body or invalid JSON), which would surface as a 500. Consider wrapping JSON parsing in a try/catch and returning a 400 with a clear error when the request body isn't valid JSON.

Suggested change
const { email } = await request.json()
let email: unknown
try {
const body = await request.json()
if (!body || typeof body !== 'object') {
return Response.json(
{ ok: false, message: 'Invalid JSON body' },
{ status: 400 },
)
}
;({ email } = body as { email?: unknown })
} catch {
return Response.json(
{ ok: false, message: 'Invalid JSON body' },
{ status: 400 },
)
}

Copilot uses AI. Check for mistakes.

let data: { result?: string; msg?: string }
try {
const json = text.replace(/^[^(]+\(/, '').replace(/\)$/, '')
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The JSONP stripping logic only removes the final ) and will fail to parse common JSONP formats that end with ); or have trailing whitespace/newlines. Make the extraction more robust (e.g., strip an optional trailing semicolon/whitespace and/or match the expected callback wrapper) so successful Mailchimp responses don't get treated as parse failures.

Suggested change
const json = text.replace(/^[^(]+\(/, '').replace(/\)$/, '')
const callbackRegex = new RegExp(
`^\\s*${MAILCHIMP_JSONP_CALLBACK}\\s*\\(([\\s\\S]*?)\\)\\s*;?\\s*$`,
)
const match = text.match(callbackRegex)
if (!match) {
throw new Error('Invalid Mailchimp JSONP format')
}
const json = match[1]

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments