import { useState } from 'react'; import { Item, ItemGroup } from "../../../../components/ui/item-group"; import { useNavigate } from 'react-router-dom'; import { Icon } from "../../../../components/ui/icon"; import { Flex, FlexItem, FlexBlock } from '../../../../components/ui/flex'; import { Text } from '../../../../components/ui/text'; import { Spacer } from '../../../../components/ui/spacer'; // `calendar` and `info` still feed WordPress icon components on each row - `info` also fed // the Help button, so it survives its Button's conversion. A separate sweep. import { Pencil, Plus, Calendar as calendar, Info as info } from 'lucide-react'; import { MedicationDispense } from 'fhir/r4'; import { AppSpinner, FhirMedicationDispenseDisplay, ScrollableTab } from '../../../../components'; import { ResourceListStatus } from '../../../../components/ui/resource-list-status'; import { formatFhirCodeableConcept } from '../../../../utils/fhirCodeableConcept.tsx'; import { formatDate } from '../../../../utils/dateUtils.ts'; import { useFhirMedicationDispenseBroadcast, useFhirMedicationDispenses, useFhirMedicationDispenseTargetedBroadcast } from '../../../../hooks'; import { useAuthServiceContext, useMedicationDispenseServiceContext } from '../../../../services'; import '../medicationRecords.css'; import { SourcePractice } from '../../../../components/ui/source-practice'; import { RecordPracticeNote, recordPracticeId, useRecordPracticeView, useRetireOnPracticeChange } from '../../../../contexts/RecordPracticeContext'; const MedicationDispenses = () => { const navigate = useNavigate(); const { userRole, USER_ROLES } = useAuthServiceContext(); const { getMedicationDispenseDisplay } = useMedicationDispenseServiceContext(); const { loading, error, clearError, medicationDispensesList, attempted } = useFhirMedicationDispenses(); const [selectedMedicationDispense, setSelectedMedicationDispense] = useState(null); const [showDisplayModal, setShowDisplayModal] = useState(false); // The record's practice context: its own dispenses under a named practice; the empty state speaks for the whole record. const practiceView = useRecordPracticeView(medicationDispensesList, recordPracticeId); useRetireOnPracticeChange(() => { setShowDisplayModal(false); setSelectedMedicationDispense(null); }); useFhirMedicationDispenseBroadcast(); useFhirMedicationDispenseTargetedBroadcast({ medicationDispense: selectedMedicationDispense || undefined, isOpen: showDisplayModal, onUpdate: (updatedMedicationDispense) => { setSelectedMedicationDispense(updatedMedicationDispense); }, onDelete: () => { setShowDisplayModal(false); setSelectedMedicationDispense(null); } }); const viewMedicationDispense = (medicationDispense: MedicationDispense) => { setSelectedMedicationDispense(medicationDispense); setShowDisplayModal(true); }; const editMedicationDispense = (event: React.MouseEvent, medicationDispense: MedicationDispense) => { event.stopPropagation(); navigate(medicationDispense.id as string, { relative: 'path' }); }; const addMedicationDispense = () => { navigate('new', { relative: 'path' }); }; const isAuthorizedToEdit = () => { return userRole && [USER_ROLES.PRACTITIONER].includes(userRole as string); }; const getStatusDisplay = (medicationDispense: MedicationDispense): { text: string, color?: string } => { if (!medicationDispense) return { text: 'Unknown' }; switch (medicationDispense.status) { case 'preparation': return { text: 'Preparation', color: '#e39700' }; case 'in-progress': return { text: 'In Progress', color: '#e39700' }; case 'cancelled': return { text: 'Cancelled', color: '#cc1818' }; case 'on-hold': return { text: 'On Hold', color: '#e39700' }; case 'completed': return { text: 'Completed', color: '#00a32a' }; case 'entered-in-error': return { text: 'Error', color: '#cc1818' }; case 'stopped': return { text: 'Stopped', color: '#cc1818' }; case 'declined': return { text: 'Declined', color: '#cc1818' }; case 'unknown': default: return { text: medicationDispense.status?.charAt(0).toUpperCase() + medicationDispense.status?.slice(1) || 'Unknown' }; } }; const getDateDisplay = (medicationDispense: MedicationDispense): string => { if (medicationDispense.whenHandedOver) { return `Handed over: ${formatDate(medicationDispense.whenHandedOver)}`; } if (medicationDispense.whenPrepared) { return `Prepared: ${formatDate(medicationDispense.whenPrepared)}`; } return ''; }; return (
{isAuthorizedToEdit() && ( )} <> {loading ? ( ) : ( {practiceView.shown.length !== 0 && ( {practiceView.shown.map((medicationDispense: MedicationDispense) => { const displayTitle = getMedicationDispenseDisplay(medicationDispense); const { text: statusText, color: statusColor } = getStatusDisplay(medicationDispense); const category = medicationDispense.category ? formatFhirCodeableConcept(medicationDispense.category) : ''; const type = medicationDispense.type ? formatFhirCodeableConcept(medicationDispense.type) : ''; const dateDisplay = getDateDisplay(medicationDispense); const dosageCount = medicationDispense.dosageInstruction?.length || 0; return ( viewMedicationDispense(medicationDispense)}> {/* Wraps: on a narrow row Edit moves below the whole title rather than being squeezed past the card's edge. */} {displayTitle} {(category || type) && ( {category && `Category: ${category}`} {category && type && ' • '} {type && `Type: ${type}`} )} {dosageCount > 0 && ( {dosageCount} dosage instruction{dosageCount !== 1 ? 's' : ''} )} {dateDisplay && ( {dateDisplay} )} {isAuthorizedToEdit() && ( )} ); })} )} )} {selectedMedicationDispense && ( { setShowDisplayModal(false); setSelectedMedicationDispense(null); }} /> )}
); }; export default MedicationDispenses;