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, FhirQuantity, FhirReference, FhirReferenceCollection } from '../../components'; import { useFhirConditions, useFhirEncounters, useFhirImmunizationBroadcast, useFhirImmunizations, useFhirLocations, useFhirObservations } 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 FhirImmunizationProps { 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` }); return ( { switch (referenceType) { default: return []; } }} required={true} disabled={disabled} readonly={readonly} multiple={false} enableInlineActions={enableInlineActions}/> ); }; export const FhirImmunization: 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 [immunizationStatus, setImmunizationStatus] = useState([]); const [immunizationStatusReason, setImmunizationStatusReason] = useState([]); const [vaccineCode, setVaccineCode] = useState([]); const [usCoreVaccineCode, setUsCoreVaccineCode] = useState([]); const [immunizationOrigin, setImmunizationOrigin] = useState([]); const [immunizationSite, setImmunizationSite] = useState([]); const [immunizationRoute, setImmunizationRoute] = useState([]); const [immunizationFunction, setImmunizationFunction] = useState([]); const [immunizationReason, setImmunizationReason] = useState([]); const [immunizationSubpotentReason, setImmunizationSubpotentReason] = useState([]); const [immunizationProgramEligibility, setImmunizationProgramEligibility] = useState([]); const [immunizationFundingSource, setImmunizationFundingSource] = useState([]); const [immunizationTargetDisease, setImmunizationTargetDisease] = useState([]); const [mvxManufacturer, setMvxManufacturer] = useState([]); const isPatient = [USER_ROLES.PATIENT, USER_ROLES.RELATED_PERSON].includes(userRole as string); const spacerMargin = '24px'; useFhirImmunizations(); useFhirImmunizationBroadcast(); const { locationsList } = useFhirLocations(); const { encountersList } = useFhirEncounters(); const { conditionsList } = useFhirConditions(); const { observationsList } = useFhirObservations(); const performerFieldArray = useFieldArray({ control, name: 'performer' }); const reactionFieldArray = useFieldArray({ control, name: 'reaction' }); const protocolAppliedFieldArray = useFieldArray({ control, name: 'protocolApplied' }); const reasonReferenceFieldArray = useFieldArray({ control, name: 'reasonReference' }); const educationFieldArray = useFieldArray({ control, name: 'education' }); useEffect(() => { const loadValueSets = async () => { setLoading(true); try { const [ immunizationStatusValueSet, immunizationStatusReasonValueSet, vaccineCodeValueSet, usCoreVaccineCodeValueSet, immunizationOriginValueSet, immunizationSiteValueSet, immunizationRouteValueSet, immunizationFunctionValueSet, immunizationReasonValueSet, immunizationSubpotentReasonValueSet, immunizationProgramEligibilityValueSet, immunizationFundingSourceValueSet, immunizationTargetDiseaseValueSet, mvxManufacturerValueSet ] = await Promise.all([ fetchValueSet(valueSetUrls.immunizationStatus), fetchValueSet(valueSetUrls.immunizationStatusReason), fetchValueSet(valueSetUrls.vaccineCode), fetchValueSet(valueSetUrls.usCoreVaccineCode), fetchValueSet(valueSetUrls.immunizationOrigin), fetchValueSet(valueSetUrls.immunizationSite), fetchValueSet(valueSetUrls.immunizationRoute), fetchValueSet(valueSetUrls.immunizationFunction), fetchValueSet(valueSetUrls.immunizationReason), fetchValueSet(valueSetUrls.immunizationSubpotentReason), fetchValueSet(valueSetUrls.immunizationProgramEligibility), fetchValueSet(valueSetUrls.immunizationFundingSource), fetchValueSet(valueSetUrls.immunizationTargetDisease), fetchValueSet(valueSetUrls.mvxManufacturer) ]); setImmunizationStatus(immunizationStatusValueSet); setImmunizationStatusReason(immunizationStatusReasonValueSet); setVaccineCode(vaccineCodeValueSet); setUsCoreVaccineCode(usCoreVaccineCodeValueSet); setImmunizationOrigin(immunizationOriginValueSet); setImmunizationSite(immunizationSiteValueSet); setImmunizationRoute(immunizationRouteValueSet); setImmunizationFunction(immunizationFunctionValueSet); setImmunizationReason(immunizationReasonValueSet); setImmunizationSubpotentReason(immunizationSubpotentReasonValueSet); setImmunizationProgramEligibility(immunizationProgramEligibilityValueSet); setImmunizationFundingSource(immunizationFundingSourceValueSet); setImmunizationTargetDisease(immunizationTargetDiseaseValueSet); setMvxManufacturer(mvxManufacturerValueSet); } 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); }; const addReaction = () => { reactionFieldArray.append({ date: '', detail: null, reported: false }); }; const removeReaction = (index: number) => { reactionFieldArray.remove(index); }; const addProtocolApplied = () => { protocolAppliedFieldArray.append({ series: '', authority: null, targetDisease: [], doseNumberPositiveInt: null, doseNumberString: '', seriesDosesPositiveInt: null, seriesDosesString: '' }); }; const removeProtocolApplied = (index: number) => { protocolAppliedFieldArray.remove(index); }; const addEducation = () => { educationFieldArray.append({ documentType: '', reference: '', publicationDate: '', presentationDate: '' }); }; const removeEducation = (index: number) => { educationFieldArray.remove(index); }; return ( {elevated && } Details {/* vaccineCode */} {/* status */} {watch('status') && watch('status') === 'not-done' && ( <> {/* statusReason */} )} {/* lotNumber */} ( )}/> {/* manufacturer - an MVX code, stored as manufacturer.identifier */} {/* expirationDate */} ( )}/> {/* occurrenceDateTime */} ( <> {fieldState.error && ( Vaccine administration date is required )} )}/> {/* recorded */} ( )}/> {/* primarySource */} ( )}/> {watch('primarySource') === false && ( <> {/* reportOrigin */} )} {/* encounter */} {/* location */} {(tab) => { // administration if (tab.name === 'administration') { return (
{/* site */} {/* route */} {/* doseQuantity */} {/* isSubpotent */} ( )}/> {watch('isSubpotent') && ( <> {/* subpotentReason */} )}
); } // protocol tab if (tab.name === 'protocol') { return (
{protocolAppliedFieldArray.fields.length === 0 && ( <> Protocol followed by the provider {!isPatient && ( )} No protocols added yet. )} {protocolAppliedFieldArray.fields.map((field, index) => (

Protocol {index + 1}

{!isPatient && ( )}
{/* series */} ( )}/> {/* targetDisease */} {/* doseNumberPositiveInt */} ( <> field.onChange(parseInt(value) || null)}/> {fieldState.error && ( Dose number within series is required )} )}/> {/* seriesDosesPositiveInt */} ( field.onChange(parseInt(value) || null)}/> )}/>
))} {!isPatient && protocolAppliedFieldArray.fields.length > 0 && ( )}
); } // reasons if (tab.name === 'reasons') { return (
{/* reasonCode */} {/* programEligibility */} {/* fundingSource */} {/* reasonReference */} { switch (referenceType) { case 'Condition': return conditionsList; case 'Observation': return observationsList; default: return []; } }} required={false} disabled={disabled} readonly={isPatient} enableInlineActions={enableInlineActions}/>
); } // reactions if (tab.name === 'reactions') { return (
{reactionFieldArray.fields.length === 0 && ( <> Reactions {!isPatient && ( )} No reactions added yet. )} {reactionFieldArray.fields.map((field, index) => (

Reaction {index + 1}

{!isPatient && ( )}
{/* reaction.date */} ( )}/> {/* reaction.detail */} {/* reaction.reported */} ( )}/>
))} {!isPatient && reactionFieldArray.fields.length > 0 && ( )}
); } // performers if (tab.name === 'performers') { return (
{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 && ( )}
); } if (tab.name === 'education') { return (
{educationFieldArray.fields.length === 0 && ( <> Educational material presented to patient {!isPatient && ( )} No education materials added yet. )} {educationFieldArray.fields.map((field, index) => (

Educational material presented to patient {index + 1}

{!isPatient && ( )}
{/* education.documentType */} ( )}/> {/* education.reference */} ( )}/> {/* education.publicationDate */} ( )}/> {/* education.presentationDate */} ( )}/>
))} {!isPatient && educationFieldArray.fields.length > 0 && ( )}
); } // notes if (tab.name === 'notes') { return (
{/* note */}
); } }}
); }; export default FhirImmunization;