import React, { useRef, useState } from "react"; import { Spinner } from "../ui/spinner"; import { Elevation } from '../ui/elevation'; import { Modal } from '../ui/wp-modal-shim'; import { Organization, Attachment, Extension, Location } from "fhir/r4"; import { Card } from "../ui/card"; import { usePhotoUrl } from "../../hooks/usePhotoUrl"; import { usePhotoUploadService } from "../../services/PhotoUploadService"; import { Building2, Camera, Mail, MapPin, Pencil, Phone } from "lucide-react"; import { formatSingleAddress } from "../../utils/fhirAddress"; import { formatFhirContactPoint } from "../../utils/fhirContactPoint"; import { PRACTICE_TYPE_SYSTEM } from "../../utils/staffRoleCatalog"; import { ORG_LOGO_EXTENSION_URL } from "../../config/organizationExtensions"; const getOrgPhoto = ( organization: Organization | null, ): Attachment | undefined => { const ext = organization?.extension?.find( (e: Extension) => e.url === ORG_LOGO_EXTENSION_URL, ); return ext?.valueAttachment as Attachment | undefined; }; interface FhirOrganizationDisplayProps { organization: Organization | null; isOpen?: boolean; onClose?: () => void; title?: string; asModal?: boolean; onPhotoChange?: (photo: Attachment) => Promise | void; onMainInfoClick?: () => void; primaryLocation?: Location | null; primaryLocationDisplay?: string; onPrimaryLocationClick?: () => void; onPracticeTypeClick?: () => void; } export const FhirOrganizationDisplay: React.FC< FhirOrganizationDisplayProps > = ({ organization, isOpen = true, onClose, title = "Organization Details", asModal = true, onPhotoChange, onMainInfoClick, primaryLocation, primaryLocationDisplay, onPrimaryLocationClick, onPracticeTypeClick, }) => { const { url: orgImageUrl } = usePhotoUrl( getOrgPhoto(organization), "organization", ); const { uploadPhoto } = usePhotoUploadService(); const fileInputRef = useRef(null); const [uploading, setUploading] = useState(false); const mainPhone = formatFhirContactPoint( organization?.telecom, "phone", ", ", "Missing phone", ); // NOT "Missing email", AND THE DIFFERENCE IS WHETHER ANYBODY HAS TO ACT. A practice's phone IS // required - the setup checklist will not complete without one - so naming its absence is a true // instruction. An email address is deliberately not required: Spencer ruled on 2026-08-12 that the // phone is the channel and widening the requirement to "phone AND email" would stall practices on // something nobody asked for. So an empty one is simply empty, and the word "Missing" beside it sent // an administrator looking for a checklist item that does not exist, on a screen whose own counter // already read 13 of 13. const mainEmail = formatFhirContactPoint( organization?.telecom, "email", ", ", "—", ); const practiceTypeDisplay = (organization?.type ?? []) .flatMap((t) => t.coding ?? []) .filter((c) => c.system === PRACTICE_TYPE_SYSTEM) .map((c) => c.display || c.code || '') .filter(Boolean) .join(', '); const hasPrimaryLocation = !!primaryLocation || !!primaryLocationDisplay; const primaryLocationText = primaryLocationDisplay || (primaryLocation?.address ? formatSingleAddress(primaryLocation.address) : "Missing location"); const handleFileChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file || !onPhotoChange) return; setUploading(true); try { const { key, contentType, size } = await uploadPhoto( file, "org-asset", ); const newPhoto: Attachment = { // Named by key only: the server fills the bytes once this exact upload scans clean. contentType, url: key, title: file.name, size, creation: new Date().toISOString(), }; await onPhotoChange(newPhoto); } finally { setUploading(false); if (e.target) e.target.value = ""; } }; const renderContent = () => ( <>
Hospital {onPhotoChange && ( <> )}

{organization?.name || "Unnamed Organization"}

{onMainInfoClick && ( )}
{practiceTypeDisplay ? ( {practiceTypeDisplay} ) : ( No practice type set )} {onPracticeTypeClick && ( )}
); if (!asModal) { return (
{renderContent()}
); } if (!isOpen) return null; return ( {renderContent()} ); }; export default FhirOrganizationDisplay;