'use client' import { useEffect, useRef, useState } from 'react' import { getApiBase } from '../lib/auth' import BrandingLogo from '../ui/BrandingLogo' import '../email-recaps/recaps.css' type LinkAction = { action: 'confirm' | 'unsubscribe'; token: string } export default function NewsletterLinkPage() { const [link, setLink] = useState(null) const [state, setState] = useState('loading') const [error, setError] = useState('') const [busy, setBusy] = useState(false) const currentLink = useRef(null) useEffect(() => { let controller: AbortController | null = null const checkLink = () => { controller?.abort() const abort = new AbortController() controller = abort setError(''); setState('loading'); setLink(null); setBusy(false); currentLink.current = null // Fragments stay out of web-server access logs and referrers. Opening the link only checks it. const params = new URLSearchParams(window.location.hash.slice(1)) const action = params.get('action') const token = params.get('token') || '' if ((action !== 'confirm' && action !== 'unsubscribe') || !/^[A-Za-z0-9_-]{40,100}$/.test(token)) { setError('This email link is incomplete. Open Profile to manage your newsletters.'); setState('error'); return } const payload = { action, token } as LinkAction currentLink.current = payload setLink(payload) void fetch(`${getApiBase()}/newsletter-subscription/check`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), signal: abort.signal, credentials: 'omit' }).then(async (response) => { const result = await response.json().catch(() => ({})) if (!response.ok) throw new Error(typeof result.detail === 'string' ? result.detail : 'Could not check this email link. Please open it again.') if (!abort.signal.aborted) setState(result.state) }).catch((err: Error) => { if (!abort.signal.aborted) { setError(err.message); setState('error') } }) } checkLink() window.addEventListener('hashchange', checkLink) return () => { currentLink.current = null; controller?.abort(); window.removeEventListener('hashchange', checkLink) } }, []) const apply = async () => { if (!link || busy) return const payload = link setBusy(true); setError('') try { const response = await fetch(`${getApiBase()}/newsletter-subscription/confirm`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), credentials: 'omit' }) const result = await response.json().catch(() => ({})) if (currentLink.current !== payload) return if (!response.ok) throw new Error(typeof result.detail === 'string' ? result.detail : 'Could not update your preference. Please try again.') setState(result.state) window.history.replaceState(null, '', '/newsletter-subscription') } catch (err) { if (currentLink.current === payload) setError(err instanceof Error ? err.message : 'Could not update your preference.') } finally { if (currentLink.current === payload) setBusy(false) } } const done = state === 'enabled' || state === 'off' return
Magent
Grizzlyflix newsletters

{state === 'enabled' ? 'You’re on the list.' : state === 'off' ? 'Newsletters are turned off.' : state === 'loading' ? 'Checking your email link' : state === 'error' ? 'This link needs another look' : link?.action === 'unsubscribe' ? 'Unsubscribe from newsletters?' : 'Your next watch starts here.'}

{state === 'enabled' ? 'Your email is confirmed. You’ll receive your personal viewing recap when the monthly schedule runs.' : state === 'off' ? 'You won’t receive further monthly recaps. You can turn them back on in Profile.' : state === 'ready' && link?.action === 'unsubscribe' ? 'This turns off new-arrival newsletters. Your personal monthly recaps are managed separately.' : state === 'ready' ? 'Confirm to receive new movies, TV updates and featured picks, with posters and links to watch.' : ''}

{error &&

{error}

} {state === 'ready' && } {(done || state === 'error') && Manage email preferences ↗} {state === 'loading' &&

One moment…

}
}