import { useEffect, useState } from "react"; import { useRelatedPersonServiceContext } from "../../../services"; import type { MemberClass } from "../../../services"; /** * WHERE A TEAM MEMBER IS FROM, on the line under their name. * * The approved deck states the requirement and the reason in one sentence: *"Every member says where * they are from. The feature exists because a team crosses organisations, so a member without their * practice beside them is missing the point of the row."* * * A collaboration team is the one surface in this product whose whole purpose is that its people come * from different organizations. Without this line a team of seven spanning three practices is seven * rows that look the same - and it is the row somebody reads before pressing **Remove**, where two * practitioners with similar names, one at the practice they have left and one at the practice they * are with, are otherwise indistinguishable at the moment of the decision. */ /** * THREE ANSWERS, NOT TWO, AND THE DIFFERENCE IS THE POINT. * * The server sends `organizationDisplays` in three states and this component says each of them out * loud, because two of them used to arrive as the same blank line: * * names the practices, joined - a practitioner at two of them is shown both, because * picking one silently is the same failure as naming the wrong person * EMPTY answered, and they belong to no organization. An outside practitioner is a * first-class member of a team rather than a failed lookup, and the ruling that no * org-less surface carries a placeholder organization is why nothing is invented here * ABSENT not answered - the read failed or the cap was reached. It says so, rather than * leaving a gap that reads as "they have no practice" * * A blank line where a practice belongs is a claim about the person, and on this screen it is a claim * made to somebody who may be about to remove them. */ /** * THE SPECIALTY, NOT THE FILING CABINET IT LIVES IN. * * Measured on the mount 2026-09-08. The coding display a real practitioner carries is the provider * taxonomy's full path: * * Behavioral Health & Social Service Providers; Counselor * Behavioral Health & Social Service Providers; Drama Therapist * Cardiovascular Disease Physician * * On a 390 frame the first two wrapped to three lines and pushed the practice - the thing the row * was rebuilt to say - onto the end of a paragraph. The approved deck writes specialties at the * other end of that path: *Family medicine*, *Orthopaedics*, *Cardiology*. * * THE LAST SEGMENT IS THE SPECIALTY AND THE ONES BEFORE IT ARE THE CATEGORY. "Counselor" is what * somebody is; "Behavioral Health & Social Service Providers" is where a directory files them, and a * patient reading who is on their care team is not browsing a directory. * * A DISPLAY THAT CARRIES NO PATH IS LEFT EXACTLY AS IT IS, which is the common case and the reason * this is a trim rather than a parse: nothing is looked up, nothing is inferred, and a value we do * not recognise passes through untouched. */ export const specialtyLabel = (display: string): string => { const segments = display.split(";").map((segment) => segment.trim()).filter(Boolean); return segments[segments.length - 1] ?? display; }; const PractitionerAffiliation = ({ organizationDisplays, specialtyDisplays, }: { organizationDisplays?: string[]; specialtyDisplays?: string[]; }) => { // WHAT THEY PRACTISE, THEN WHERE - the deck's order, and the useful one: on a team assembled // across organizations the specialty is often the reason somebody is on it at all. // // BUILT BY FILTERING RATHER THAN BY CONCATENATION, which is the control on this card wearing a // typographic coat: a middot with empty space in front of it reads as a value that failed to // load, not as one that was never there. A practitioner with no specialty coded shows the // practice alone, and nothing announces the difference because there is nothing to announce. const specialty = specialtyDisplays?.map(specialtyLabel).join(" · "); if (!organizationDisplays) { return (
{[specialty, "Practice not available"].filter(Boolean).join(" · ")}
); } if (organizationDisplays.length === 0) { return ({[specialty, "Outside practitioner"].filter(Boolean).join(" · ")}
); } return ({[specialty, ...organizationDisplays].filter(Boolean).join(" · ")}
); }; /** * "Your spouse", from the relationship the patient already recorded. * * Lower-cased after the first word rather than printed as stored: the text is a label somebody typed * at the desk or a coding's display, so its capitalisation belongs to whoever wrote it and "Your * Spouse" reads as a title. */ const relationshipPhrase = (text: string | undefined): string | undefined => { const trimmed = text?.trim(); if (!trimmed) return undefined; return `Your ${trimmed.charAt(0).toLowerCase()}${trimmed.slice(1)}`; }; /** * A related person has no practice, so this line carries what they are to the patient instead. * * RESOLVED ON THE CLIENT, and that is not the inconsistency it looks like beside the practitioner * half. The relationship is the patient's own record of their own helper: their token reads it, the * service already caches the list, and the reason the practitioner's practice has to come from the * server - that a patient cannot read anybody outside their own organization - simply does not apply. * * Its absence is left silent rather than announced. Unlike a missing practice there is nothing a * blank could be mistaken for here: the row is a person the patient added, not an organization that * failed to resolve. */ const RelatedPersonAffiliation = ({ id }: { id: string | undefined }) => { const { fetchRelatedPerson } = useRelatedPersonServiceContext(); const [phrase, setPhrase] = useState{phrase}
: null; }; export const MemberAffiliation = ({ memberRef, memberClass, organizationDisplays, specialtyDisplays, }: { memberRef: string; memberClass: MemberClass; organizationDisplays?: string[]; specialtyDisplays?: string[]; }) => { // AN OUTSTANDING EMAIL INVITE IS NOT AN UNRESOLVED PRACTICE. Their memberRef is a hash of the // address rather than a reference, so the server never looks their roles up and the field is // always absent - which "Practice not available" would misreport as a failed read. There is // genuinely nothing to say until they accept, and the row already shows the address. if (memberClass === "external-practitioner") return null; if (memberClass === "related-person") { return