import { useCallback, useEffect, useState } from "react"; import type { Organization, Location } from "fhir/r4"; import { useLocationServiceContext } from "../../../../services/LocationService.tsx"; import { formatSingleAddress } from "../../../../utils/fhirAddress.tsx"; import { getFirstContactPointBySystem } from "../../../../utils/fhirContactPoint.tsx"; import { formatPhoneNumber } from "../../../../utils/phoneNumber.tsx"; import { OrgSection } from "./OrgSection.tsx"; import { sectionReadFailure, type SectionReadFailure } from "../../../../utils/sectionReadRefusal"; import { SectionReadNotice } from "./SectionReadNotice.tsx"; export const OrgInfoSection = ({ organization }: { organization: Organization }) => { const { fetchLocations } = useLocationServiceContext(); const [locations, setLocations] = useState([]); // THE SNEAKIEST OF THE THREE REFUSALS ON THIS PAGE, because it left no sentence to disbelieve: the // Location read answered 403, the error was discarded, and the block below simply was not rendered. // An absent block is the same false assertion as a wrong one with less to read. // // A GENUINELY EMPTY LIST STILL RENDERS NOTHING, and that is the distinction rather than an // inconsistency. This is a sub-block of the practice's identity card, not a section of its own, so a // practice with no locations on file is describing itself completely by not having one. const [failure, setFailure] = useState(null); const practice = organization.name || "This practice"; const load = useCallback(() => { let cancelled = false; setFailure(null); fetchLocations(organization) .then(b => { if (!cancelled) setLocations((b.entry ?? []).map(e => e.resource as Location)); }) .catch(readError => { if (!cancelled) setFailure(sectionReadFailure(readError)); }); return () => { cancelled = true; }; }, [organization, fetchLocations]); useEffect(() => load(), [load]); /** * NOTHING AT ALL WHEN THERE IS NOTHING TO SAY, rather than an empty bordered box. * * This used to open with the practice's logo, name and phone. That was right while this was a PAGE * and the row that named the practice was on the screen you came from; the body is a sibling of that * row inside the same card now, so it was drawing the practice's identity a second time two lines * under the first. The deck opens the card with the street address for that reason and never repeats * the name. * * WHAT SURVIVES IS THE HALF THAT EARNED ITS PLACE: the locations, and the refusal notice when that * read is denied. A 403 here once rendered as nothing at all - the sneakiest of the three refusals on * this screen, because it left no sentence to disbelieve. */ if (!failure && locations.length === 0) { return null; } return ( {failure ? ( { load(); }} /> ) : (
{/* * `divide-line-soft`, NOT bare `divide-y` - see the note on the Card in `OrgDetailBody`. * `divide-y` sets a border WIDTH only and the colour falls through to Tailwind preflight's * `#e5e7eb`, which belongs to no palette here. * * ⚖️ AND THE TOKEN IS THE SOFT ONE, DELIBERATELY. This card runs a two-level hairline system: * `--line` separates the card's own BANDS, `--line-soft` separates ROWS inside one - which is * exactly what `ProviderAccessSection` already uses for the three agreement rows * (`border-t border-line-soft`). Bare `divide-y` flattened both levels onto the same foreign * grey, so a location row was divided as strongly as the band boundary above it, and the two * sibling sections drew their rows in two different colours: * * location row (here) rgb(229, 231, 235) preflight * agreement row (ProviderAccess) rgb(240, 237, 231) --line-soft */} {locations.map((loc) => { const address = loc.address ? formatSingleAddress(loc.address) : ""; const phone = getFirstContactPointBySystem(loc.telecom, "phone")?.value; return (
{/* The deck's `.pd-loc`: the name is a BLOCK, so it takes its own line, and everything else is one muted line under it - not three. */} {loc.name || "Location"} {/* * AN ABSENCE EXPLAINED BEATS AN ABSENCE DELETED, and this line is the second attempt * at the same defect. * * The first form rendered "Video Visit — " with a trailing em-dash and nothing after * it, which read like something had failed to load; the fix filtered the empty part * away. That fixed the wrong half. A row that says only "Video visit" leaves the * patient wondering whether the address failed to load - which is exactly what the * first fix existed to stop - on the screen they opened to find out where to go. * * So it SAYS SO. A location with no address on file has one for a reason, and the * reason is the useful sentence. */} {address || "No address — you join from here"} {/* A `tel:` LINK, unlike the number on the CLOSED row above. That row is a button, and an interactive element inside another resolves by dropping one; this is ordinary content inside an opened card, so the number becomes the control it should be. */} {phone && ( <> {" · "} {/* `text-primary`, the NAMED class. The base rule for an `a` under the mount id sets `color: inherit`, and an arbitrary `text-[var(--primary)]` is emitted bare - so it loses the cascade and the number paints as body text. */} {formatPhoneNumber(phone)} )}
); })}
)}
); };