Skip to content

Commit 1704c6f

Browse files
Copilotbobbyiliev
andcommitted
fix: submit to Brevo directly via fetch, remove API route
Co-authored-by: bobbyiliev <21223421+bobbyiliev@users.noreply.github.com>
1 parent 3615dc0 commit 1704c6f

File tree

4 files changed

+27
-50
lines changed

4 files changed

+27
-50
lines changed

app/api/newsletter/route.ts

Lines changed: 0 additions & 36 deletions
This file was deleted.

components/book-promotion-popup.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { motion, AnimatePresence } from 'framer-motion'
55
import { BookOpen, X, Sparkles } from 'lucide-react'
66
import { Button } from '@/components/ui/button'
77
import Confetti from 'react-confetti'
8+
import { EMAIL_RE, submitToBrevo } from '@/lib/newsletter'
89

910
export function BookPromotionPopup() {
1011
const [isVisible, setIsVisible] = useState(false)
@@ -63,14 +64,10 @@ export function BookPromotionPopup() {
6364
const handleSubscribe = async (e: React.FormEvent<HTMLFormElement>) => {
6465
e.preventDefault();
6566

66-
if (!email) return;
67+
if (!email || !EMAIL_RE.test(email)) return;
6768

6869
try {
69-
await fetch('/api/newsletter', {
70-
method: 'POST',
71-
headers: { 'Content-Type': 'application/json' },
72-
body: JSON.stringify({ email }),
73-
});
70+
await submitToBrevo(email);
7471
} catch (err) {
7572
console.error('[newsletter] Popup subscription error:', err);
7673
// Proceed optimistically – show thank you regardless

hooks/use-newsletter-subscribe.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
'use client';
22

33
import { useState } from 'react';
4+
import { EMAIL_RE, submitToBrevo } from '@/lib/newsletter';
45

56
export type SubscribeStatus = 'idle' | 'loading' | 'success' | 'error';
67

7-
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
8-
98
export function useNewsletterSubscribe() {
109
const [status, setStatus] = useState<SubscribeStatus>('idle');
1110

@@ -16,12 +15,8 @@ export function useNewsletterSubscribe() {
1615
}
1716
setStatus('loading');
1817
try {
19-
const res = await fetch('/api/newsletter', {
20-
method: 'POST',
21-
headers: { 'Content-Type': 'application/json' },
22-
body: JSON.stringify({ email }),
23-
});
24-
setStatus(res.ok ? 'success' : 'error');
18+
await submitToBrevo(email);
19+
setStatus('success');
2520
} catch {
2621
setStatus('error');
2722
}

lib/newsletter.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
11
/** Brevo subscription form URL. Public — safe to commit, no env var needed. */
22
export const BREVO_FORM_URL =
33
'https://66ce6dcc.sibforms.com/serve/MUIFABg_VUzhY-5kln8REbgjz0epYq6FtPckqwqsIG_s4FKBiVUqR9Q5SakKep9c2cHa2NEC1J02ps4tMUbaxssoB7MvwSggRvWktJJ7-LM9oWVRG3h0KhFHXsNOgoCSEo9OTB_CIp8JyRlALoSmEQOGpRoVYIYEq2LD0ikQ6T56zXVF8ZNc3tFBykMZGOxtLEfD7tap75LwptWPxg==';
4+
5+
export const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
6+
7+
/**
8+
* Submit an email to the Brevo hosted subscription form.
9+
* Uses mode:'no-cors' because Brevo's endpoint doesn't emit CORS headers.
10+
* The response is opaque, so any non-throwing fetch is treated as success.
11+
*/
12+
export async function submitToBrevo(email: string): Promise<void> {
13+
const body = new URLSearchParams({
14+
EMAIL: email.trim(),
15+
email_address_check: '',
16+
locale: 'en',
17+
});
18+
await fetch(BREVO_FORM_URL, {
19+
method: 'POST',
20+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
21+
body: body.toString(),
22+
mode: 'no-cors',
23+
});
24+
}

0 commit comments

Comments
 (0)