diff --git a/app/admin/newsletter/page.tsx b/app/admin/newsletter/page.tsx new file mode 100644 index 00000000..6b78b709 --- /dev/null +++ b/app/admin/newsletter/page.tsx @@ -0,0 +1,271 @@ +"use client" + +import { useEffect, useState } from "react" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Download, Send, Loader2, Users, Mail } from "lucide-react" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" + +interface Subscriber { + id: number + email: string + status: string + created_at: string +} + +export default function NewsletterAdminPage() { + const [subscribers, setSubscribers] = useState([]) + const [loading, setLoading] = useState(true) + const [stats, setStats] = useState({ total: 0, subscribed: 0, unsubscribed: 0 }) + const [error, setError] = useState("") + + // Newsletter sending state + const [subject, setSubject] = useState("") + const [content, setContent] = useState("") + const [sending, setSending] = useState(false) + + useEffect(() => { + fetchSubscribers() + }, []) + + const fetchSubscribers = async () => { + try { + const response = await fetch("/api/admin/newsletter/subscribers") + const data = await response.json() + + if (response.ok) { + setSubscribers(data.subscribers || []) + setStats(data.stats || { total: 0, subscribed: 0, unsubscribed: 0 }) + } else { + setError(data.error || "Failed to fetch subscribers") + console.error("API Error:", data) + } + } catch (err) { + console.error("Failed to fetch subscribers:", err) + setError("Network error - check console") + } finally { + setLoading(false) + } + } + + const exportSubscribers = () => { + const csv = [ + ["Email", "Status", "Subscribed Date"], + ...subscribers.map(sub => [ + sub.email, + sub.status, + new Date(sub.created_at).toLocaleDateString() + ]) + ].map(row => row.join(",")).join("\n") + + const blob = new Blob([csv], { type: "text/csv" }) + const url = window.URL.createObjectURL(blob) + const a = document.createElement("a") + a.href = url + a.download = `newsletter-subscribers-${new Date().toISOString().split("T")[0]}.csv` + a.click() + } + + const sendNewsletter = async () => { + if (!subject || !content) { + alert("Please fill in both subject and content") + return + } + + if (!confirm(`Send newsletter to ${stats.subscribed} subscribers?`)) { + return + } + + setSending(true) + try { + const response = await fetch("/api/admin/newsletter/send", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ subject, content }), + }) + + const data = await response.json() + + if (response.ok) { + alert(`Newsletter sent successfully to ${data.sent} subscribers!`) + setSubject("") + setContent("") + } else { + alert(`Failed to send newsletter: ${data.error}`) + } + } catch { + alert("Failed to send newsletter") + } finally { + setSending(false) + } + } + + if (loading) { + return ( +
+ +
+ ) + } + + if (error) { + return ( +
+
+

Error Loading Subscribers

+

{error}

+

+ Make sure you're logged in as an admin and RLS policies are configured correctly. +

+
+
+ ) + } + + return ( +
+
+
+

Newsletter Management

+

Manage subscribers and send newsletters

+
+ + {/* Stats */} +
+
+
+
+

Total Subscribers

+

{stats.total}

+
+ +
+
+
+
+
+

Active

+

{stats.subscribed}

+
+ +
+
+
+
+
+

Unsubscribed

+

{stats.unsubscribed}

+
+ +
+
+
+ + + + Subscribers + Send Newsletter + + + +
+

All Subscribers

+ +
+ +
+
+ + + + + + + + + + {subscribers.map((sub) => ( + + + + + + ))} + +
EmailStatusSubscribed Date
{sub.email} + + {sub.status} + + + {new Date(sub.created_at).toLocaleDateString()} +
+
+
+
+ + +
+

Compose Newsletter

+ +
+ + setSubject(e.target.value)} + disabled={sending} + /> +
+ +
+ +