import { useEffect, useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { api, isLoggedIn } from "../api/client"; interface InviteInfo { id: string; band_id: string; token: string; role: string; expires_at: string; used_at: string | null; } export function InvitePage() { const { token } = useParams<{ token: string }>(); const navigate = useNavigate(); const [invite, setInvite] = useState(null); const [error, setError] = useState(null); const [accepting, setAccepting] = useState(false); const [done, setDone] = useState(false); const loggedIn = isLoggedIn(); useEffect(() => { if (!token) return; api.get(`/invites/${token}`) .then(setInvite) .catch((err) => setError(err instanceof Error ? err.message : "Invalid invite")); }, [token]); async function accept() { if (!token) return; setAccepting(true); try { await api.post(`/invites/${token}/accept`, {}); setDone(true); setTimeout(() => navigate("/"), 2000); } catch (err) { setError(err instanceof Error ? err.message : "Failed to accept invite"); } finally { setAccepting(false); } } function goLogin() { navigate(`/login?next=/invite/${token}`); } return (

◈ RehearsalHub

Band invite

{error && (
{error}
)} {done && (
Joined! Redirecting…
)} {!done && invite && ( <>

You've been invited to join a band as {invite.role}.

Expires {new Date(invite.expires_at).toLocaleDateString()} {invite.used_at && " · Already used"}

{loggedIn ? ( ) : (

Log in or register to accept this invite.

)} )} {!done && !invite && !error && (

Loading invite…

)}
); }