@openmrs/esm-patient-medications-app 11.3.1-patch.9064 → 11.3.1-patch.9310
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +25 -27
- package/dist/1022.js +1 -0
- package/dist/1022.js.map +1 -0
- package/dist/1119.js +1 -1
- package/dist/1197.js +1 -1
- package/dist/1268.js +2 -0
- package/dist/1268.js.map +1 -0
- package/dist/1780.js +1 -0
- package/dist/1780.js.map +1 -0
- package/dist/2146.js +1 -1
- package/dist/2690.js +1 -1
- package/dist/3099.js +1 -1
- package/dist/3338.js +2 -0
- package/dist/3338.js.map +1 -0
- package/dist/3584.js +1 -1
- package/dist/4055.js +1 -1
- package/dist/4132.js +1 -1
- package/dist/4300.js +1 -1
- package/dist/4335.js +1 -1
- package/dist/4341.js +1 -0
- package/dist/4341.js.map +1 -0
- package/dist/4618.js +1 -1
- package/dist/4652.js +1 -1
- package/dist/4944.js +1 -1
- package/dist/4953.js +1 -0
- package/dist/4953.js.map +1 -0
- package/dist/5173.js +1 -1
- package/dist/5241.js +1 -1
- package/dist/5442.js +1 -1
- package/dist/5661.js +1 -1
- package/dist/5670.js +1 -1
- package/dist/5670.js.map +1 -1
- package/dist/6022.js +1 -1
- package/dist/6336.js +1 -0
- package/dist/6336.js.map +1 -0
- package/dist/6468.js +1 -1
- package/dist/6679.js +1 -1
- package/dist/6840.js +1 -1
- package/dist/6859.js +1 -1
- package/dist/7097.js +1 -1
- package/dist/7159.js +1 -1
- package/dist/723.js +1 -1
- package/dist/7617.js +1 -1
- package/dist/795.js +1 -1
- package/dist/8163.js +1 -1
- package/dist/8349.js +1 -1
- package/dist/8437.js +1 -0
- package/dist/8437.js.map +1 -0
- package/dist/8618.js +1 -1
- package/dist/8812.js +1 -1
- package/dist/8812.js.map +1 -1
- package/dist/890.js +1 -1
- package/dist/9214.js +1 -1
- package/dist/9538.js +1 -1
- package/dist/9569.js +1 -1
- package/dist/986.js +1 -1
- package/dist/9879.js +1 -1
- package/dist/9895.js +1 -1
- package/dist/9900.js +1 -1
- package/dist/9913.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-patient-medications-app.js +1 -1
- package/dist/openmrs-esm-patient-medications-app.js.buildmanifest.json +324 -296
- package/dist/openmrs-esm-patient-medications-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +4 -4
- package/src/active-medications/active-medications.component.tsx +8 -2
- package/src/active-medications/active-medications.test.tsx +6 -11
- package/src/add-drug-order/add-drug-order.component.tsx +168 -0
- package/src/add-drug-order/add-drug-order.scss +6 -0
- package/src/add-drug-order/add-drug-order.test.tsx +28 -17
- package/src/add-drug-order/add-drug-order.workspace.tsx +25 -94
- package/src/add-drug-order/drug-order-form.component.tsx +193 -230
- package/src/add-drug-order/drug-order-form.resource.ts +212 -0
- package/src/add-drug-order/drug-order-form.scss +11 -7
- package/src/add-drug-order/drug-search/drug-search-combobox.component.tsx +55 -0
- package/src/add-drug-order/drug-search/drug-search-combobox.test.tsx +56 -0
- package/src/add-drug-order/drug-search/drug-search.component.tsx +11 -11
- package/src/add-drug-order/drug-search/drug-search.resource.tsx +82 -19
- package/src/add-drug-order/drug-search/helpers.ts +1 -1
- package/src/add-drug-order/drug-search/order-basket-search-results.component.tsx +45 -19
- package/src/add-drug-order/exported-add-drug-order.workspace.tsx +30 -0
- package/src/add-drug-order/fill-prescription-form.workspace.tsx +112 -0
- package/src/api/api.ts +25 -4
- package/src/api/order-config.ts +3 -3
- package/src/components/medications-details-table.component.tsx +57 -18
- package/src/config-schema.ts +15 -2
- package/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx +22 -33
- package/src/drug-order-basket-panel/drug-order-basket-panel.test.tsx +13 -6
- package/src/drug-order-basket-panel/order-basket-item-tile.component.tsx +1 -1
- package/src/index.ts +9 -1
- package/src/medications-summary/medications-summary.component.tsx +5 -3
- package/src/past-medications/past-medications.component.tsx +44 -0
- package/src/past-medications/past-medications.scss +7 -0
- package/src/past-medications/past-medications.test.tsx +85 -0
- package/src/routes.json +46 -4
- package/translations/am.json +20 -4
- package/translations/ar.json +20 -4
- package/translations/ar_SY.json +20 -4
- package/translations/bn.json +20 -4
- package/translations/de.json +20 -4
- package/translations/en.json +22 -4
- package/translations/en_US.json +20 -4
- package/translations/es.json +29 -13
- package/translations/es_MX.json +20 -4
- package/translations/fr.json +26 -10
- package/translations/he.json +20 -4
- package/translations/hi.json +20 -4
- package/translations/hi_IN.json +20 -4
- package/translations/id.json +29 -13
- package/translations/it.json +29 -13
- package/translations/ka.json +27 -11
- package/translations/km.json +20 -4
- package/translations/ku.json +20 -4
- package/translations/ky.json +20 -4
- package/translations/lg.json +20 -4
- package/translations/ne.json +20 -4
- package/translations/pl.json +20 -4
- package/translations/pt.json +29 -13
- package/translations/pt_BR.json +29 -13
- package/translations/qu.json +20 -4
- package/translations/ro_RO.json +29 -13
- package/translations/ru_RU.json +20 -4
- package/translations/si.json +20 -4
- package/translations/sw.json +20 -4
- package/translations/sw_KE.json +20 -4
- package/translations/tr.json +20 -4
- package/translations/tr_TR.json +20 -4
- package/translations/uk.json +20 -4
- package/translations/uz.json +20 -4
- package/translations/uz@Latn.json +20 -4
- package/translations/uz_UZ.json +20 -4
- package/translations/vi.json +20 -4
- package/translations/zh.json +21 -5
- package/translations/zh_CN.json +29 -13
- package/dist/2537.js +0 -1
- package/dist/2537.js.map +0 -1
- package/dist/4918.js +0 -1
- package/dist/4918.js.map +0 -1
- package/dist/5837.js +0 -2
- package/dist/5837.js.map +0 -1
- package/dist/6783.js +0 -2
- package/dist/6783.js.map +0 -1
- package/dist/8803.js +0 -1
- package/dist/8803.js.map +0 -1
- package/dist/9365.js +0 -1
- package/dist/9365.js.map +0 -1
- package/dist/9647.js +0 -1
- package/dist/9647.js.map +0 -1
- package/src/types.ts +0 -75
- /package/dist/{6783.js.LICENSE.txt → 1268.js.LICENSE.txt} +0 -0
- /package/dist/{5837.js.LICENSE.txt → 3338.js.LICENSE.txt} +0 -0
|
@@ -3,15 +3,15 @@ import classNames from 'classnames';
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { Button, ButtonSkeleton, SkeletonText, Tile } from '@carbon/react';
|
|
5
5
|
import { ShoppingCartArrowUp } from '@carbon/react/icons';
|
|
6
|
-
import {
|
|
6
|
+
import { type DrugOrderBasketItem, useOrderBasket } from '@openmrs/esm-patient-common-lib';
|
|
7
7
|
import {
|
|
8
8
|
ArrowRightIcon,
|
|
9
|
-
closeWorkspace,
|
|
10
9
|
ShoppingCartArrowDownIcon,
|
|
11
10
|
useConfig,
|
|
12
11
|
useLayoutType,
|
|
13
12
|
UserHasAccess,
|
|
14
|
-
|
|
13
|
+
type Visit,
|
|
14
|
+
type Workspace2DefinitionProps,
|
|
15
15
|
} from '@openmrs/esm-framework';
|
|
16
16
|
import { type ConfigObject } from '../../config-schema';
|
|
17
17
|
import { prepMedicationOrderPostData, useActivePatientOrders } from '../../api/api';
|
|
@@ -22,24 +22,32 @@ import {
|
|
|
22
22
|
useDrugSearch,
|
|
23
23
|
useDrugTemplate,
|
|
24
24
|
} from './drug-search.resource';
|
|
25
|
-
import type { DrugOrderBasketItem } from '../../types';
|
|
26
25
|
import styles from './order-basket-search-results.scss';
|
|
27
26
|
|
|
28
27
|
export interface OrderBasketSearchResultsProps {
|
|
28
|
+
patient: fhir.Patient;
|
|
29
29
|
searchTerm: string;
|
|
30
|
+
closeWorkspace: Workspace2DefinitionProps['closeWorkspace'];
|
|
30
31
|
openOrderForm: (searchResult: DrugOrderBasketItem) => void;
|
|
31
32
|
focusAndClearSearchInput: () => void;
|
|
33
|
+
visit: Visit;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
interface DrugSearchResultItemProps {
|
|
37
|
+
patient: fhir.Patient;
|
|
35
38
|
drug: DrugSearchResult;
|
|
36
39
|
openOrderForm: (searchResult: DrugOrderBasketItem) => void;
|
|
40
|
+
visit: Visit;
|
|
41
|
+
closeWorkspace: Workspace2DefinitionProps['closeWorkspace'];
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
export default function OrderBasketSearchResults({
|
|
40
45
|
searchTerm,
|
|
41
46
|
openOrderForm,
|
|
42
47
|
focusAndClearSearchInput,
|
|
48
|
+
patient,
|
|
49
|
+
visit,
|
|
50
|
+
closeWorkspace,
|
|
43
51
|
}: OrderBasketSearchResultsProps) {
|
|
44
52
|
const { t } = useTranslation();
|
|
45
53
|
const isTablet = useLayoutType() === 'tablet';
|
|
@@ -105,24 +113,45 @@ export default function OrderBasketSearchResults({
|
|
|
105
113
|
</Button>
|
|
106
114
|
</div>
|
|
107
115
|
<div className={styles.resultsContainer}>
|
|
108
|
-
{drugs?.map((drug) =>
|
|
116
|
+
{drugs?.map((drug) => (
|
|
117
|
+
<DrugSearchResultItem
|
|
118
|
+
key={drug.uuid}
|
|
119
|
+
patient={patient}
|
|
120
|
+
drug={drug}
|
|
121
|
+
openOrderForm={openOrderForm}
|
|
122
|
+
visit={visit}
|
|
123
|
+
closeWorkspace={closeWorkspace}
|
|
124
|
+
/>
|
|
125
|
+
))}
|
|
109
126
|
</div>
|
|
110
127
|
</div>
|
|
111
128
|
);
|
|
112
129
|
}
|
|
113
130
|
|
|
114
|
-
const DrugSearchResultItem: React.FC<DrugSearchResultItemProps> = ({
|
|
131
|
+
const DrugSearchResultItem: React.FC<DrugSearchResultItemProps> = ({
|
|
132
|
+
patient,
|
|
133
|
+
drug,
|
|
134
|
+
openOrderForm,
|
|
135
|
+
visit,
|
|
136
|
+
closeWorkspace,
|
|
137
|
+
}) => {
|
|
115
138
|
const isTablet = useLayoutType() === 'tablet';
|
|
116
|
-
const { orders, setOrders } = useOrderBasket<DrugOrderBasketItem>(
|
|
117
|
-
|
|
139
|
+
const { orders, setOrders } = useOrderBasket<DrugOrderBasketItem>(
|
|
140
|
+
patient,
|
|
141
|
+
'medications',
|
|
142
|
+
prepMedicationOrderPostData,
|
|
143
|
+
);
|
|
144
|
+
const patientUuid = patient.id;
|
|
118
145
|
const { data: activeOrders, isLoading: isLoadingActiveOrders } = useActivePatientOrders(patientUuid);
|
|
119
146
|
const drugAlreadyInBasket = useMemo(
|
|
120
|
-
() => orders?.some((order) => ordersEqual(order, getTemplateOrderBasketItem(drug))),
|
|
121
|
-
[orders, drug],
|
|
147
|
+
() => orders?.some((order) => ordersEqual(order, getTemplateOrderBasketItem(drug, visit))),
|
|
148
|
+
[orders, drug, visit],
|
|
122
149
|
);
|
|
150
|
+
// TODO: use the backend instead of this to determine whether the drug formulation can be ordered
|
|
151
|
+
// See: https://openmrs.atlassian.net/browse/RESTWS-1003
|
|
123
152
|
const drugAlreadyPrescribed = useMemo(
|
|
124
153
|
() => activeOrders?.some((order) => order?.drug?.uuid === drug?.uuid),
|
|
125
|
-
[activeOrders, drug],
|
|
154
|
+
[activeOrders, drug?.uuid],
|
|
126
155
|
);
|
|
127
156
|
|
|
128
157
|
const { templates, error: fetchingDrugOrderTemplatesError } = useDrugTemplate(drug?.uuid);
|
|
@@ -131,9 +160,9 @@ const DrugSearchResultItem: React.FC<DrugSearchResultItemProps> = ({ drug, openO
|
|
|
131
160
|
const drugItemTemplateOptions: Array<DrugOrderBasketItem> = useMemo(
|
|
132
161
|
() =>
|
|
133
162
|
templates?.length
|
|
134
|
-
? templates.map((template) => getTemplateOrderBasketItem(drug, config?.daysDurationUnit, template))
|
|
135
|
-
: [getTemplateOrderBasketItem(drug, config?.daysDurationUnit)],
|
|
136
|
-
[templates, drug, config?.daysDurationUnit],
|
|
163
|
+
? templates.map((template) => getTemplateOrderBasketItem(drug, visit, config?.daysDurationUnit, template))
|
|
164
|
+
: [getTemplateOrderBasketItem(drug, visit, config?.daysDurationUnit)],
|
|
165
|
+
[templates, drug, config?.daysDurationUnit, visit],
|
|
137
166
|
);
|
|
138
167
|
|
|
139
168
|
const addToBasket = useCallback(
|
|
@@ -141,12 +170,9 @@ const DrugSearchResultItem: React.FC<DrugSearchResultItemProps> = ({ drug, openO
|
|
|
141
170
|
// Directly adding the order to basket should be marked as incomplete
|
|
142
171
|
searchResult.isOrderIncomplete = true;
|
|
143
172
|
setOrders([...orders, searchResult]);
|
|
144
|
-
closeWorkspace(
|
|
145
|
-
ignoreChanges: true,
|
|
146
|
-
onWorkspaceClose: () => launchWorkspace('order-basket'),
|
|
147
|
-
});
|
|
173
|
+
closeWorkspace();
|
|
148
174
|
},
|
|
149
|
-
[orders, setOrders],
|
|
175
|
+
[orders, setOrders, closeWorkspace],
|
|
150
176
|
);
|
|
151
177
|
|
|
152
178
|
const removeFromBasket = useCallback(
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type Workspace2DefinitionProps } from '@openmrs/esm-framework';
|
|
3
|
+
import { type ExportedOrderBasketWindowProps, type DrugOrderBasketItem } from '@openmrs/esm-patient-common-lib';
|
|
4
|
+
import AddDrugOrder from './add-drug-order.component';
|
|
5
|
+
|
|
6
|
+
export interface AddDrugOrderWorkspaceAdditionalProps {
|
|
7
|
+
order: DrugOrderBasketItem;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* This workspace displays the drug order form for adding or editing a drug order.
|
|
12
|
+
* On form submission, it saves the drug order to the (frontend) order basket.
|
|
13
|
+
* For a form that submits the drug order directly on submit,
|
|
14
|
+
* see fill-prescription-form.workspace.tsx
|
|
15
|
+
*/
|
|
16
|
+
export default function ExportedAddDrugOrderWorkspace({
|
|
17
|
+
workspaceProps: { order: initialOrder },
|
|
18
|
+
windowProps: { patient, patientUuid, visitContext },
|
|
19
|
+
closeWorkspace,
|
|
20
|
+
}: Workspace2DefinitionProps<AddDrugOrderWorkspaceAdditionalProps, ExportedOrderBasketWindowProps, {}>) {
|
|
21
|
+
return (
|
|
22
|
+
<AddDrugOrder
|
|
23
|
+
initialOrder={initialOrder}
|
|
24
|
+
patient={patient}
|
|
25
|
+
patientUuid={patientUuid}
|
|
26
|
+
visitContext={visitContext}
|
|
27
|
+
closeWorkspace={closeWorkspace}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
type ConfigObject,
|
|
4
|
+
type DefaultWorkspaceProps,
|
|
5
|
+
showSnackbar,
|
|
6
|
+
useConfig,
|
|
7
|
+
useSession,
|
|
8
|
+
useVisit,
|
|
9
|
+
} from '@openmrs/esm-framework';
|
|
10
|
+
import { type DrugOrderBasketItem, type EncounterPost, postEncounter } from '@openmrs/esm-patient-common-lib';
|
|
11
|
+
import { prepMedicationOrderPostData } from '../api';
|
|
12
|
+
import DrugOrderForm from './drug-order-form.component';
|
|
13
|
+
import { useTranslation } from 'react-i18next';
|
|
14
|
+
|
|
15
|
+
export interface FillPrescriptionFormProps extends DefaultWorkspaceProps {
|
|
16
|
+
patient: fhir.Patient;
|
|
17
|
+
onAfterSave?(patient: fhir.Patient, encounterUuid: string);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This form is meant for backfilling prescriptions from paper forms, and is similar to the drug order form in the
|
|
22
|
+
* order basket, except:
|
|
23
|
+
* - it contains additional fields select the drug (inline), the prescribing clinician and the prescribing date.
|
|
24
|
+
* - when submitting the form, it directly submits the order instead of saving to the order basket
|
|
25
|
+
*
|
|
26
|
+
* This component is not used in the medications app itself, but is intended to be used in other apps
|
|
27
|
+
* (like dispensing).
|
|
28
|
+
*/
|
|
29
|
+
const FillPrescriptionForm: React.FC<FillPrescriptionFormProps> = ({
|
|
30
|
+
patient,
|
|
31
|
+
closeWorkspace,
|
|
32
|
+
closeWorkspaceWithSavedChanges,
|
|
33
|
+
promptBeforeClosing,
|
|
34
|
+
onAfterSave,
|
|
35
|
+
}) => {
|
|
36
|
+
const { sessionLocation } = useSession();
|
|
37
|
+
const { t } = useTranslation();
|
|
38
|
+
const { drugOrderEncounterType } = useConfig<ConfigObject>();
|
|
39
|
+
const patientUuid = patient.id;
|
|
40
|
+
const { activeVisit, isLoading: isLoadingVisit } = useVisit(patientUuid);
|
|
41
|
+
|
|
42
|
+
const submitDrugOrder = useCallback(
|
|
43
|
+
async (finalizedOrder: DrugOrderBasketItem) => {
|
|
44
|
+
const drugOrderPost = prepMedicationOrderPostData(finalizedOrder, patientUuid, null);
|
|
45
|
+
const encounter: EncounterPost = {
|
|
46
|
+
patient: patientUuid,
|
|
47
|
+
location: sessionLocation.uuid,
|
|
48
|
+
encounterType: drugOrderEncounterType,
|
|
49
|
+
encounterDatetime: new Date(),
|
|
50
|
+
visit: null, // let the server's logic associate the encounter with a visit
|
|
51
|
+
obs: [],
|
|
52
|
+
orders: [drugOrderPost],
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
const encounterUuid = await postEncounter(encounter);
|
|
56
|
+
showSnackbar({
|
|
57
|
+
isLowContrast: true,
|
|
58
|
+
kind: 'success',
|
|
59
|
+
title: t('orderCompleted', 'Placed orders'),
|
|
60
|
+
subtitle: t('ordered', 'Placed order for {{order}}', {
|
|
61
|
+
order: finalizedOrder.drug.display,
|
|
62
|
+
}),
|
|
63
|
+
});
|
|
64
|
+
closeWorkspaceWithSavedChanges();
|
|
65
|
+
onAfterSave?.(patient, encounterUuid);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
showSnackbar({
|
|
68
|
+
isLowContrast: true,
|
|
69
|
+
kind: 'error',
|
|
70
|
+
title: t('saveDrugOrderFailed', 'Error ordering {{orderName}}', {
|
|
71
|
+
orderName: finalizedOrder.drug.display,
|
|
72
|
+
}),
|
|
73
|
+
subtitle: e?.responseBody?.error?.translatedMessage ?? e?.responseBody?.error?.message,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
[
|
|
78
|
+
patientUuid,
|
|
79
|
+
closeWorkspaceWithSavedChanges,
|
|
80
|
+
sessionLocation.uuid,
|
|
81
|
+
t,
|
|
82
|
+
drugOrderEncounterType,
|
|
83
|
+
onAfterSave,
|
|
84
|
+
patient,
|
|
85
|
+
],
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (!isLoadingVisit && !activeVisit) {
|
|
89
|
+
return (
|
|
90
|
+
<div>
|
|
91
|
+
{t('visitRequiredForFillingPrescription', 'Patient is required to have an active visit to fill prescription')}
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return (
|
|
96
|
+
<DrugOrderForm
|
|
97
|
+
initialOrderBasketItem={{ action: 'NEW' } as DrugOrderBasketItem}
|
|
98
|
+
patient={patient}
|
|
99
|
+
onSave={submitDrugOrder}
|
|
100
|
+
saveButtonText={t('fillPrescription', 'Fill prescription')}
|
|
101
|
+
onCancel={closeWorkspace}
|
|
102
|
+
allowSelectingPrescribingClinician={true}
|
|
103
|
+
visitContext={activeVisit}
|
|
104
|
+
allowSelectingDrug={true}
|
|
105
|
+
setHasUnsavedChanges={function (hasUnsavedChanges: boolean): void {
|
|
106
|
+
throw new Error('Function not implemented.');
|
|
107
|
+
}}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export default FillPrescriptionForm;
|
package/src/api/api.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { useCallback, useMemo } from 'react';
|
|
2
2
|
import useSWR, { useSWRConfig } from 'swr';
|
|
3
3
|
import useSWRImmutable from 'swr/immutable';
|
|
4
|
-
import { openmrsFetch, restBaseUrl, useConfig, type FetchResponse } from '@openmrs/esm-framework';
|
|
5
|
-
import type {
|
|
4
|
+
import { openmrsFetch, restBaseUrl, useConfig, useOpenmrsFetchAll, type FetchResponse } from '@openmrs/esm-framework';
|
|
5
|
+
import type {
|
|
6
|
+
DrugOrderBasketItem,
|
|
7
|
+
DrugOrderPost,
|
|
8
|
+
PatientOrderFetchResponse,
|
|
9
|
+
Order,
|
|
10
|
+
} from '@openmrs/esm-patient-common-lib';
|
|
6
11
|
import { type ConfigObject } from '../config-schema';
|
|
7
|
-
import { type DrugOrderBasketItem } from '../types';
|
|
8
12
|
|
|
9
13
|
export const careSettingUuid = '6f0c9a92-6f24-11e3-af88-005056821db0';
|
|
10
14
|
|
|
11
15
|
const customRepresentation =
|
|
12
16
|
'custom:(uuid,dosingType,orderNumber,accessionNumber,' +
|
|
13
17
|
'patient:ref,action,careSetting:ref,previousOrder:ref,dateActivated,scheduledDate,dateStopped,autoExpireDate,' +
|
|
14
|
-
'orderType:ref,encounter:
|
|
18
|
+
'orderType:ref,encounter:(uuid,display,visit),orderer:(uuid,display,person:(display)),orderReason,orderReasonNonCoded,orderType,urgency,instructions,' +
|
|
15
19
|
'commentToFulfiller,fulfillerStatus,drug:(uuid,display,strength,dosageForm:(display,uuid),concept),dose,doseUnits:ref,' +
|
|
16
20
|
'frequency:ref,asNeeded,asNeededCondition,quantity,quantityUnits:ref,numRefills,dosingInstructions,' +
|
|
17
21
|
'duration,durationUnits:ref,route:ref,brandName,dispenseAsWritten)';
|
|
@@ -229,3 +233,20 @@ export function useRequireOutpatientQuantity(): {
|
|
|
229
233
|
|
|
230
234
|
return results;
|
|
231
235
|
}
|
|
236
|
+
|
|
237
|
+
export interface Provider {
|
|
238
|
+
uuid: string;
|
|
239
|
+
person: {
|
|
240
|
+
display?: string;
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function useProviders(providerRoles: Array<string>) {
|
|
245
|
+
const rep = 'custom:(uuid,person:(display)';
|
|
246
|
+
const ret = useOpenmrsFetchAll<Provider>(
|
|
247
|
+
providerRoles != null ? `${restBaseUrl}/provider?providerRoles=${providerRoles.join(',')}&v=${rep})` : null,
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
ret.data?.sort((a, b) => (a.person?.display ?? '').localeCompare(b.person?.display ?? ''));
|
|
251
|
+
return ret;
|
|
252
|
+
}
|
package/src/api/order-config.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
-
import { useMemo } from 'react';
|
|
3
|
-
import useSWRImmutable from 'swr/immutable';
|
|
4
2
|
import {
|
|
5
3
|
type DosingUnit,
|
|
6
4
|
type DurationUnit,
|
|
7
5
|
type MedicationFrequency,
|
|
8
6
|
type MedicationRoute,
|
|
9
7
|
type QuantityUnit,
|
|
10
|
-
} from '
|
|
8
|
+
} from '@openmrs/esm-patient-common-lib';
|
|
9
|
+
import { useMemo } from 'react';
|
|
10
|
+
import useSWRImmutable from 'swr/immutable';
|
|
11
11
|
|
|
12
12
|
export interface ConceptName {
|
|
13
13
|
uuid: string;
|
|
@@ -21,10 +21,15 @@ import {
|
|
|
21
21
|
import {
|
|
22
22
|
CardHeader,
|
|
23
23
|
compare,
|
|
24
|
+
type DrugOrderBasketItem,
|
|
24
25
|
PatientChartPagination,
|
|
25
26
|
type Order,
|
|
26
27
|
useLaunchWorkspaceRequiringVisit,
|
|
27
28
|
useOrderBasket,
|
|
29
|
+
type PatientWorkspaceGroupProps,
|
|
30
|
+
invalidateVisitByUuid,
|
|
31
|
+
invalidateVisitAndEncounterData,
|
|
32
|
+
type OrderBasketWindowProps,
|
|
28
33
|
} from '@openmrs/esm-patient-common-lib';
|
|
29
34
|
import {
|
|
30
35
|
AddIcon,
|
|
@@ -36,14 +41,16 @@ import {
|
|
|
36
41
|
useLayoutType,
|
|
37
42
|
usePagination,
|
|
38
43
|
UserIcon,
|
|
44
|
+
launchWorkspace2,
|
|
45
|
+
type Encounter,
|
|
39
46
|
} from '@openmrs/esm-framework';
|
|
40
47
|
import { useTranslation } from 'react-i18next';
|
|
41
48
|
import { useReactToPrint } from 'react-to-print';
|
|
42
|
-
import { type AddDrugOrderWorkspaceAdditionalProps } from '../add-drug-order/add-drug-order.workspace';
|
|
43
|
-
import { type DrugOrderBasketItem } from '../types';
|
|
44
49
|
import { type ConfigObject } from '../config-schema';
|
|
45
50
|
import PrintComponent from '../print/print.component';
|
|
46
51
|
import styles from './medications-details-table.scss';
|
|
52
|
+
import { useSWRConfig } from 'swr';
|
|
53
|
+
import { type AddDrugOrderWorkspaceProps } from '../add-drug-order/add-drug-order.workspace';
|
|
47
54
|
|
|
48
55
|
export interface MedicationsDetailsTableProps {
|
|
49
56
|
isValidating?: boolean;
|
|
@@ -68,15 +75,14 @@ const MedicationsDetailsTable: React.FC<MedicationsDetailsTableProps> = ({
|
|
|
68
75
|
}) => {
|
|
69
76
|
const pageSize = 5;
|
|
70
77
|
const { t } = useTranslation();
|
|
71
|
-
const launchOrderBasket = useLaunchWorkspaceRequiringVisit('order-basket');
|
|
72
|
-
const launchAddDrugOrder = useLaunchWorkspaceRequiringVisit('add-drug-order');
|
|
78
|
+
const launchOrderBasket = useLaunchWorkspaceRequiringVisit(patient.id, 'order-basket');
|
|
73
79
|
const config = useConfig<ConfigObject>();
|
|
74
80
|
const showPrintButton = config.showPrintButton;
|
|
75
81
|
const contentToPrintRef = useRef(null);
|
|
76
82
|
const { excludePatientIdentifierCodeTypes } = useConfig();
|
|
77
83
|
const [isPrinting, setIsPrinting] = useState(false);
|
|
78
84
|
|
|
79
|
-
const { orders, setOrders } = useOrderBasket<DrugOrderBasketItem>('medications');
|
|
85
|
+
const { orders, setOrders } = useOrderBasket<DrugOrderBasketItem>(patient, 'medications');
|
|
80
86
|
const { results, goTo, currentPage } = usePagination(medications, pageSize);
|
|
81
87
|
|
|
82
88
|
const tableHeaders = [
|
|
@@ -251,7 +257,7 @@ const MedicationsDetailsTable: React.FC<MedicationsDetailsTableProps> = ({
|
|
|
251
257
|
kind="ghost"
|
|
252
258
|
renderIcon={(props: ComponentProps<typeof AddIcon>) => <AddIcon size={16} {...props} />}
|
|
253
259
|
iconDescription="Launch order basket"
|
|
254
|
-
onClick={
|
|
260
|
+
onClick={() => launchOrderBasket({}, { encounterUuid: '' })}
|
|
255
261
|
>
|
|
256
262
|
{t('add', 'Add')}
|
|
257
263
|
</Button>
|
|
@@ -298,14 +304,13 @@ const MedicationsDetailsTable: React.FC<MedicationsDetailsTableProps> = ({
|
|
|
298
304
|
{!isPrinting && (
|
|
299
305
|
<TableCell className="cds--table-column-menu">
|
|
300
306
|
<OrderBasketItemActions
|
|
307
|
+
patient={patient}
|
|
301
308
|
showDiscontinueButton={showDiscontinueButton}
|
|
302
309
|
showModifyButton={showModifyButton}
|
|
303
310
|
showReorderButton={showReorderButton}
|
|
304
311
|
medication={medications[rowIndex]}
|
|
305
312
|
items={orders}
|
|
306
313
|
setItems={setOrders}
|
|
307
|
-
openOrderBasket={launchOrderBasket}
|
|
308
|
-
openDrugOrderForm={launchAddDrugOrder}
|
|
309
314
|
/>
|
|
310
315
|
</TableCell>
|
|
311
316
|
)}
|
|
@@ -337,27 +342,39 @@ function InfoTooltip({ orderer }: { orderer: string }) {
|
|
|
337
342
|
}
|
|
338
343
|
|
|
339
344
|
function OrderBasketItemActions({
|
|
345
|
+
patient,
|
|
340
346
|
showDiscontinueButton,
|
|
341
347
|
showModifyButton,
|
|
342
348
|
showReorderButton,
|
|
343
349
|
medication,
|
|
344
350
|
items,
|
|
345
351
|
setItems,
|
|
346
|
-
openOrderBasket,
|
|
347
|
-
openDrugOrderForm,
|
|
348
352
|
}: {
|
|
353
|
+
patient: fhir.Patient;
|
|
349
354
|
showDiscontinueButton: boolean;
|
|
350
355
|
showModifyButton: boolean;
|
|
351
356
|
showReorderButton: boolean;
|
|
352
357
|
medication: Order;
|
|
353
358
|
items: Array<DrugOrderBasketItem>;
|
|
354
359
|
setItems: (items: Array<DrugOrderBasketItem>) => void;
|
|
355
|
-
openOrderBasket: () => void;
|
|
356
|
-
openDrugOrderForm: (additionalProps?: AddDrugOrderWorkspaceAdditionalProps) => void;
|
|
357
360
|
}) {
|
|
361
|
+
const { mutate: globalMutate } = useSWRConfig();
|
|
358
362
|
const { t } = useTranslation();
|
|
359
363
|
const isTablet = useLayoutType() === 'tablet';
|
|
360
364
|
const alreadyInBasket = items.some((x) => x.uuid === medication.uuid);
|
|
365
|
+
|
|
366
|
+
const workspaceGroupProps: PatientWorkspaceGroupProps = useMemo(
|
|
367
|
+
() => ({
|
|
368
|
+
patient,
|
|
369
|
+
patientUuid: patient.id,
|
|
370
|
+
visitContext: medication.encounter.visit,
|
|
371
|
+
mutateVisitContext: () => {
|
|
372
|
+
invalidateVisitByUuid(globalMutate, medication.encounter.visit?.uuid);
|
|
373
|
+
invalidateVisitAndEncounterData(globalMutate, patient.id);
|
|
374
|
+
},
|
|
375
|
+
}),
|
|
376
|
+
[patient, medication, globalMutate],
|
|
377
|
+
);
|
|
361
378
|
const handleDiscontinueClick = useCallback(() => {
|
|
362
379
|
setItems([
|
|
363
380
|
...items,
|
|
@@ -403,10 +420,17 @@ function OrderBasketItemActions({
|
|
|
403
420
|
value: medication.quantityUnits?.display,
|
|
404
421
|
valueCoded: medication.quantityUnits?.uuid,
|
|
405
422
|
},
|
|
423
|
+
encounterUuid: medication.encounter?.uuid,
|
|
424
|
+
visit: medication.encounter?.visit,
|
|
406
425
|
},
|
|
407
426
|
]);
|
|
408
|
-
|
|
409
|
-
|
|
427
|
+
launchWorkspace2<{}, OrderBasketWindowProps, PatientWorkspaceGroupProps>(
|
|
428
|
+
'order-basket',
|
|
429
|
+
{},
|
|
430
|
+
{ encounterUuid: medication.encounter.uuid },
|
|
431
|
+
workspaceGroupProps,
|
|
432
|
+
);
|
|
433
|
+
}, [items, setItems, medication, workspaceGroupProps]);
|
|
410
434
|
|
|
411
435
|
const handleModifyClick = useCallback(() => {
|
|
412
436
|
const newItem: DrugOrderBasketItem = {
|
|
@@ -451,10 +475,18 @@ function OrderBasketItemActions({
|
|
|
451
475
|
value: medication.quantityUnits?.display,
|
|
452
476
|
valueCoded: medication.quantityUnits?.uuid,
|
|
453
477
|
},
|
|
478
|
+
encounterUuid: medication.encounter?.uuid,
|
|
479
|
+
visit: medication.encounter?.visit,
|
|
454
480
|
};
|
|
455
481
|
setItems([...items, newItem]);
|
|
456
|
-
|
|
457
|
-
|
|
482
|
+
|
|
483
|
+
launchWorkspace2<AddDrugOrderWorkspaceProps, OrderBasketWindowProps, PatientWorkspaceGroupProps>(
|
|
484
|
+
'add-drug-order',
|
|
485
|
+
{ order: newItem },
|
|
486
|
+
{ encounterUuid: medication.encounter.uuid },
|
|
487
|
+
workspaceGroupProps,
|
|
488
|
+
);
|
|
489
|
+
}, [items, setItems, medication, workspaceGroupProps]);
|
|
458
490
|
|
|
459
491
|
const handleReorderClick = useCallback(() => {
|
|
460
492
|
setItems([
|
|
@@ -501,10 +533,17 @@ function OrderBasketItemActions({
|
|
|
501
533
|
value: medication.quantityUnits?.display,
|
|
502
534
|
valueCoded: medication.quantityUnits?.uuid,
|
|
503
535
|
},
|
|
536
|
+
encounterUuid: medication.encounter?.uuid,
|
|
537
|
+
visit: medication.encounter?.visit,
|
|
504
538
|
},
|
|
505
539
|
]);
|
|
506
|
-
|
|
507
|
-
|
|
540
|
+
launchWorkspace2<{}, OrderBasketWindowProps, PatientWorkspaceGroupProps>(
|
|
541
|
+
'order-basket',
|
|
542
|
+
{},
|
|
543
|
+
{ encounterUuid: medication.encounter.uuid },
|
|
544
|
+
workspaceGroupProps,
|
|
545
|
+
);
|
|
546
|
+
}, [items, setItems, medication, workspaceGroupProps]);
|
|
508
547
|
|
|
509
548
|
return (
|
|
510
549
|
<OverflowMenu aria-label="Actions menu" selectorPrimaryFocus={'#modify'} flipped size={isTablet ? 'lg' : 'md'}>
|
package/src/config-schema.ts
CHANGED
|
@@ -2,11 +2,10 @@ import { Type, validator } from '@openmrs/esm-framework';
|
|
|
2
2
|
|
|
3
3
|
export const configSchema = {
|
|
4
4
|
daysDurationUnit: {
|
|
5
|
-
_description:
|
|
6
|
-
'The default medication duration unit is days. The concept for that medication duration unit is specified here.',
|
|
7
5
|
uuid: {
|
|
8
6
|
_type: Type.ConceptUuid,
|
|
9
7
|
_default: '1072AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
8
|
+
_description: 'The uuid of the concept of medication duration unit in days',
|
|
10
9
|
},
|
|
11
10
|
display: {
|
|
12
11
|
_type: Type.String,
|
|
@@ -37,6 +36,18 @@ export const configSchema = {
|
|
|
37
36
|
_description: 'Whether to require an indication when placing a medication order',
|
|
38
37
|
_default: true,
|
|
39
38
|
},
|
|
39
|
+
prescriberProviderRoles: {
|
|
40
|
+
_type: Type.Array,
|
|
41
|
+
_description:
|
|
42
|
+
'Array of provider roles uuids. If specified, the drug order form shows the "Prescribing Clinician" dropdown listing all providers with one of the specified roles. (The dropdown is hidden if no providers match the role criteria.) This feature requires the providermanagement backend module. Note that, in any case, any user who can submit the drug order form may still do so with themselves as the prescriber.',
|
|
43
|
+
_default: [],
|
|
44
|
+
},
|
|
45
|
+
drugOrderEncounterType: {
|
|
46
|
+
_type: Type.UUID,
|
|
47
|
+
_description:
|
|
48
|
+
'The encounter type of the encounter for the Fill Prescription form. Defaults to the "Order" encounter type.',
|
|
49
|
+
_default: '39da3525-afe4-45ff-8977-c53b7b359158',
|
|
50
|
+
},
|
|
40
51
|
};
|
|
41
52
|
|
|
42
53
|
export interface ConfigObject {
|
|
@@ -48,4 +59,6 @@ export interface ConfigObject {
|
|
|
48
59
|
showPrintButton: boolean;
|
|
49
60
|
debounceDelayInMs: number;
|
|
50
61
|
requireIndication: boolean;
|
|
62
|
+
prescriberProviderRoles: Array<string>;
|
|
63
|
+
drugOrderEncounterType: string;
|
|
51
64
|
}
|
|
@@ -2,28 +2,31 @@ import React, { type ComponentProps, useCallback, useEffect, useMemo, useState }
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import { Button, Tile } from '@carbon/react';
|
|
5
|
+
import { AddIcon, ChevronDownIcon, ChevronUpIcon, useLayoutType } from '@openmrs/esm-framework';
|
|
5
6
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
launchWorkspace,
|
|
11
|
-
useLayoutType,
|
|
12
|
-
} from '@openmrs/esm-framework';
|
|
13
|
-
import { useOrderBasket } from '@openmrs/esm-patient-common-lib';
|
|
7
|
+
type OrderBasketExtensionProps,
|
|
8
|
+
useOrderBasket,
|
|
9
|
+
type DrugOrderBasketItem,
|
|
10
|
+
} from '@openmrs/esm-patient-common-lib';
|
|
14
11
|
import { prepMedicationOrderPostData } from '../api/api';
|
|
15
|
-
import type { DrugOrderBasketItem } from '../types';
|
|
16
12
|
import OrderBasketItemTile from './order-basket-item-tile.component';
|
|
17
13
|
import RxIcon from './rx-icon.component';
|
|
18
14
|
import styles from './drug-order-basket-panel.scss';
|
|
19
15
|
|
|
20
16
|
/**
|
|
17
|
+
* The extension is slotted into order-basket-slot in the main Order Basket workspace by default.
|
|
18
|
+
* It renders the "Add +" button for drug orders, and lists pending drug orders in the order basket.
|
|
19
|
+
*
|
|
21
20
|
* Designs: https://app.zeplin.io/project/60d59321e8100b0324762e05/screen/62c6bb9500e7671a618efa56
|
|
22
21
|
*/
|
|
23
|
-
|
|
22
|
+
function DrugOrderBasketPanelExtension({ patient, launchDrugOrderForm }: OrderBasketExtensionProps) {
|
|
24
23
|
const { t } = useTranslation();
|
|
25
24
|
const isTablet = useLayoutType() === 'tablet';
|
|
26
|
-
const { orders, setOrders } = useOrderBasket<DrugOrderBasketItem>(
|
|
25
|
+
const { orders, setOrders } = useOrderBasket<DrugOrderBasketItem>(
|
|
26
|
+
patient,
|
|
27
|
+
'medications',
|
|
28
|
+
prepMedicationOrderPostData,
|
|
29
|
+
);
|
|
27
30
|
const [isExpanded, setIsExpanded] = useState(orders.length > 0);
|
|
28
31
|
const {
|
|
29
32
|
incompleteOrderBasketItems,
|
|
@@ -61,22 +64,6 @@ export default function DrugOrderBasketPanelExtension() {
|
|
|
61
64
|
};
|
|
62
65
|
}, [orders]);
|
|
63
66
|
|
|
64
|
-
const openDrugSearch = () => {
|
|
65
|
-
closeWorkspace('order-basket', {
|
|
66
|
-
ignoreChanges: true,
|
|
67
|
-
onWorkspaceClose: () => launchWorkspace('add-drug-order'),
|
|
68
|
-
closeWorkspaceGroup: false,
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const openDrugForm = (order: DrugOrderBasketItem) => {
|
|
73
|
-
closeWorkspace('order-basket', {
|
|
74
|
-
ignoreChanges: true,
|
|
75
|
-
onWorkspaceClose: () => launchWorkspace('add-drug-order', { order }),
|
|
76
|
-
closeWorkspaceGroup: false,
|
|
77
|
-
});
|
|
78
|
-
};
|
|
79
|
-
|
|
80
67
|
const removeMedication = useCallback(
|
|
81
68
|
(order: DrugOrderBasketItem) => {
|
|
82
69
|
const newOrders = [...orders];
|
|
@@ -105,7 +92,7 @@ export default function DrugOrderBasketPanelExtension() {
|
|
|
105
92
|
kind="ghost"
|
|
106
93
|
renderIcon={(props: ComponentProps<typeof AddIcon>) => <AddIcon size={16} {...props} />}
|
|
107
94
|
iconDescription="Add medication"
|
|
108
|
-
onClick={
|
|
95
|
+
onClick={() => launchDrugOrderForm()}
|
|
109
96
|
size={isTablet ? 'md' : 'sm'}
|
|
110
97
|
>
|
|
111
98
|
{t('add', 'Add')}
|
|
@@ -133,7 +120,7 @@ export default function DrugOrderBasketPanelExtension() {
|
|
|
133
120
|
<OrderBasketItemTile
|
|
134
121
|
key={index}
|
|
135
122
|
orderBasketItem={order}
|
|
136
|
-
onItemClick={() =>
|
|
123
|
+
onItemClick={() => launchDrugOrderForm(order)}
|
|
137
124
|
onRemoveClick={() => removeMedication(order)}
|
|
138
125
|
/>
|
|
139
126
|
))}
|
|
@@ -145,7 +132,7 @@ export default function DrugOrderBasketPanelExtension() {
|
|
|
145
132
|
<OrderBasketItemTile
|
|
146
133
|
key={index}
|
|
147
134
|
orderBasketItem={order}
|
|
148
|
-
onItemClick={() =>
|
|
135
|
+
onItemClick={() => launchDrugOrderForm(order)}
|
|
149
136
|
onRemoveClick={() => removeMedication(order)}
|
|
150
137
|
/>
|
|
151
138
|
))}
|
|
@@ -158,7 +145,7 @@ export default function DrugOrderBasketPanelExtension() {
|
|
|
158
145
|
<OrderBasketItemTile
|
|
159
146
|
key={index}
|
|
160
147
|
orderBasketItem={item}
|
|
161
|
-
onItemClick={() =>
|
|
148
|
+
onItemClick={() => launchDrugOrderForm(item)}
|
|
162
149
|
onRemoveClick={() => removeMedication(item)}
|
|
163
150
|
/>
|
|
164
151
|
))}
|
|
@@ -171,7 +158,7 @@ export default function DrugOrderBasketPanelExtension() {
|
|
|
171
158
|
<OrderBasketItemTile
|
|
172
159
|
key={index}
|
|
173
160
|
orderBasketItem={item}
|
|
174
|
-
onItemClick={() =>
|
|
161
|
+
onItemClick={() => launchDrugOrderForm(item)}
|
|
175
162
|
onRemoveClick={() => removeMedication(item)}
|
|
176
163
|
/>
|
|
177
164
|
))}
|
|
@@ -184,7 +171,7 @@ export default function DrugOrderBasketPanelExtension() {
|
|
|
184
171
|
<OrderBasketItemTile
|
|
185
172
|
key={index}
|
|
186
173
|
orderBasketItem={item}
|
|
187
|
-
onItemClick={() =>
|
|
174
|
+
onItemClick={() => launchDrugOrderForm(item)}
|
|
188
175
|
onRemoveClick={() => removeMedication(item)}
|
|
189
176
|
/>
|
|
190
177
|
))}
|
|
@@ -195,3 +182,5 @@ export default function DrugOrderBasketPanelExtension() {
|
|
|
195
182
|
</Tile>
|
|
196
183
|
);
|
|
197
184
|
}
|
|
185
|
+
|
|
186
|
+
export default DrugOrderBasketPanelExtension;
|