"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 = { automatic_monthly: boolean; state: "off" | "pending" | "expired" | "enabled"; email: string | null; can_subscribe: boolean; detail: string; schedule_enabled: boolean; next_send_at: number | null; day: 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 MonthlyRecapPreference() { const router = useRouter(); const [data, setData] = useState(null); const [automatic, setAutomatic] = useState(false); 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/email-recaps`, { 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); setAutomatic(result.automatic_monthly); } }) .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, monthly = automatic) => { if (busy) return; setBusy(true); setError(""); setNotice(""); try { const response = await authFetch(`${getApiBase()}/profile/email-recaps`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ enabled, automatic_monthly: monthly }), }); 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); setAutomatic(result.automatic_monthly); setNow(Date.now()); setNotice( result.message || (enabled ? "Personal report emails are enabled." : "Personal report emails 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/email-recaps`).catch(() => null); if (response?.ok) { const fresh = await response.json(); setData(fresh); setAutomatic(fresh.automatic_monthly); setNow(Date.now()); } } finally { setBusy(false); } }; const cooldown = data?.resend_after ? Math.max(0, Math.ceil(data.resend_after - now / 1000)) : 0; return (
A little look back

Your reports, your choice.

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

Email yourself your viewing report whenever you want. Choose a previous month or the current month so far, and decide whether you also want automatic monthly emails.{" "} Explore your latest report ↗

{!data && !error &&

Loading your email preference…

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

Recaps will go to {data.email}.{" "} {!data.automatic_monthly ? "On demand only: choose a month in Reports and email it whenever you want." : data.schedule_enabled && data.next_send_at ? `Next scheduled send: ${scheduled(data.next_send_at)}.` : "The administrator has paused scheduled delivery."}

) : (

{data.state === "pending" ? `Check ${data.email} for a confirmation link. It expires after 24 hours. No viewing history is emailed until you confirm.` : data.state === "expired" ? "Request a new confirmation link to turn on your recaps." : "Confirm your profile email to turn this on. You can unsubscribe from any recap or here in Profile."}

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

{data.detail}

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

You can subscribe now. Monthly sends will begin when your administrator starts the schedule.

)}
{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}

)}
); }