[UXIT-3791][filecoin.io V3] Hook up NewsletterForm [skip percy]#2181
[UXIT-3791][filecoin.io V3] Hook up NewsletterForm [skip percy]#2181barbaraperic wants to merge 2 commits intomainfrom
Conversation
…g and add API subscription route
…olledFormInput for improved form handling; update success message in useNewsletterForm hook; enhance Mailchimp subscription API error handling and response parsing.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
3 Skipped Deployments
|
There was a problem hiding this comment.
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
useNewsletterFormto own form validation + submission + notification dialog behavior. - Refactored
NewsletterFormto 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.
| 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, |
There was a problem hiding this comment.
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.
| const MAILCHIMP_JSONP_CALLBACK = 'handle_response' | ||
|
|
||
| export async function POST(request: NextRequest) { | ||
| const { email } = await request.json() |
There was a problem hiding this comment.
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.
| 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 }, | |
| ) | |
| } |
|
|
||
| let data: { result?: string; msg?: string } | ||
| try { | ||
| const json = text.replace(/^[^(]+\(/, '').replace(/\)$/, '') |
There was a problem hiding this comment.
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.
| 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] |
📝 Description
This PR adds a functional newsletter subscription form that integrates with Mailchimp for the Filecoin site.
🛠️ Key Changes
NewsletterForm.tsx- Refactored to useControlledFormandControlledFormInputfor form handlinguseNewsletterForm.ts- New custom hook that manages form state, validation, and submission logic with notification dialogs for success/error feedbackapi/subscribe/route.ts- New API route that handles Mailchimp subscription requests with robust error handling for inconsistent API responsesNotes
MAILCHIMP_UandMAILCHIMP_LIST_IDenvironment variables to be set.🧪 How to Test
📸 Screenshots