'use client'; import { Suspense, useEffect, useState } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { Logo } from '@/components/logo'; import { apiFetch } from '@/lib/api'; function CallbackInner() { const router = useRouter(); const params = useSearchParams(); const token = params.get('token'); const [state, setState] = useState<'verifying' | 'ok' | 'error'>('verifying'); const [error, setError] = useState(null); useEffect(() => { if (!token) { setState('error'); setError('Missing token'); return; } (async () => { try { await apiFetch('/v1/auth/verify', { method: 'POST', body: JSON.stringify({ token }), }); setState('ok'); setTimeout(() => router.replace('/dashboard'), 200); } catch (err) { setState('error'); setError((err as Error).message); } })(); }, [token, router]); return (
{state === 'verifying' && (

Verifying your magic link…

)} {state === 'ok' && (

Signed in. Redirecting…

)} {state === 'error' && ( <>

Could not verify magic link.

{error &&

{error}

} )}
); } // useSearchParams() requires a Suspense boundary or `next build` cannot // statically render this route. export default function CallbackPage() { return (

Verifying your magic link…

} >
); }