import React, { useState, useEffect } from 'react'; import { Card, CardHeader, CardBody, CardDivider } from '../ui/wp-card'; import { Elevation } from '../ui/elevation'; import { InputControl } from '../ui/input-control'; import { Divider } from '../ui/divider'; import { DismissibleAlert } from '../ui/dismissible-alert'; import { Heading } from '../ui/heading'; import { Flex, FlexItem } from '../ui/flex'; import { Spacer } from '../ui/spacer'; import { TabPanel } from '../ui/tab-panel'; import { Disabled } from '../ui/disabled'; import { useFormContext, Controller, useFieldArray } from 'react-hook-form'; import { IValueSet, useAuthServiceContext, useValueSetServiceContext } from '../../services'; import { FhirAnnotation, FhirCode, FhirCodeableConcept, FhirDosage, FhirQuantity, FhirReference, FhirReferenceCollection, FhirValueSetSearch, TypeSelector } from '../../components'; import { useFhirDetectedIssues, useFhirDevices, useFhirEncounters, useFhirEpisodesOfCare, useFhirLocations, useFhirMedicationDispenseBroadcast, useFhirMedicationDispenses, useFhirMedicationRequests, useFhirPractitioners, useFhirProcedures, useFhirRelatedPersons } from '../../hooks'; import { FhirResource } from 'fhir/r4'; import { PlusCircle, Trash2 } from 'lucide-react'; // - WordPress's ToggleControl, swapped for the ui/* adapter. Same props, same JSX; // only `__nextHasNoMarginBottom` is dropped, which means nothing outside WordPress. import { ToggleControl } from '../ui/toggle-control'; interface FhirMedicationDispenseProps { elevated?: boolean; disabled?: boolean; enableInlineActions?: boolean; } const PerformerActorReferences: React.FC<{ index: number; disabled: boolean; readonly: boolean; enableInlineActions: boolean; }> = ({ index, disabled, readonly = false, enableInlineActions = true }) => { const { control } = useFormContext(); const itemReferenceFieldArray = useFieldArray({ control, name: `performer.${index}.actor` }); const { practitionersList } = useFhirPractitioners(); const { relatedPersonsList } = useFhirRelatedPersons(); const { devicesList } = useFhirDevices(); return ( { switch (referenceType) { case 'Practitioner': return practitionersList.map(p => p.practitioner); case 'RelatedPerson': return relatedPersonsList; case 'Device': return devicesList; default: return []; } }} required={true} disabled={disabled} readonly={readonly} multiple={false} enableInlineActions={enableInlineActions}/> ); }; export const FhirMedicationDispense: React.FC = ({ elevated = true, disabled = false, enableInlineActions = true }) => { const { control, watch } = useFormContext(); const { userRole, USER_ROLES } = useAuthServiceContext(); const { fetchValueSet, valueSetUrls } = useValueSetServiceContext(); const [loading, setLoading] = useState(false); // value sets const [medicationdispenseStatus, setMedicationdispenseStatus] = useState([]); const [medicationdispenseStatusReason, setMedicationdispenseStatusReason] = useState([]); const [medicationdispenseCategory, setMedicationdispenseCategory] = useState([]); const [medicationdispensePerformerFunction, setMedicationdispensePerformerFunction] = useState([]); const [actPharmacySupplyType, setActPharmacySupplyType] = useState([]); const [actSubstanceAdminSubstitutionCode, setActSubstanceAdminSubstitutionCode] = useState([]); const [substanceAdminSubstitutionReason, setSubstanceAdminSubstitutionReason] = useState([]); const isPatient = [USER_ROLES.PATIENT, USER_ROLES.RELATED_PERSON].includes(userRole as string); const spacerMargin = '24px'; useFhirMedicationDispenses(); useFhirMedicationDispenseBroadcast(); const { locationsList } = useFhirLocations(); const { encountersList } = useFhirEncounters(); const { episodesOfCareList } = useFhirEpisodesOfCare(); const { proceduresList } = useFhirProcedures(); const { detectedIssuesList } = useFhirDetectedIssues(); const { medicationRequestsList } = useFhirMedicationRequests(); const { practitionersList } = useFhirPractitioners(); const medicationType = watch('medicationType'); const wasSubstituted = watch('substitution.wasSubstituted'); const performerFieldArray = useFieldArray({ control, name: 'performer' }); const contextFieldArray = useFieldArray({ control, name: 'context' }); useEffect(() => { const loadValueSets = async () => { setLoading(true); try { const [ medicationdispenseStatusValueSet, medicationdispenseStatusReasonValueSet, medicationdispenseCategoryValueSet, medicationdispensePerformerFunctionValueSet, actPharmacySupplyTypeValueSet, actSubstanceAdminSubstitutionCodeValueSet, substanceAdminSubstitutionReasonValueSet ] = await Promise.all([ fetchValueSet(valueSetUrls.medicationdispenseStatus), fetchValueSet(valueSetUrls.medicationdispenseStatusReason), fetchValueSet(valueSetUrls.medicationdispenseCategory), fetchValueSet(valueSetUrls.medicationdispensePerformerFunction), fetchValueSet(valueSetUrls.actPharmacySupplyType), fetchValueSet(valueSetUrls.actSubstanceAdminSubstitutionCode), fetchValueSet(valueSetUrls.substanceAdminSubstitutionReason) ]); setMedicationdispenseStatus(medicationdispenseStatusValueSet); setMedicationdispenseStatusReason(medicationdispenseStatusReasonValueSet); setMedicationdispenseCategory(medicationdispenseCategoryValueSet); setMedicationdispensePerformerFunction(medicationdispensePerformerFunctionValueSet); setActPharmacySupplyType(actPharmacySupplyTypeValueSet); setActSubstanceAdminSubstitutionCode(actSubstanceAdminSubstitutionCodeValueSet); setSubstanceAdminSubstitutionReason(substanceAdminSubstitutionReasonValueSet); } catch (err) { console.error('Error loading value sets:', err); } finally { setLoading(false); } }; loadValueSets(); }, [fetchValueSet, valueSetUrls]); const addPerformer = () => { performerFieldArray.append({ function: null, actor: null }); }; const removePerformer = (index: number) => { performerFieldArray.remove(index); }; return ( {elevated && } Details {/* medicationCodeableConcept */} {medicationType === 'codeableConcept' && ( <> )} {medicationType === 'reference' && ( <> {/* medicationReference */} )} {/* status */} {/* statusReason */} {watch('statusReason') === 'codeableConcept' && ( <> {/* statusReasonCodeableConcept */} )} {watch('statusReason') === 'reference' && ( <> {/* statusReasonReference */} )} {/* category */} {/* type */} {/* authorizingPrescription */} {/* location */} {/* destination */} {/* whenPrepared */} ( )}/> {/* whenHandedOver */} ( )}/> {/* detectedIssue */} {/* partOf */} {/* context */} { switch (referenceType) { case 'Encounter': return encountersList; case 'EpisodeOfCare': return episodesOfCareList; default: return []; } }} required={false} disabled={disabled} readonly={isPatient} multiple={false} enableInlineActions={enableInlineActions}/> {(tab) => { // quantities if (tab.name === 'quantities') { return (
{/* quantity */} {/* daysSupply */}
); } // dosage if (tab.name === 'dosage') { return (
{/* dosage */}
); } // substitution if (tab.name === 'substitution') { return (
Substitution Information {/* wasSubstituted */} ( )}/> {wasSubstituted && ( <> {/* substitution.type */} {/* substitution.reason */} {/* substitution.responsibleParty */} item.practitioner)} enableInlineActions={enableInlineActions} multiple={true} required={false} disabled={disabled}/> )}
); } // performers if (tab.name === 'performers') { return (
{/* The operands were the wrong way round - the JSX was the LEFT one, so the whole expression collapsed to a boolean and React rendered nothing. There was no Add Performer button and no empty state on this tab at all, which reads as a tab that simply has no content rather than one that is broken. */} {performerFieldArray.fields.length === 0 && ( <> {!isPatient && ( )} No performers added yet. )} {performerFieldArray.fields.map((field, index) => (

Performer {index + 1}

{!isPatient && ( )}
{/* performer.function */} {/* performer.actor */}
))} {!isPatient && performerFieldArray.fields.length > 0 && ( )}
); } // notes if (tab.name === 'notes') { return (
{/* note */}
); } return null; }}
); }; export default FhirMedicationDispense;