import React, { useState, useEffect } from "react"; import { DismissibleAlert } from '../ui/dismissible-alert'; import { useFormContext, useWatch, Controller } from "react-hook-form"; import { useValueSetServiceContext } from "../../services"; import { FhirCodeableConcept, PhotoAttachment } from "../../components"; import { Attachment } from "fhir/r4"; import { useFhirRelatedPersonBroadcast, useFhirRelatedPersons, } from "../../hooks"; import { Input } from "../ui/input"; import { Field, FieldLabel } from "../ui/field"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../ui/select"; import { RelationValueSetList, relationshipType } from "./FhirRelations"; import { AuthorityTier, TIER_DESCRIPTIONS, TIER_LABELS, } from "../../services/relatedPersonAuthority"; import { TierChoices } from "../FhirRelatedPersonDisplay/TierChoices"; import { BILLING_DEPENDENCY_NOTE, INVITE_TIER_DESCRIPTIONS } from "../FhirRelatedPersonDisplay/tierWords"; import { Switch } from "../ui/switch"; // F1 authority tier picker order - mirrors CareAccess.tsx's TIER_ORDER (the post-create "Care access" // control). Kept local rather than re-exported from relatedPersonAuthority.ts to avoid touching that // file for a 3-item literal outside this task's scope. const TIER_ORDER: AuthorityTier[] = [ "assist-only", "scheduling-forms", "full-proxy", ]; interface FhirRelatedPersonProps { elevated?: boolean; disabled?: boolean; photo: Attachment | undefined; onPhotoChange: (photo: Attachment | undefined) => void; isNew: boolean; enableInlineActions?: boolean; /** The patient inviting someone: their own words, and the tiers as choices. */ patientVoice?: boolean; } export const FhirRelatedPerson: React.FC = ({ elevated = true, disabled = false, photo, onPhotoChange, isNew, patientVoice = false, }) => { const { control, setValue } = useFormContext(); const inviteTier = useWatch({ control, name: "tier" }) as AuthorityTier | undefined; const inviteSeesInvoices = useWatch({ control, name: "allowBillingView" }) === true; const { fetchValueSet, valueSetUrls } = useValueSetServiceContext(); const [loading, setLoading] = useState(false); // Watch form values for debugging (optional) // const formValues = watch(); // value sets // const [languages, setLanguages] = useState([]); const [relatedPersonRelationshipType, setRelatedPersonRelationshipType] = useState([]); useFhirRelatedPersons(); useFhirRelatedPersonBroadcast(); useEffect(() => { const loadValueSets = async () => { setLoading(true); try { await Promise.all([ // fetchValueSet(valueSetUrls.languages), fetchValueSet(valueSetUrls.relatedPersonRelationshipType), ]); // setLanguages(languagesValueSet || []); setRelatedPersonRelationshipType(relationshipType || []); } catch (err) { console.error("Error loading value sets:", err); } finally { setLoading(false); } }; loadValueSets(); }, [fetchValueSet, valueSetUrls]); // The patient's invitation, as the family deck draws it: who, how they are related, what they may do. if (patientVoice) { return (

Who

{isNew && ( ( <> {fieldState.error && ( {fieldState.error.message} )} )} /> )} ( <> {fieldState.error && ( {fieldState.error.message} )} )} /> ( <> {fieldState.error && ( {fieldState.error.message} )} )} />
{isNew && ( <>

What they may do

( { // Messaging comes with the higher tiers; dropping back starts it off, as in the permissions panel. if (next === "assist-only" && field.value !== "assist-only") setValue("allowMessaging", false); field.onChange(next); }} disabled={disabled} /> )} />

Separately

{(inviteTier ?? "assist-only") === "assist-only" && ( (
field.onChange(on === true)} />
)} /> )} (
{ if (on !== true) setValue("allowBillingPay", false); field.onChange(on === true); }} />
)} /> (
field.onChange(on === true)} />
)} />

{BILLING_DEPENDENCY_NOTE}

)}
); } return (
{/* Email - Only show for new records */} {isNew && (
( <> {patientVoice ? "Their email address" : "Login Mail"} {fieldState.error && ( {fieldState.error.message} )} )} />
)} {/* First Name */}
( <> {patientVoice ? "First name" : "First Name"} {fieldState.error && ( {fieldState.error.message} )} )} />
{/* Last Name */}
( <> {patientVoice ? "Last name" : "Last Name"} {fieldState.error && ( {fieldState.error.message} )} )} />
{/* F1 authority tier — captured only at invite; adjustable afterward via the "Care access" control on the related person's detail sheet (CareAccess.tsx), not here. RelatedPerson is a thin link with no demographics, so this replaces the old birthDate/gender/prefix/suffix fields entirely rather than sitting alongside them. */} {isNew && (
{ const currentTier = (field.value as AuthorityTier) || "assist-only"; return (
Care access level

{TIER_DESCRIPTIONS[currentTier]}

{fieldState.error && ( {fieldState.error.message} )}
); }} />
)} {/* Relationship */}
); }; export default FhirRelatedPerson;