pwf-website-new/functions/api/newsletter.ts

119 lines
4.0 KiB
TypeScript

import { z } from 'zod';
const newsletterSchema = z.object({
email: z.string().email(),
agreedToTerms: z.boolean()
});
// Mailchimp integration
async function subscribeToMailchimp(email: string, env: any) {
const API_KEY = env.MAILCHIMP_API_KEY;
const SERVER_PREFIX = env.MAILCHIMP_SERVER_PREFIX;
const LIST_ID = env.MAILCHIMP_LIST_ID;
if (!API_KEY || !SERVER_PREFIX || !LIST_ID) {
throw new Error('Mailchimp configuration missing. Please check your environment variables.');
}
try {
// Create MD5 hash of lowercase email for Mailchimp
const emailHash = crypto.createHash('md5').update(email.toLowerCase()).digest('hex');
// Set up the request
const url = `https://${SERVER_PREFIX}.api.mailchimp.com/3.0/lists/${LIST_ID}/members`;
const data = {
email_address: email,
status: 'subscribed'
};
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${btoa(`apikey:${API_KEY}`)}`
},
body: JSON.stringify(data)
});
if (!response.ok) {
const errorData = await response.json();
if (response.status === 400 && errorData.title === 'Member Exists') {
return { status: 'already_subscribed', message: 'This email is already subscribed to our newsletter.' };
}
throw new Error(`Mailchimp API error: ${errorData.detail || 'Unknown error'}`);
}
return await response.json();
} catch (error: any) {
throw new Error(`Failed to subscribe to newsletter: ${error.message}`);
}
}
export const onRequest: PagesFunction = async (context) => {
const { request, env } = context;
if (request.method === 'POST') {
try {
const body = await request.json();
const newsletterData = newsletterSchema.parse(body);
// Check if email already exists in KV storage
const existingNewsletter = await env.STORAGE.get(`newsletter:${newsletterData.email}`);
// Store in KV storage
if (!existingNewsletter) {
const newsletterRecord = {
email: newsletterData.email,
agreedToTerms: newsletterData.agreedToTerms,
createdAt: new Date().toISOString()
};
await env.STORAGE.put(`newsletter:${newsletterData.email}`, JSON.stringify(newsletterRecord));
}
// Subscribe to Mailchimp
try {
const mailchimpResponse = await subscribeToMailchimp(newsletterData.email, env);
if (mailchimpResponse && mailchimpResponse.status === 'already_subscribed') {
return new Response(JSON.stringify({ message: mailchimpResponse.message }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
return new Response(JSON.stringify({ message: "Successfully subscribed to the newsletter" }), {
status: 201,
headers: { 'Content-Type': 'application/json' }
});
} catch (mailchimpError: any) {
console.error('Mailchimp error:', mailchimpError.message);
// Still return success if we stored in KV but Mailchimp failed
return new Response(JSON.stringify({ message: "Successfully subscribed to the newsletter" }), {
status: 201,
headers: { 'Content-Type': 'application/json' }
});
}
} catch (error) {
if (error instanceof z.ZodError) {
return new Response(JSON.stringify({
message: "Invalid newsletter data",
errors: error.errors
}), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
console.error('Newsletter subscription error:', error);
return new Response(JSON.stringify({ message: "Failed to subscribe to newsletter" }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
}
return new Response(JSON.stringify({ message: "Method not allowed" }), {
status: 405,
headers: { 'Content-Type': 'application/json' }
});
};