import { useCallback, useEffect, useState } from "react"; import ReactDOM from "react-dom"; import { useLocation, useNavigate } from "react-router-dom"; import { useAuth } from "../hooks/useAuth"; import { listMyInvites, acceptInvite, rejectInvite, PendingInvite } from "../api/collaboration"; /** * Global watcher that pops an Accept/Reject modal whenever the signed-in user has * a pending collaboration invite — no matter what page they're on. The dedicated * /invite/:token page handles the link-click flow; this covers the "already logged * in" case (e.g. they land on the dashboard with an invite waiting). */ export default function InviteDecisionModal() { const { user } = useAuth(); const location = useLocation(); const navigate = useNavigate(); const [invite, setInvite] = useState(null); const [busy, setBusy] = useState<"accept" | "reject" | null>(null); const refresh = useCallback(async () => { if (!user) { setInvite(null); return; } try { const res = await listMyInvites(); setInvite(res.data[0] ?? null); } catch { /* ignore — transient; will retry on next navigation */ } }, [user]); // Check on login and on route changes (cheap; surfaces invites promptly). // Skip the dedicated invite page — it owns that flow itself. useEffect(() => { if (location.pathname.startsWith("/invite/")) { setInvite(null); return; } refresh(); }, [user, location.pathname, refresh]); if (!invite || location.pathname.startsWith("/invite/")) return null; const handleAccept = async () => { setBusy("accept"); try { const res = await acceptInvite(invite.invite_token); setInvite(null); navigate(`/project/${res.data.project_id}`, { replace: true }); } catch { // Likely already handled elsewhere — drop it and re-check. setInvite(null); refresh(); } finally { setBusy(null); } }; const handleReject = async () => { setBusy("reject"); try { await rejectInvite(invite.invite_token); } catch { /* ignore */ } finally { setBusy(null); setInvite(null); refresh(); } }; return ReactDOM.createPortal(

You're invited to collaborate

"{invite.project_name}"

{invite.invited_by && (

Invited by {invite.invited_by}

)}

You'll be able to co-edit this video's scenes.

, document.body, ); }