import { createClient } from '@/lib/supabase/server'; import { NextRequest, NextResponse } from 'next/server'; import nodemailer from 'nodemailer'; // GET: list all subscribers export async function GET(req: NextRequest) { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const { searchParams } = new URL(req.url); const status = searchParams.get('status') || 'all'; const search = searchParams.get('search') || ''; let query = supabase .from('newsletter_subscribers') .select('*') .order('subscribed_at', { ascending: false }); if (status !== 'all') query = query.eq('status', status); if (search) query = query.ilike('email', `%${search}%`); const { data, error } = await query; if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ subscribers: data || [] }); } // DELETE: unsubscribe a subscriber export async function DELETE(req: NextRequest) { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const { id } = await req.json(); if (!id) return NextResponse.json({ error: 'ID required' }, { status: 400 }); const { error } = await supabase .from('newsletter_subscribers') .update({ status: 'unsubscribed', unsubscribed_at: new Date().toISOString() }) .eq('id', id); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ success: true }); } // PATCH: bulk actions (bulk_unsubscribe, bulk_delete) export async function PATCH(req: NextRequest) { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const { action, ids } = await req.json(); if (!action || !Array.isArray(ids) || ids.length === 0) { return NextResponse.json({ error: 'action and ids[] required' }, { status: 400 }); } if (action === 'bulk_unsubscribe') { const { error } = await supabase .from('newsletter_subscribers') .update({ status: 'unsubscribed', unsubscribed_at: new Date().toISOString() }) .in('id', ids) .eq('status', 'active'); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ success: true, count: ids.length }); } if (action === 'bulk_delete') { const { error } = await supabase .from('newsletter_subscribers') .delete() .in('id', ids); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ success: true, count: ids.length }); } return NextResponse.json({ error: 'Unknown action' }, { status: 400 }); } // POST: send digest email to all active subscribers export async function POST(req: NextRequest) { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const { subject, previewText, articles, customMessage } = await req.json(); if (!subject) return NextResponse.json({ error: 'Subject is required' }, { status: 400 }); if (!articles || articles.length === 0) { return NextResponse.json({ error: 'At least one article is required' }, { status: 400 }); } const smtpHost = process.env.SMTP_HOST; const smtpPort = parseInt(process.env.SMTP_PORT || '587'); 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) { return NextResponse.json({ error: 'SMTP credentials not configured' }, { status: 500 }); } // Fetch active subscribers const { data: subscribers, error: subError } = await supabase .from('newsletter_subscribers') .select('email') .eq('status', 'active'); if (subError) return NextResponse.json({ error: subError.message }, { status: 500 }); if (!subscribers || subscribers.length === 0) { return NextResponse.json({ error: 'No active subscribers found' }, { status: 400 }); } const transporter = nodemailer.createTransport({ host: smtpHost, port: smtpPort, secure: smtpPort === 465, auth: { user: smtpUser, pass: smtpPass }, }); // Build article HTML blocks const articlesHtml = articles .map( (a: { title: string; excerpt?: string; url?: string; image?: string; category?: string }) => `
${a.excerpt}
` : ''} ${a.url ? `Read more →` : ''}Pro AV, Display and Live Production Tech
${previewText}
` : ''} ${customMessage ? `${customMessage}
You're receiving this because you subscribed at avbeat.com.