import { useEffect, useRef, useState } from "react"; import { useLocation } from "react-router-dom"; import { Card } from "../../components/ui/card"; import { Button } from "../../components/ui/button"; import { Input } from "../../components/ui/input"; import { Label } from "../../components/ui/label"; import { environment } from "../../environments/environment.ts"; import { parseAcceptInviteParams } from "./acceptInviteParams"; import { akashicFetch } from "../../config/clientManifest"; type Status = "ready" | "working" | "accepted" | "invalid" | "failed"; const UNKNOWN = "We could not confirm the acceptance. Try again."; export const AcceptCareTeamInvitePage = () => { const { search } = useLocation(); const params = parseAcceptInviteParams(search); const key = params.ok ? JSON.stringify([params.token, params.email]) : `invalid:${search}`; const opening = useRef({ key }); if (opening.current.key !== key) opening.current = { key }; const owner = opening.current; const mounted = useRef(true); const pending = useRef(); useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []); const [state, setState] = useState({ owner, status: params.ok ? "ready" as Status : "invalid" as Status, firstname: "", lastname: "", error: "" }); const current = state.owner === owner ? state : { owner, status: params.ok ? "ready" as Status : "invalid" as Status, firstname: "", lastname: "", error: "" }; const { status, firstname, lastname, error } = current; const belongs = () => mounted.current && opening.current === owner; const publish = (next: Partial) => { if (belongs()) setState(previous => ({ ...(previous.owner === owner ? previous : current), ...next, owner })); }; const accept = async () => { if (!params.ok || !firstname.trim() || !lastname.trim() || pending.current === owner) return; pending.current = owner; publish({ status: "working", error: "" }); try { const response = await akashicFetch(`${environment.fhirClinicalApi}/collaboration-team-external-invite-accept`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: params.token, email: params.email, firstname: firstname.trim(), lastname: lastname.trim() }), }); const answer: unknown = await response.json(); if (!belongs()) return; const body = answer && typeof answer === "object" ? answer as Record : undefined; if (response.status === 200 && body?.status === "accepted" && typeof body.teamId === "string" && body.teamId) { publish({ status: "accepted" }); } else if (response.status === 400) { publish({ status: "ready", error: "Enter your first and last name." }); } else if (response.status === 403 && body?.code === "ACCOUNT_REFUSED") { publish({ status: "ready", error: typeof body.message === "string" ? body.message : "This account cannot accept this invitation." }); } else if (response.status === 403) { publish({ status: "invalid" }); } else if (response.status === 409 && body?.code === "INVITATION_BEING_ACCEPTED") { publish({ status: "ready", error: "This invitation is being accepted right now. Wait a moment, then try again." }); } else { publish({ status: "failed", error: UNKNOWN }); } } catch { publish({ status: "failed", error: UNKNOWN }); } finally { if (belongs() && pending.current === owner) pending.current = undefined; } }; return (

Join a patient's care team

{status === "invalid" &&

This invitation link is not valid. It may have already been used, or it may have expired.

Ask whoever invited you to send a new one — invitations can be re-sent.

} {status === "failed" &&

{error}

} {(status === "ready" || status === "working") &&

You have been invited to collaborate on a patient's care. Accepting creates your free Akashic account for {params.ok ? params.email : ""}.

This confirms who you are. You will not see the patient's record until they approve you and you have signed a business associate agreement.

publish({ firstname: event.target.value })} /> publish({ lastname: event.target.value })} /> {error &&

{error}

}
} {status === "accepted" &&

Your account is ready.

Sign in with {params.ok ? params.email : ""} to see this invitation. The patient still needs to approve your access, and you will be asked to sign a business associate agreement before you can view their record.

}
); }; export default AcceptCareTeamInvitePage;