"use client"; import { useEffect, useRef, useState, Suspense } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { useAuth } from "@/context/AuthContext"; function BetaMagicPageContent() { const params = useSearchParams(); const token = params.get("token"); const router = useRouter(); const { setSession } = useAuth(); const ran = useRef(false); const [status, setStatus] = useState<"loading" | "success" | "error">("loading"); const [message, setMessage] = useState("Signing you in…"); useEffect(() => { if (!token) { setStatus("error"); setMessage("Missing token."); return; } // ✅ Prevent double-call (Strict Mode / rerenders) if (ran.current) return; ran.current = true; (async () => { try { const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://battlbuilder-api:8080"}/api/auth/magic/exchange`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token }), }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error(text || "Magic link failed"); } const data = await res.json(); // Your AuthContext expects { token, email, displayName, role } // and stores it in localStorage. // We can simulate "login" by directly setting localStorage like AuthContext does, // but easiest is just to store it here in the same shape. setSession(data.token ?? data.accessToken, { uuid: data.uuid ?? data.id, email: data.email, displayName: data.displayName ?? null, role: data.role ?? "USER", }); setStatus("success"); setMessage("You’re in. Redirecting…"); router.replace("/account?welcome=1"); } catch (e: any) { setStatus("error"); setMessage(e?.message || "Magic link expired. Request a new one."); } })(); }, [token, router, setSession]); return (

Battl Builders

{message}

{status === "error" && (
Try going back to your inbox and requesting a fresh sign-in link.
)}
); } export default function BetaMagicPage() { return (

Battl Builders

Loading…

}>
); }