"use client"; import { useCallback, useEffect, useState, type ReactNode, } from "react"; import { usePortalAuth } from "@/components/auth/portal-auth-provider"; import { clearPortalSession, fetchPortalSession, type AuthMethod, } from "@/lib/portal-session"; export type PortalIdentity = { isLoading: boolean; isSignedIn: boolean; label: string | null; source: "briven" | "demo" | "wallet" | "konnos" | null; userId: string | null; walletAddress: string | null; method: AuthMethod | null; signOut: () => Promise; }; /** * Identity for dashboard gates. Any login method (email OTP, Konnos, MetaMask, * later mavi) mints first-party /api/session so the user stays signed in. */ export function IdentityConsumer({ children, }: { children: (identity: PortalIdentity) => ReactNode; }) { const { brivenConfigured } = usePortalAuth(); if (brivenConfigured) { return {children}; } return {children}; } function DemoIdentityConsumer({ children, }: { children: (identity: PortalIdentity) => ReactNode; }) { const portal = usePortalAuth(); const identity: PortalIdentity = { isLoading: false, isSignedIn: Boolean(portal.demoSession), label: portal.demoSession?.label ?? null, source: portal.demoSession?.kind ?? null, userId: portal.demoSession?.userId ?? null, walletAddress: portal.demoSession?.walletAddress ?? null, method: portal.demoSession?.kind === "wallet" ? "wallet" : "demo", signOut: async () => { portal.clearDemo(); }, }; return <>{children(identity)}; } function SessionIdentityConsumer({ children, }: { children: (identity: PortalIdentity) => ReactNode; }) { const portal = usePortalAuth(); const [loading, setLoading] = useState(true); const [userId, setUserId] = useState(null); const [email, setEmail] = useState(null); const [method, setMethod] = useState(null); const [walletAddress, setWalletAddress] = useState(null); const refresh = useCallback(async () => { const s = await fetchPortalSession(); if (s.authenticated) { setUserId(s.userId); setEmail(s.email ?? null); setMethod(s.method ?? null); setWalletAddress(s.walletAddress ?? null); } else if (portal.demoSession) { setUserId(portal.demoSession.userId); setEmail( portal.demoSession.kind === "demo" ? portal.demoSession.label : null, ); setMethod( portal.demoSession.kind === "wallet" ? "wallet" : "demo", ); setWalletAddress(portal.demoSession.walletAddress ?? null); } else { setUserId(null); setEmail(null); setMethod(null); setWalletAddress(null); } setLoading(false); }, [portal.demoSession]); useEffect(() => { void refresh(); const onFocus = () => void refresh(); window.addEventListener("focus", onFocus); window.addEventListener("krypco-auth-change", onFocus); return () => { window.removeEventListener("focus", onFocus); window.removeEventListener("krypco-auth-change", onFocus); }; }, [refresh]); const signedIn = Boolean(userId) || Boolean(portal.demoSession); const source: PortalIdentity["source"] = (() => { if (method === "wallet" || portal.demoSession?.kind === "wallet") return "wallet"; if (method === "konnos") return "konnos"; if (method === "demo" || portal.demoSession?.kind === "demo") return "demo"; if (userId) return "briven"; return null; })(); const label = email || (walletAddress ? `${walletAddress.slice(0, 6)}…${walletAddress.slice(-4)}` : null) || portal.demoSession?.label || userId; const identity: PortalIdentity = { isLoading: loading, isSignedIn: signedIn, label, source, userId: userId || portal.demoSession?.userId || null, walletAddress: walletAddress || portal.demoSession?.walletAddress || null, method: method || (portal.demoSession?.kind === "wallet" ? "wallet" : null), signOut: async () => { try { await fetch("/api/auth/signout", { method: "POST", credentials: "include", headers: { "content-type": "application/json", rid: "session", }, body: "{}", }).catch(() => null); await clearPortalSession(); } finally { portal.clearDemo(); setUserId(null); setEmail(null); setMethod(null); setWalletAddress(null); window.dispatchEvent(new Event("krypco-auth-change")); } }, }; return <>{children(identity)}; }