"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { authFetch, getApiBase } from "../lib/auth"; import "../email-recaps/recaps.css"; type Preference = { state: "off" | "pending" | "expired" | "enabled"; email: string | null; can_subscribe: boolean; detail: string; schedule_enabled: boolean; next_send_at: number | null; weekday: number; hour: number; resend_after: number | null; }; const scheduled = (value: number) => `${new Date(value * 1000).toLocaleString(undefined, { dateStyle: "long", timeStyle: "short", timeZone: "UTC" })} UTC`; export default function NewsletterPreference() { const router = useRouter(); const [data, setData] = useState(null); const [busy, setBusy] = useState(false); const [error, setError] = useState(""); const [notice, setNotice] = useState(""); const [revision, setRevision] = useState(0); const [now, setNow] = useState(Date.now()); useEffect(() => { void revision; const abort = new AbortController(); setError(""); void authFetch(`${getApiBase()}/profile/newsletters`, { signal: abort.signal }) .then(async (response) => { if (response.status === 401) { router.replace("/login?next=%2Fprofile"); return; } if (!response.ok) throw new Error("Could not load your email preference. Please try again."); const result = (await response.json()) as Preference; if (!abort.signal.aborted) setData(result); }) .catch((err: Error) => { if (!abort.signal.aborted) setError(err.message); }); return () => abort.abort(); }, [revision, router]); useEffect(() => { if (!data?.resend_after || data.state === "enabled" || data.resend_after * 1000 <= Date.now()) return; const timer = window.setInterval(() => setNow(Date.now()), 1000); return () => window.clearInterval(timer); }, [data?.resend_after, data?.state]); const save = async (enabled: boolean) => { if (busy) return; setBusy(true); setError(""); setNotice(""); try { const response = await authFetch(`${getApiBase()}/profile/newsletters`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ enabled }), }); if (response.status === 401) { router.replace("/login?next=%2Fprofile"); return; } const result = await response.json().catch(() => ({})); if (!response.ok) throw new Error(typeof result.detail === "string" ? result.detail : "Could not update your email preference."); setData(result); setNow(Date.now()); setNotice(result.message || (enabled ? "Newsletters are on." : "Newsletters are off.")); } catch (err) { setError(err instanceof Error ? err.message : "Could not update your email preference."); // A confirmation may be pending even if SMTP could not confirm delivery. const response = await authFetch(`${getApiBase()}/profile/newsletters`).catch(() => null); if (response?.ok) { setData(await response.json()); setNow(Date.now()); } } finally { setBusy(false); } }; const cooldown = data?.resend_after ? Math.max(0, Math.ceil(data.resend_after - now / 1000)) : 0; return (
Your next watch

New on Grizzlyflix.

{data && ( { { off: "Off", pending: "Check your inbox", expired: "Confirmation expired", enabled: "Subscribed" }[ data.state ] } )}

Your minutes, movies, episodes, longest run and requests, in one personal monthly email.{" "} Explore your latest report ↗

{!data && !error &&

Loading your email preference…

} {data && ( <> {data.state === "enabled" ? (

Newsletters will go to {data.email}.{" "} {data.schedule_enabled && data.next_send_at ? `Next scheduled send: ${scheduled(data.next_send_at)}.` : "Weekly sending is paused. You may still receive editions scheduled by your administrator."}

) : (

{data.state === "pending" ? `Check ${data.email} for a confirmation link. It expires after 24 hours. Your newsletter subscription starts after you confirm.` : data.state === "expired" ? "Request a new confirmation link to turn on newsletters." : "Subscribe with your profile email. If you already confirmed it for monthly recaps, you can turn this on straight away. Otherwise, we?ll send a confirmation link."}

)} {!data.can_subscribe && data.state !== "enabled" &&

{data.detail}

} {data.state !== "enabled" && data.can_subscribe && !data.schedule_enabled && (

You can subscribe now, ready for the next edition your administrator sends.

)}
{data.state !== "enabled" && ( )} {data.state !== "off" && ( )}
{cooldown > 0 && data.state !== "enabled" && (

Another confirmation can be requested in {Math.ceil(cooldown / 60)}{" "} {Math.ceil(cooldown / 60) === 1 ? "minute" : "minutes"}.

)} )} {error && (

{error} {!data && ( )}

)} {notice && (

{notice}

)}
); }