File tree Expand file tree Collapse file tree 4 files changed +27
-50
lines changed
Expand file tree Collapse file tree 4 files changed +27
-50
lines changed Load Diff This file was deleted.
Original file line number Diff line number Diff line change @@ -5,6 +5,7 @@ import { motion, AnimatePresence } from 'framer-motion'
55import { BookOpen , X , Sparkles } from 'lucide-react'
66import { Button } from '@/components/ui/button'
77import Confetti from 'react-confetti'
8+ import { EMAIL_RE , submitToBrevo } from '@/lib/newsletter'
89
910export 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
Original file line number Diff line number Diff line change 11'use client' ;
22
33import { useState } from 'react' ;
4+ import { EMAIL_RE , submitToBrevo } from '@/lib/newsletter' ;
45
56export type SubscribeStatus = 'idle' | 'loading' | 'success' | 'error' ;
67
7- const EMAIL_RE = / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / ;
8-
98export 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 }
Original file line number Diff line number Diff line change 11/** Brevo subscription form URL. Public — safe to commit, no env var needed. */
22export 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+ }
You can’t perform that action at this time.
0 commit comments