"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { useAuth, useAppShell } from "@abe-kap/appshell-sdk/react"; import { PortalAside, PanelBrand } from "@/components/portal/parts"; import { CookieBanner, Spinner } from "@/components/portal/bits"; import { isShellConfigured } from "@/lib/appshell"; /** * Team invitation landing page (/portal/invite?token=…). Redeems the invite: * - not signed in → send to registration; it redeems the stashed token on finish. * - signed in but no CRM profile → send to onboarding; it redeems on finish. * - signed in + registered → accept now (creates the membership with the invited role). * The token (a 128-hex secret emailed to the invitee) is the authorization. */ export default function InvitePage() { const router = useRouter(); const { status, getUserEmail } = useAuth(); const { ready, sdk } = useAppShell(); const [error, setError] = useState(""); useEffect(() => { let token = ""; try { token = new URLSearchParams(window.location.search).get("token") ?? ""; } catch { /* ignore */ } if (!token) { setError("This invitation link is invalid or incomplete."); return; } try { sessionStorage.setItem("invite_token", token); } catch { /* ignore */ } // No Shell (local/mock) → just go register. if (!isShellConfigured()) { router.replace("/portal/register"); return; } if (!ready) return; let cancelled = false; (async () => { if (status === "unauthenticated") { router.replace("/portal/register"); // sign up first; finish() redeems the token return; } // Authenticated: registered users accept immediately; profile-less users onboard. try { const st = await sdk.query<{ registered: boolean }>("crm.account.registrationStatus"); if (!st?.registered) { try { const em = await getUserEmail(); if (em) sessionStorage.setItem("onboard_email", em); } catch { /* ignore */ } router.replace("/portal/onboarding"); return; } } catch { /* fall through to accept */ } try { await sdk.command("crm.team.invitation.accept", { token }); try { sessionStorage.removeItem("invite_token"); } catch { /* ignore */ } router.replace("/dashboard"); } catch { if (!cancelled) setError("We couldn't accept this invitation — it may have expired or already been used."); } })(); return () => { cancelled = true; }; }, [ready, status, router, sdk, getUserEmail]); return (
{error ? ( <>

Invitation problem

{error}

) : (

Accepting your invitation…

Setting up your team access.

)}
); }