import React, { useState, useEffect } from 'react'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; import { Card, CardBody, CardDivider, CardHeader } from '../../../../components/ui/wp-card'; import { InputControl } from '../../../../components/ui/input-control'; import { Divider } from '../../../../components/ui/divider'; import { DismissibleAlert } from '../../../../components/ui/dismissible-alert'; import { Heading } from '../../../../components/ui/heading'; import { Flex, FlexItem } from '../../../../components/ui/flex'; import { Text } from '../../../../components/ui/text'; import { Spacer } from '../../../../components/ui/spacer'; import { TabPanel } from '../../../../components/ui/tab-panel'; import { Modal } from '../../../../components/ui/wp-modal-shim'; import { useForm, FormProvider, useFieldArray, Controller } from 'react-hook-form'; import { Medication } from 'fhir/r4'; import { Check, 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 '../../../../components/ui/toggle-control'; import { AppHeader, AppSpinner, FhirCode, FhirCodeableConcept, FhirRatio, FhirValueSetSearch, ProfileLayoutContainer } from '../../../../components'; import { IValueSet, useMedicationServiceContext, useValueSetServiceContext } from '../../../../services'; import { describeWriteFailure } from '../../../../utils/fetchFailureMessage'; const EditMedicationPage: React.FC = () => { const { medicationId } = useParams<{ medicationId: string }>(); const navigate = useNavigate(); const { state } = useLocation(); const { fetchMedication, transformToFhirMedication, transformFromFhirMedication, createMedication, updateMedication, deleteMedication, setMedicationState, setShouldReload, setMedicationsList, fetchMedicationsWithPolling, medicationsBundle } = useMedicationServiceContext(); const { fetchValueSet, valueSetUrls } = useValueSetServiceContext(); const [loading, setLoading] = useState(false); const [submitting, setSubmitting] = useState(false); const [success, setSuccess] = useState(); const [error, setError] = useState(); const [medication, setMedication] = useState(null); const [showDeleteModal, setShowDeleteModal] = useState(false); // value sets const [medicationStatus, setMedicationStatus] = useState([]); const [medicationFormCodes, setMedicationFormCodes] = useState([]); const isNew = medicationId === 'new'; const spacerMargin = '24px'; useEffect(() => { const loadValueSets = async () => { const [ medicationStatusValueSet, medicationFormCodesValueSet ] = await Promise.all([ fetchValueSet(valueSetUrls.medicationStatus), fetchValueSet(valueSetUrls.medicationFormCodes) ]); setMedicationStatus(medicationStatusValueSet); setMedicationFormCodes(medicationFormCodesValueSet); }; loadValueSets(); }, [fetchValueSet, valueSetUrls]); const methods = useForm({ defaultValues: { status: 'active', code: null, manufacturer: { reference: '', display: '' }, form: null, amount: { numerator: { value: '', unit: '', system: 'http://unitsofmeasure.org', code: '' }, denominator: { value: '', unit: '', system: 'http://unitsofmeasure.org', code: '' } }, ingredient: [], batch: { lotNumber: '', expirationDate: '' }, note: [] } }); const { control, handleSubmit, reset } = methods; const ingredientFieldArray = useFieldArray({ control, name: 'ingredient' }); useEffect(() => { const loadMedication = async () => { if (isNew || medication) return; const { medication: medicationState } = state ?? {}; if (medicationState) { const formData = transformFromFhirMedication(medicationState); reset(formData); setMedication(medicationState); return; } setLoading(true); try { const fetchedMedication = await fetchMedication(medicationId as string); const formData = transformFromFhirMedication(fetchedMedication); reset(formData); setMedication(fetchedMedication); } catch (err) { console.error('Error loading medication:', err); setError('Could not load medication. Try again.'); } finally { setLoading(false); } }; loadMedication(); }, [medicationId, isNew, fetchMedication, transformFromFhirMedication, reset, setMedicationState]); useEffect(() => { const loadMedications = async () => { try { await fetchMedicationsWithPolling(); } catch (error) { console.error('Failed to load medications:', error); setError(`Could not load medications. Try again.`); } }; if (!medicationsBundle) { loadMedications(); } }, [fetchMedicationsWithPolling, medicationsBundle]); const onSubmit = async (data: any) => { setSubmitting(true); setSuccess(undefined); setError(undefined); try { let result: Medication; if (isNew) { result = await createMedication(transformToFhirMedication(data)); setMedicationsList(prev => [...prev, result]); navigate(-1); } else { result = await updateMedication({ id: medication?.id, ...transformToFhirMedication(data) }); setMedicationsList(prev => prev.map(p => p.id === result.id ? result : p)); } setSuccess(`Medication ${isNew ? 'created' : 'updated'} successfully.`); } catch (err: any) { console.error(`Error ${isNew ? 'creating' : 'updating'} medication:`, err); setError(describeWriteFailure(err, `Failed to ${isNew ? 'create' : 'update'} medication`)); } finally { setSubmitting(false); } }; const addIngredient = () => { ingredientFieldArray.append({ itemCodeableConcept: null, isActive: true, strength: { numerator: { value: '', unit: '', system: 'http://unitsofmeasure.org', code: '' }, denominator: { value: '', unit: '', system: 'http://unitsofmeasure.org', code: '' } } }); }; const removeIngredient = (index: number) => { ingredientFieldArray.remove(index); }; const handleDeleteMedication = async () => { if (!medication) return; try { await deleteMedication(medication); setMedicationsList(prev => prev.filter(p => p.id !== medication.id)); navigate(-1); } catch (error) { console.error('Failed to delete medication:', error); // The save path above already reads a refusal correctly; the delete was left behind by // that sweep and is the same clinical write. setError(describeWriteFailure(error, 'Failed to delete medication')); } finally { setShouldReload(true); setShowDeleteModal(false); } }; if (loading) { return ; } return (
{!isNew && ( )} {success && ( <> setSuccess(undefined)}> {success} )} {error && ( <> setError(undefined)}>
{error}
)} {/* status */} {/* code */} {/* form */} {/* manufacturer */} {/*Manufacturer*/} {/**/} {/**/} {/* (*/} {/* */} {/* )}/>*/} {/**/} {/* (*/} {/* */} {/* )}/>*/} {/**/} {(tab) => { // amount if (tab.name === 'amount') { return (
{/* amount */}
); } // ingredients if (tab.name === 'ingredients') { return (
{ingredientFieldArray.fields.length === 0 && ( <> Medication Ingredients No ingredients added yet. )} {(ingredientFieldArray.fields as any[]).map((ingredient, index) => ( <> {ingredientFieldArray.fields.length > 0 && (

Ingredient {index + 1}

)} {/* itemCodeableConcept */} {/* isActive */} ( )}/> {/* amount */}
))} {ingredientFieldArray.fields.length !== 0 && ( <> )}
); } // batch if (tab.name === 'batch') { return (
Batch Information {/* batch.lotNumber */} ( )}/> {/* batch.expirationDate */} ( )}/>
); } }}
{/* Delete Confirmation Modal */} {showDeleteModal && ( setShowDeleteModal(false)}> Are you sure you want to delete this medication record? )}
); }; export default EditMedicationPage;