import { createAdminClient } from '@/lib/supabase/admin'; import { NextRequest, NextResponse } from 'next/server'; import nodemailer from 'nodemailer'; export const runtime = 'nodejs'; // Public newsletter subscribe endpoint. Used by: // - NewsletterModal (site-wide popup) // - Header subscribe widget // - Homepage NewsletterSignup section // - Footer signup // // Why service-role (not the session client): // bb.newsletter_subscribers' RLS only has an INSERT policy for anon // ('public_subscribe_newsletter') — upsert needs both INSERT+UPDATE // to handle re-subscribers. Service-role bypasses RLS cleanly. export async function POST(req: NextRequest) { try { const { email, topics, source } = await req.json(); if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { return NextResponse.json({ error: 'Please enter a valid email address.' }, { status: 400 }); } const normalized = email.toLowerCase().trim(); const supabase = createAdminClient(); // Upsert subscriber (re-subscribe if previously unsubscribed) const { error } = await supabase .from('newsletter_subscribers') .upsert( { email: normalized, topics: topics && Array.isArray(topics) ? topics : [], status: 'active', subscribed_at: new Date().toISOString(), unsubscribed_at: null, }, { onConflict: 'email' }, ); if (error) { console.error('newsletter_subscribers upsert failed:', error.message, error.details); return NextResponse.json( { error: 'Could not save subscription. Please try again in a moment.' }, { status: 500 }, ); } // Best-effort welcome email — never block the API response on SMTP. // The signup is already saved to the DB, so we return 200 either way // and let the email fire in the background. void sendWelcome(normalized, topics).catch((e) => console.error('newsletter welcome email failed:', e?.message || e), ); return NextResponse.json({ success: true, source: source || null }); } catch (err: any) { console.error('Subscribe handler error:', err?.message || err); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } async function sendWelcome(email: string, topics?: string[]) { const smtpHost = process.env.SMTP_HOST; const smtpPort = parseInt(process.env.SMTP_PORT || '587', 10); const smtpUser = process.env.SMTP_USER; const smtpPass = process.env.SMTP_PASS; const fromEmail = process.env.SMTP_FROM_EMAIL || smtpUser; const fromName = process.env.SMTP_FROM_NAME || 'AV Beat'; const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://avbeat.com'; if (!smtpHost || !smtpUser || !smtpPass || !fromEmail) { // SMTP not configured — signal that to logs but don't blow up. console.warn('newsletter welcome: SMTP env not set; skipping send'); return; } const transporter = nodemailer.createTransport({ host: smtpHost, port: smtpPort, secure: smtpPort === 465, auth: { user: smtpUser, pass: smtpPass }, }); const topicsBlock = topics && topics.length > 0 ? `
You'll receive coverage on: ${topics.join(', ')}
` : ''; await transporter.sendMail({ from: `"${fromName}" <${fromEmail}>`, to: email, subject: 'Welcome to AV Beat', html: `