@openmrs/esm-patient-tests-app 11.3.1-pre.9447 → 11.3.1-pre.9455
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 +11 -11
- package/dist/{1935.js → 1176.js} +1 -1
- package/dist/1176.js.map +1 -0
- package/dist/1477.js +1 -1
- package/dist/1477.js.map +1 -1
- package/dist/1638.js +1 -1
- package/dist/1638.js.map +1 -1
- package/dist/4300.js +1 -1
- package/dist/629.js +1 -0
- package/dist/629.js.map +1 -0
- package/dist/671.js +1 -0
- package/dist/671.js.map +1 -0
- package/dist/7202.js +1 -1
- package/dist/7202.js.map +1 -1
- package/dist/790.js +1 -1
- package/dist/790.js.map +1 -1
- package/dist/9838.js +1 -0
- package/dist/9838.js.map +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-patient-tests-app.js +1 -1
- package/dist/openmrs-esm-patient-tests-app.js.buildmanifest.json +109 -85
- package/dist/openmrs-esm-patient-tests-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +2 -2
- package/src/edit-test-results/modal/edit-lab-results.modal.tsx +4 -3
- package/src/index.ts +5 -1
- package/src/routes.json +2 -3
- package/src/test-orders/add-test-order/add-test-order.component.tsx +125 -0
- package/src/test-orders/add-test-order/add-test-order.test.tsx +22 -45
- package/src/test-orders/add-test-order/add-test-order.workspace.tsx +24 -152
- package/src/test-orders/add-test-order/exported-add-test-order.workspace.tsx +30 -0
- package/src/test-orders/add-test-order/test-order-form.component.tsx +68 -60
- package/src/test-orders/add-test-order/test-order.ts +3 -3
- package/src/test-orders/add-test-order/test-type-search.component.tsx +28 -60
- package/src/test-orders/api.ts +6 -2
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-item-tile.component.tsx +1 -1
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-panel.extension.tsx +26 -84
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-panel.test.tsx +10 -12
- package/src/test-results/tree-view/tree-view.component.tsx +1 -1
- package/src/types.ts +0 -9
- package/translations/en.json +2 -4
- package/dist/1935.js.map +0 -1
- package/dist/34.js +0 -1
- package/dist/34.js.map +0 -1
- package/dist/6113.js +0 -1
- package/dist/6113.js.map +0 -1
|
@@ -19,35 +19,35 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
|
|
19
19
|
import { z } from 'zod';
|
|
20
20
|
import { useTranslation } from 'react-i18next';
|
|
21
21
|
import {
|
|
22
|
-
type DefaultPatientWorkspaceProps,
|
|
23
|
-
type Order,
|
|
24
22
|
type OrderUrgency,
|
|
25
23
|
priorityOptions,
|
|
26
24
|
useOrderBasket,
|
|
27
25
|
useOrderType,
|
|
26
|
+
type TestOrderBasketItem,
|
|
27
|
+
postOrder,
|
|
28
|
+
useMutatePatientOrders,
|
|
29
|
+
showOrderSuccessToast,
|
|
28
30
|
} from '@openmrs/esm-patient-common-lib';
|
|
29
31
|
import {
|
|
30
32
|
ExtensionSlot,
|
|
31
|
-
launchWorkspace,
|
|
32
33
|
OpenmrsDatePicker,
|
|
34
|
+
showSnackbar,
|
|
33
35
|
useConfig,
|
|
34
36
|
useLayoutType,
|
|
35
37
|
useSession,
|
|
38
|
+
type Workspace2DefinitionProps,
|
|
36
39
|
} from '@openmrs/esm-framework';
|
|
37
40
|
import { prepTestOrderPostData, useOrderReasons } from '../api';
|
|
38
41
|
import { ordersEqual } from './test-order';
|
|
39
42
|
import { type ConfigObject } from '../../config-schema';
|
|
40
|
-
import { type TestOrderBasketItem } from '../../types';
|
|
41
|
-
import { WORKSPACES } from '../lab-order-basket-panel/lab-order-basket-panel.extension';
|
|
42
43
|
import styles from './test-order-form.scss';
|
|
43
44
|
|
|
44
|
-
export interface LabOrderFormProps
|
|
45
|
+
export interface LabOrderFormProps {
|
|
46
|
+
closeWorkspace: Workspace2DefinitionProps['closeWorkspace'];
|
|
45
47
|
initialOrder: TestOrderBasketItem;
|
|
46
48
|
orderTypeUuid: string;
|
|
47
49
|
orderableConceptSets: Array<string>;
|
|
48
|
-
|
|
49
|
-
isWorkSpaceType: (value: string) => boolean;
|
|
50
|
-
prevOrder: Order;
|
|
50
|
+
setHasUnsavedChanges: (hasUnsavedChanges: boolean) => void;
|
|
51
51
|
patient: fhir.Patient;
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -57,25 +57,22 @@ export interface LabOrderFormProps extends DefaultPatientWorkspaceProps {
|
|
|
57
57
|
export function LabOrderForm({
|
|
58
58
|
initialOrder,
|
|
59
59
|
closeWorkspace,
|
|
60
|
-
closeWorkspaceWithSavedChanges,
|
|
61
|
-
promptBeforeClosing,
|
|
62
60
|
orderTypeUuid,
|
|
63
|
-
|
|
64
|
-
prevWorkSpace,
|
|
65
|
-
isWorkSpaceType,
|
|
66
|
-
prevOrder,
|
|
67
|
-
patientUuid,
|
|
61
|
+
setHasUnsavedChanges,
|
|
68
62
|
patient,
|
|
69
63
|
}: LabOrderFormProps) {
|
|
70
64
|
const { t } = useTranslation();
|
|
71
65
|
const isTablet = useLayoutType() === 'tablet';
|
|
72
66
|
const session = useSession();
|
|
73
|
-
const
|
|
74
|
-
|
|
67
|
+
const { orders, setOrders, clearOrders } = useOrderBasket<TestOrderBasketItem>(
|
|
68
|
+
patient,
|
|
69
|
+
orderTypeUuid,
|
|
70
|
+
prepTestOrderPostData,
|
|
71
|
+
);
|
|
75
72
|
const [showErrorNotification, setShowErrorNotification] = useState(false);
|
|
76
73
|
const config = useConfig<ConfigObject>();
|
|
77
|
-
const { orderType
|
|
78
|
-
|
|
74
|
+
const { orderType } = useOrderType(orderTypeUuid);
|
|
75
|
+
const { mutate: mutateOrders } = useMutatePatientOrders(patient.id);
|
|
79
76
|
const orderReasonRequired = useMemo(
|
|
80
77
|
() =>
|
|
81
78
|
(config.labTestsWithOrderReasons?.find((c) => c.labTestUuid === initialOrder?.testType?.conceptUuid) || {})
|
|
@@ -147,7 +144,7 @@ export function LabOrderForm({
|
|
|
147
144
|
return itemDisplay?.includes(inputValue);
|
|
148
145
|
}, []);
|
|
149
146
|
|
|
150
|
-
const
|
|
147
|
+
const saveLabOrderToBasket = useCallback(
|
|
151
148
|
(data: TestOrderBasketItem) => {
|
|
152
149
|
const finalizedOrder: TestOrderBasketItem = {
|
|
153
150
|
...initialOrder,
|
|
@@ -170,40 +167,46 @@ export function LabOrderForm({
|
|
|
170
167
|
|
|
171
168
|
setOrders(newOrders);
|
|
172
169
|
|
|
173
|
-
|
|
174
|
-
onWorkspaceClose: () =>
|
|
175
|
-
typeof isWorkSpaceType === 'function' &&
|
|
176
|
-
isWorkSpaceType(prevWorkSpace) &&
|
|
177
|
-
prevWorkSpace === WORKSPACES.TEST_RESULTS_FORM
|
|
178
|
-
? launchWorkspace(prevWorkSpace, { order: prevOrder })
|
|
179
|
-
: launchWorkspace(WORKSPACES.ORDER_BASKET),
|
|
180
|
-
closeWorkspaceGroup: false,
|
|
181
|
-
});
|
|
170
|
+
closeWorkspace({ discardUnsavedChanges: true });
|
|
182
171
|
},
|
|
183
|
-
[
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
172
|
+
[orders, setOrders, session?.currentProvider?.uuid, closeWorkspace, initialOrder],
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const submitLabOrderToServer = useCallback(
|
|
176
|
+
(data: TestOrderBasketItem) => {
|
|
177
|
+
const finalizedOrder: TestOrderBasketItem = {
|
|
178
|
+
...initialOrder,
|
|
179
|
+
...data,
|
|
180
|
+
};
|
|
181
|
+
finalizedOrder.orderer = session.currentProvider.uuid;
|
|
182
|
+
postOrder(prepTestOrderPostData(finalizedOrder, patient.id, finalizedOrder?.encounterUuid))
|
|
183
|
+
.then(() => {
|
|
184
|
+
clearOrders();
|
|
185
|
+
mutateOrders();
|
|
186
|
+
showOrderSuccessToast(t, [finalizedOrder]);
|
|
187
|
+
closeWorkspace({ discardUnsavedChanges: true });
|
|
188
|
+
})
|
|
189
|
+
.catch((error) => {
|
|
190
|
+
showSnackbar({
|
|
191
|
+
isLowContrast: false,
|
|
192
|
+
kind: 'error',
|
|
193
|
+
title: t('errorSavingLabOrder', 'Error saving lab order'),
|
|
194
|
+
subtitle: error.message,
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
[clearOrders, closeWorkspace, initialOrder, mutateOrders, patient.id, session.currentProvider.uuid, t],
|
|
193
199
|
);
|
|
194
200
|
|
|
195
201
|
const cancelOrder = useCallback(() => {
|
|
196
202
|
setOrders(orders.filter((order) => order.testType.conceptUuid !== defaultValues.testType.conceptUuid));
|
|
197
|
-
closeWorkspace(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
closeWorkspaceGroup: false,
|
|
205
|
-
});
|
|
206
|
-
}, [closeWorkspace, orders, setOrders, defaultValues, isWorkSpaceType, prevOrder, prevWorkSpace]);
|
|
203
|
+
closeWorkspace();
|
|
204
|
+
}, [closeWorkspace, orders, setOrders, defaultValues]);
|
|
205
|
+
|
|
206
|
+
const closeModifyOrderWorkspace = useCallback(() => {
|
|
207
|
+
clearOrders();
|
|
208
|
+
closeWorkspace();
|
|
209
|
+
}, [clearOrders, closeWorkspace]);
|
|
207
210
|
|
|
208
211
|
const onError = (errors: FieldErrors<TestOrderBasketItem>) => {
|
|
209
212
|
if (errors) {
|
|
@@ -225,19 +228,23 @@ export function LabOrderForm({
|
|
|
225
228
|
);
|
|
226
229
|
|
|
227
230
|
useEffect(() => {
|
|
228
|
-
|
|
229
|
-
}, [isDirty,
|
|
231
|
+
setHasUnsavedChanges(isDirty);
|
|
232
|
+
}, [isDirty, setHasUnsavedChanges]);
|
|
230
233
|
|
|
231
234
|
const responsiveSize = isTablet ? 'lg' : 'sm';
|
|
232
235
|
|
|
233
236
|
return (
|
|
234
|
-
<Form
|
|
237
|
+
<Form
|
|
238
|
+
className={styles.orderForm}
|
|
239
|
+
onSubmit={handleSubmit(initialOrder?.action == 'REVISE' ? submitLabOrderToServer : saveLabOrderToBasket, onError)}
|
|
240
|
+
id="drugOrderForm"
|
|
241
|
+
>
|
|
235
242
|
<div className={styles.form}>
|
|
236
243
|
<ExtensionSlot name="top-of-lab-order-form-slot" state={{ order: initialOrder }} />
|
|
237
244
|
<Grid className={styles.gridRow}>
|
|
238
245
|
<Column lg={16} md={8} sm={4}>
|
|
239
246
|
<InputWrapper>
|
|
240
|
-
<
|
|
247
|
+
<label className={styles.testTypeLabel}>{t('testType', 'Test type')}</label>
|
|
241
248
|
<p className={styles.testType}>{initialOrder?.testType?.label}</p>
|
|
242
249
|
</InputWrapper>
|
|
243
250
|
</Column>
|
|
@@ -381,15 +388,16 @@ export function LabOrderForm({
|
|
|
381
388
|
<ButtonSet
|
|
382
389
|
className={classNames(styles.buttonSet, isTablet ? styles.tabletButtonSet : styles.desktopButtonSet)}
|
|
383
390
|
>
|
|
384
|
-
<Button
|
|
391
|
+
<Button
|
|
392
|
+
className={styles.button}
|
|
393
|
+
kind="secondary"
|
|
394
|
+
onClick={initialOrder?.action == 'REVISE' ? closeModifyOrderWorkspace : cancelOrder}
|
|
395
|
+
size="xl"
|
|
396
|
+
>
|
|
385
397
|
{t('discard', 'Discard')}
|
|
386
398
|
</Button>
|
|
387
399
|
<Button className={styles.button} kind="primary" size="xl" type="submit">
|
|
388
|
-
{
|
|
389
|
-
isWorkSpaceType(prevWorkSpace) &&
|
|
390
|
-
prevWorkSpace === WORKSPACES.TEST_RESULTS_FORM
|
|
391
|
-
? t('saveTest', 'Save test')
|
|
392
|
-
: t('saveOrder', 'Save order')}
|
|
400
|
+
{t('saveOrder', 'Save order')}
|
|
393
401
|
</Button>
|
|
394
402
|
</ButtonSet>
|
|
395
403
|
</div>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { priorityOptions, type OrderUrgency } from '@openmrs/esm-patient-common-lib';
|
|
1
|
+
import { priorityOptions, type OrderUrgency, type TestOrderBasketItem } from '@openmrs/esm-patient-common-lib';
|
|
2
2
|
import { type TestType } from './useTestTypes';
|
|
3
|
-
import type { TestOrderBasketItem } from '../../types';
|
|
4
3
|
|
|
5
4
|
type LabOrderRequest = Pick<TestOrderBasketItem, 'action' | 'testType'>;
|
|
6
5
|
|
|
7
|
-
export function createEmptyLabOrder(testType: TestType, orderer: string): TestOrderBasketItem {
|
|
6
|
+
export function createEmptyLabOrder(testType: TestType, orderer: string, visit): TestOrderBasketItem {
|
|
8
7
|
return {
|
|
9
8
|
action: 'NEW',
|
|
10
9
|
urgency: priorityOptions[0].value as OrderUrgency,
|
|
11
10
|
display: testType.label,
|
|
12
11
|
testType,
|
|
13
12
|
orderer,
|
|
13
|
+
visit,
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -5,34 +5,30 @@ import { Button, ButtonSkeleton, Search, SkeletonText, Tile } from '@carbon/reac
|
|
|
5
5
|
import { ShoppingCartArrowUp } from '@carbon/react/icons';
|
|
6
6
|
import {
|
|
7
7
|
ArrowRightIcon,
|
|
8
|
-
closeWorkspace,
|
|
9
|
-
launchWorkspace,
|
|
10
8
|
ResponsiveWrapper,
|
|
11
9
|
ShoppingCartArrowDownIcon,
|
|
12
10
|
useDebounce,
|
|
13
11
|
useLayoutType,
|
|
14
12
|
useSession,
|
|
13
|
+
type Visit,
|
|
14
|
+
type Workspace2DefinitionProps,
|
|
15
15
|
} from '@openmrs/esm-framework';
|
|
16
|
-
import { useOrderBasket, type
|
|
17
|
-
import type { TestOrderBasketItem } from '../../types';
|
|
16
|
+
import { useOrderBasket, type TestOrderBasketItem } from '@openmrs/esm-patient-common-lib';
|
|
18
17
|
import { prepTestOrderPostData } from '../api';
|
|
19
18
|
import { createEmptyLabOrder } from './test-order';
|
|
20
19
|
import { useTestTypes, type TestType } from './useTestTypes';
|
|
21
|
-
import { WORKSPACES } from '../lab-order-basket-panel/lab-order-basket-panel.extension';
|
|
22
20
|
import styles from './test-type-search.scss';
|
|
23
21
|
|
|
24
22
|
export interface TestTypeSearchProps {
|
|
25
23
|
openLabForm: (searchResult: TestOrderBasketItem) => void;
|
|
26
24
|
orderTypeUuid: string;
|
|
27
25
|
orderableConceptSets: Array<string>;
|
|
28
|
-
|
|
29
|
-
isWorkSpaceType: (value: string) => boolean;
|
|
30
|
-
prevOrder: Order;
|
|
26
|
+
closeWorkspace: Workspace2DefinitionProps['closeWorkspace'];
|
|
31
27
|
patient: fhir.Patient;
|
|
28
|
+
visit: Visit;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
interface TestTypeSearchResultsProps extends TestTypeSearchProps {
|
|
35
|
-
cancelOrder: () => void;
|
|
36
32
|
searchTerm: string;
|
|
37
33
|
focusAndClearSearchInput: () => void;
|
|
38
34
|
patient: fhir.Patient;
|
|
@@ -42,20 +38,18 @@ interface TestTypeSearchResultItemProps {
|
|
|
42
38
|
orderTypeUuid: string;
|
|
43
39
|
testType: TestType;
|
|
44
40
|
openOrderForm: (searchResult: TestOrderBasketItem) => void;
|
|
45
|
-
prevWorkSpace: string;
|
|
46
|
-
isWorkSpaceType: (value: string) => boolean;
|
|
47
|
-
prevOrder: Order;
|
|
48
41
|
patient: fhir.Patient;
|
|
42
|
+
visit: Visit;
|
|
43
|
+
closeWorkspace: Workspace2DefinitionProps['closeWorkspace'];
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
export function TestTypeSearch({
|
|
47
|
+
patient,
|
|
48
|
+
visit,
|
|
52
49
|
openLabForm,
|
|
53
50
|
orderTypeUuid,
|
|
54
51
|
orderableConceptSets,
|
|
55
|
-
|
|
56
|
-
isWorkSpaceType,
|
|
57
|
-
prevOrder,
|
|
58
|
-
patient,
|
|
52
|
+
closeWorkspace,
|
|
59
53
|
}: TestTypeSearchProps) {
|
|
60
54
|
const { t } = useTranslation();
|
|
61
55
|
const [searchTerm, setSearchTerm] = useState('');
|
|
@@ -67,18 +61,6 @@ export function TestTypeSearch({
|
|
|
67
61
|
searchInputRef.current?.focus();
|
|
68
62
|
}, [setSearchTerm]);
|
|
69
63
|
|
|
70
|
-
const cancelOrder = useCallback(() => {
|
|
71
|
-
closeWorkspace('add-lab-order', {
|
|
72
|
-
ignoreChanges: true,
|
|
73
|
-
onWorkspaceClose: () =>
|
|
74
|
-
typeof isWorkSpaceType === 'function' &&
|
|
75
|
-
isWorkSpaceType(prevWorkSpace) &&
|
|
76
|
-
prevWorkSpace === WORKSPACES.TEST_RESULTS_FORM
|
|
77
|
-
? launchWorkspace(prevWorkSpace, { order: prevOrder })
|
|
78
|
-
: launchWorkspace(WORKSPACES.ORDER_BASKET),
|
|
79
|
-
});
|
|
80
|
-
}, [isWorkSpaceType, prevOrder, prevWorkSpace]);
|
|
81
|
-
|
|
82
64
|
const handleSearchTermChange = useCallback(
|
|
83
65
|
(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
84
66
|
setSearchTerm(event.target.value ?? '');
|
|
@@ -100,32 +82,28 @@ export function TestTypeSearch({
|
|
|
100
82
|
/>
|
|
101
83
|
</ResponsiveWrapper>
|
|
102
84
|
<TestTypeSearchResults
|
|
103
|
-
|
|
85
|
+
closeWorkspace={closeWorkspace}
|
|
104
86
|
orderTypeUuid={orderTypeUuid}
|
|
105
87
|
orderableConceptSets={orderableConceptSets}
|
|
106
88
|
focusAndClearSearchInput={focusAndClearSearchInput}
|
|
107
89
|
openLabForm={openLabForm}
|
|
108
90
|
searchTerm={debouncedSearchTerm}
|
|
109
|
-
prevWorkSpace={prevWorkSpace}
|
|
110
|
-
isWorkSpaceType={isWorkSpaceType}
|
|
111
|
-
prevOrder={prevOrder}
|
|
112
91
|
patient={patient}
|
|
92
|
+
visit={visit}
|
|
113
93
|
/>
|
|
114
94
|
</>
|
|
115
95
|
);
|
|
116
96
|
}
|
|
117
97
|
|
|
118
98
|
function TestTypeSearchResults({
|
|
119
|
-
|
|
99
|
+
closeWorkspace,
|
|
120
100
|
searchTerm,
|
|
121
101
|
orderTypeUuid,
|
|
122
102
|
orderableConceptSets,
|
|
123
103
|
openLabForm,
|
|
124
104
|
focusAndClearSearchInput,
|
|
125
|
-
prevWorkSpace,
|
|
126
|
-
isWorkSpaceType,
|
|
127
|
-
prevOrder,
|
|
128
105
|
patient,
|
|
106
|
+
visit,
|
|
129
107
|
}: TestTypeSearchResultsProps) {
|
|
130
108
|
const { t } = useTranslation();
|
|
131
109
|
const isTablet = useLayoutType() === 'tablet';
|
|
@@ -176,10 +154,9 @@ function TestTypeSearchResults({
|
|
|
176
154
|
orderTypeUuid={orderTypeUuid}
|
|
177
155
|
openOrderForm={openLabForm}
|
|
178
156
|
testType={testType}
|
|
179
|
-
|
|
180
|
-
isWorkSpaceType={isWorkSpaceType}
|
|
181
|
-
prevOrder={prevOrder}
|
|
157
|
+
closeWorkspace={closeWorkspace}
|
|
182
158
|
patient={patient}
|
|
159
|
+
visit={visit}
|
|
183
160
|
/>
|
|
184
161
|
))}
|
|
185
162
|
</div>
|
|
@@ -187,12 +164,12 @@ function TestTypeSearchResults({
|
|
|
187
164
|
{isTablet && (
|
|
188
165
|
<div className={styles.separatorContainer}>
|
|
189
166
|
<p className={styles.separator}>{t('or', 'or')}</p>
|
|
190
|
-
<Button
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
167
|
+
<Button
|
|
168
|
+
iconDescription="Return to order basket"
|
|
169
|
+
kind="ghost"
|
|
170
|
+
onClick={() => closeWorkspace({ discardUnsavedChanges: true })}
|
|
171
|
+
>
|
|
172
|
+
{t('back', 'Back')}
|
|
196
173
|
</Button>
|
|
197
174
|
</div>
|
|
198
175
|
)}
|
|
@@ -224,10 +201,9 @@ const TestTypeSearchResultItem: React.FC<TestTypeSearchResultItemProps> = ({
|
|
|
224
201
|
testType,
|
|
225
202
|
openOrderForm,
|
|
226
203
|
orderTypeUuid,
|
|
227
|
-
|
|
228
|
-
isWorkSpaceType,
|
|
229
|
-
prevOrder,
|
|
204
|
+
closeWorkspace,
|
|
230
205
|
patient,
|
|
206
|
+
visit,
|
|
231
207
|
}) => {
|
|
232
208
|
const { t } = useTranslation();
|
|
233
209
|
const isTablet = useLayoutType() === 'tablet';
|
|
@@ -241,25 +217,17 @@ const TestTypeSearchResultItem: React.FC<TestTypeSearchResultItemProps> = ({
|
|
|
241
217
|
|
|
242
218
|
const createLabOrder = useCallback(
|
|
243
219
|
(orderableConcept: TestType) => {
|
|
244
|
-
return createEmptyLabOrder(orderableConcept, session.currentProvider?.uuid);
|
|
220
|
+
return createEmptyLabOrder(orderableConcept, session.currentProvider?.uuid, visit);
|
|
245
221
|
},
|
|
246
|
-
[session.currentProvider.uuid],
|
|
222
|
+
[session.currentProvider.uuid, visit],
|
|
247
223
|
);
|
|
248
224
|
|
|
249
225
|
const addToBasket = useCallback(() => {
|
|
250
226
|
const labOrder = createLabOrder(testType);
|
|
251
227
|
labOrder.isOrderIncomplete = true;
|
|
252
228
|
setOrders([...orders, labOrder]);
|
|
253
|
-
closeWorkspace(
|
|
254
|
-
|
|
255
|
-
onWorkspaceClose: () =>
|
|
256
|
-
typeof isWorkSpaceType === 'function' &&
|
|
257
|
-
isWorkSpaceType(prevWorkSpace) &&
|
|
258
|
-
prevWorkSpace === WORKSPACES.TEST_RESULTS_FORM
|
|
259
|
-
? launchWorkspace(prevWorkSpace, { order: prevOrder })
|
|
260
|
-
: launchWorkspace(WORKSPACES.ORDER_BASKET),
|
|
261
|
-
});
|
|
262
|
-
}, [orders, setOrders, createLabOrder, testType, isWorkSpaceType, prevOrder, prevWorkSpace]);
|
|
229
|
+
closeWorkspace({ discardUnsavedChanges: true });
|
|
230
|
+
}, [orders, setOrders, createLabOrder, testType, closeWorkspace]);
|
|
263
231
|
|
|
264
232
|
const removeFromBasket = useCallback(() => {
|
|
265
233
|
setOrders(orders.filter((order) => order.testType.conceptUuid !== testType.conceptUuid));
|
package/src/test-orders/api.ts
CHANGED
|
@@ -2,7 +2,12 @@ import { useCallback, useMemo } from 'react';
|
|
|
2
2
|
import { chunk } from 'lodash-es';
|
|
3
3
|
import useSWR, { useSWRConfig } from 'swr';
|
|
4
4
|
import useSWRImmutable from 'swr/immutable';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
OrderPost,
|
|
7
|
+
PatientOrderFetchResponse,
|
|
8
|
+
TestOrderBasketItem,
|
|
9
|
+
TestOrderPost,
|
|
10
|
+
} from '@openmrs/esm-patient-common-lib';
|
|
6
11
|
import {
|
|
7
12
|
type FetchResponse,
|
|
8
13
|
openmrsFetch,
|
|
@@ -12,7 +17,6 @@ import {
|
|
|
12
17
|
useConfig,
|
|
13
18
|
} from '@openmrs/esm-framework';
|
|
14
19
|
import { type ConfigObject } from '../config-schema';
|
|
15
|
-
import type { TestOrderBasketItem } from '../types';
|
|
16
20
|
|
|
17
21
|
export const careSettingUuid = '6f0c9a92-6f24-11e3-af88-005056821db0';
|
|
18
22
|
|
|
@@ -3,7 +3,7 @@ import classNames from 'classnames';
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { ClickableTile, IconButton, Tile } from '@carbon/react';
|
|
5
5
|
import { ExtensionSlot, TrashCanIcon, useLayoutType, WarningIcon } from '@openmrs/esm-framework';
|
|
6
|
-
import type { TestOrderBasketItem } from '
|
|
6
|
+
import type { TestOrderBasketItem } from '@openmrs/esm-patient-common-lib';
|
|
7
7
|
import styles from './lab-order-basket-item-tile.scss';
|
|
8
8
|
|
|
9
9
|
export interface OrderBasketItemTileProps {
|
|
@@ -2,38 +2,26 @@ import React, { type ComponentProps, useCallback, useEffect, useMemo, useState }
|
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { Button, Tile } from '@carbon/react';
|
|
5
|
+
import { AddIcon, ChevronDownIcon, ChevronUpIcon, useLayoutType, useConfig, MaybeIcon } from '@openmrs/esm-framework';
|
|
5
6
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
useConfig,
|
|
12
|
-
MaybeIcon,
|
|
13
|
-
launchWorkspace,
|
|
14
|
-
useWorkspaces,
|
|
15
|
-
type Visit,
|
|
16
|
-
} from '@openmrs/esm-framework';
|
|
17
|
-
import { type OrderBasketItem, useOrderBasket, useOrderType } from '@openmrs/esm-patient-common-lib';
|
|
7
|
+
type TestOrderBasketItem,
|
|
8
|
+
useOrderBasket,
|
|
9
|
+
useOrderType,
|
|
10
|
+
type OrderBasketExtensionProps,
|
|
11
|
+
} from '@openmrs/esm-patient-common-lib';
|
|
18
12
|
import type { ConfigObject } from '../../config-schema';
|
|
19
|
-
import type { TestOrderBasketItem } from '../../types';
|
|
20
13
|
import { LabOrderBasketItemTile } from './lab-order-basket-item-tile.component';
|
|
21
14
|
import { prepTestOrderPostData } from '../api';
|
|
22
15
|
import LabIcon from './lab-icon.component';
|
|
23
16
|
import styles from './lab-order-basket-panel.scss';
|
|
24
17
|
|
|
25
|
-
interface OrderBasketSlotProps {
|
|
26
|
-
patientUuid: string;
|
|
27
|
-
patient: fhir.Patient;
|
|
28
|
-
visitContext: Visit;
|
|
29
|
-
mutateVisitContext: () => void;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
18
|
/**
|
|
19
|
+
* The extension is slotted into order-basket-slot in the main Order Basket workspace by default.
|
|
20
|
+
* It renders the "Add +" button for lab orders, and lists pending lab orders in the order basket.
|
|
21
|
+
*
|
|
33
22
|
* Designs: https://app.zeplin.io/project/60d59321e8100b0324762e05/screen/648c44d9d4052c613e7f23da
|
|
34
|
-
* Slotted into order-basket-slot by default
|
|
35
23
|
*/
|
|
36
|
-
|
|
24
|
+
export function LabOrderBasketPanelExtension({ patient, launchLabOrderForm }: OrderBasketExtensionProps) {
|
|
37
25
|
const { orders, additionalTestOrderTypes } = useConfig<ConfigObject>();
|
|
38
26
|
const { t } = useTranslation();
|
|
39
27
|
const allOrderTypes: ConfigObject['additionalTestOrderTypes'] = [
|
|
@@ -49,35 +37,30 @@ const LabOrderBasketPanelExtension: React.FC<OrderBasketSlotProps> = ({ patient
|
|
|
49
37
|
return (
|
|
50
38
|
<>
|
|
51
39
|
{allOrderTypes.map((orderTypeConfig) => (
|
|
52
|
-
<LabOrderBasketPanel
|
|
40
|
+
<LabOrderBasketPanel
|
|
41
|
+
key={orderTypeConfig.orderTypeUuid}
|
|
42
|
+
patient={patient}
|
|
43
|
+
{...orderTypeConfig}
|
|
44
|
+
launchLabOrderForm={launchLabOrderForm}
|
|
45
|
+
/>
|
|
53
46
|
))}
|
|
54
47
|
</>
|
|
55
48
|
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const WORKSPACES = {
|
|
59
|
-
TEST_RESULTS_FORM: 'test-results-form-workspace',
|
|
60
|
-
ORDER_BASKET: 'order-basket',
|
|
61
|
-
};
|
|
49
|
+
}
|
|
62
50
|
|
|
63
51
|
type OrderTypeConfig = ConfigObject['additionalTestOrderTypes'][0];
|
|
64
52
|
|
|
65
53
|
interface LabOrderBasketPanelProps extends OrderTypeConfig {
|
|
66
54
|
patient: fhir.Patient;
|
|
55
|
+
launchLabOrderForm(orderTypeUuid: string, order?: TestOrderBasketItem): void;
|
|
67
56
|
}
|
|
68
57
|
|
|
69
|
-
function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient }: LabOrderBasketPanelProps) {
|
|
58
|
+
function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient, launchLabOrderForm }: LabOrderBasketPanelProps) {
|
|
70
59
|
const { t } = useTranslation();
|
|
71
|
-
type WorkSpaceType = (typeof WORKSPACES)[keyof typeof WORKSPACES];
|
|
72
60
|
const isTablet = useLayoutType() === 'tablet';
|
|
73
61
|
const responsiveSize = isTablet ? 'md' : 'sm';
|
|
74
62
|
const isDefaultLabOrder = icon === 'omrs-icon-lab-order';
|
|
75
63
|
const { orderType, isLoadingOrderType } = useOrderType(orderTypeUuid);
|
|
76
|
-
const { workspaces = [{ name: WORKSPACES.ORDER_BASKET, additionalProps: {} }] } = useWorkspaces();
|
|
77
|
-
const [prevWorkSpace, setPrevWorkSpace] = useState(workspaces[0]?.name);
|
|
78
|
-
const [prevOrder, setPrevOrder] = useState(
|
|
79
|
-
workspaces[0]?.name === WORKSPACES.TEST_RESULTS_FORM ? workspaces[0].additionalProps['order'] : null,
|
|
80
|
-
);
|
|
81
64
|
const { orders, setOrders } = useOrderBasket<TestOrderBasketItem>(patient, orderTypeUuid, prepTestOrderPostData);
|
|
82
65
|
const [isExpanded, setIsExpanded] = useState(orders.length > 0);
|
|
83
66
|
const {
|
|
@@ -115,41 +98,6 @@ function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient }: LabOrderBa
|
|
|
115
98
|
discontinuedOrderBasketItems,
|
|
116
99
|
};
|
|
117
100
|
}, [orders]);
|
|
118
|
-
const isWorkSpaceType = useCallback((value: string): value is WorkSpaceType => {
|
|
119
|
-
return Object.values(WORKSPACES).includes(value as WorkSpaceType);
|
|
120
|
-
}, []);
|
|
121
|
-
|
|
122
|
-
const openNewLabForm = useCallback(() => {
|
|
123
|
-
closeWorkspace(isWorkSpaceType(prevWorkSpace) ? prevWorkSpace : WORKSPACES.ORDER_BASKET, {
|
|
124
|
-
ignoreChanges: true,
|
|
125
|
-
onWorkspaceClose: () =>
|
|
126
|
-
launchWorkspace('add-lab-order', {
|
|
127
|
-
orderTypeUuid: orderTypeUuid,
|
|
128
|
-
prevWorkSpace: prevWorkSpace,
|
|
129
|
-
isWorkSpaceType: isWorkSpaceType,
|
|
130
|
-
prevOrder: prevOrder,
|
|
131
|
-
}),
|
|
132
|
-
closeWorkspaceGroup: false,
|
|
133
|
-
});
|
|
134
|
-
}, [orderTypeUuid, isWorkSpaceType, prevOrder, prevWorkSpace]);
|
|
135
|
-
|
|
136
|
-
const openEditLabForm = useCallback(
|
|
137
|
-
(order: OrderBasketItem) => {
|
|
138
|
-
closeWorkspace(isWorkSpaceType(prevWorkSpace) ? prevWorkSpace : WORKSPACES.ORDER_BASKET, {
|
|
139
|
-
ignoreChanges: true,
|
|
140
|
-
onWorkspaceClose: () =>
|
|
141
|
-
launchWorkspace('add-lab-order', {
|
|
142
|
-
order,
|
|
143
|
-
orderTypeUuid: orderTypeUuid,
|
|
144
|
-
prevWorkSpace: prevWorkSpace,
|
|
145
|
-
isWorkSpaceType: isWorkSpaceType,
|
|
146
|
-
prevOrder: prevOrder,
|
|
147
|
-
}),
|
|
148
|
-
closeWorkspaceGroup: false,
|
|
149
|
-
});
|
|
150
|
-
},
|
|
151
|
-
[orderTypeUuid, isWorkSpaceType, prevOrder, prevWorkSpace],
|
|
152
|
-
);
|
|
153
101
|
|
|
154
102
|
const removeLabOrder = useCallback(
|
|
155
103
|
(order: TestOrderBasketItem) => {
|
|
@@ -181,20 +129,14 @@ function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient }: LabOrderBa
|
|
|
181
129
|
) : (
|
|
182
130
|
<MaybeIcon icon={icon ? icon : 'omrs-icon-generic-order-type'} size={isTablet ? 40 : 24} />
|
|
183
131
|
)}
|
|
184
|
-
<h4 className={styles.heading}>{`${
|
|
185
|
-
isWorkSpaceType(prevWorkSpace) && prevWorkSpace === WORKSPACES.ORDER_BASKET
|
|
186
|
-
? label
|
|
187
|
-
? t(label)
|
|
188
|
-
: orderType?.display
|
|
189
|
-
: t('tests', 'Tests')
|
|
190
|
-
} (${orders.length})`}</h4>
|
|
132
|
+
<h4 className={styles.heading}>{`${label ? t(label) : orderType?.display} (${orders.length})`}</h4>
|
|
191
133
|
</div>
|
|
192
134
|
<div className={styles.buttonContainer}>
|
|
193
135
|
<Button
|
|
194
136
|
className={styles.addButton}
|
|
195
137
|
iconDescription="Add lab order"
|
|
196
138
|
kind="ghost"
|
|
197
|
-
onClick={
|
|
139
|
+
onClick={() => launchLabOrderForm(orderTypeUuid)}
|
|
198
140
|
renderIcon={(props: ComponentProps<typeof AddIcon>) => <AddIcon size={16} {...props} />}
|
|
199
141
|
size={responsiveSize}
|
|
200
142
|
>
|
|
@@ -225,7 +167,7 @@ function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient }: LabOrderBa
|
|
|
225
167
|
{incompleteOrderBasketItems.map((order) => (
|
|
226
168
|
<LabOrderBasketItemTile
|
|
227
169
|
key={order.uuid}
|
|
228
|
-
onItemClick={() =>
|
|
170
|
+
onItemClick={() => launchLabOrderForm(orderTypeUuid, order)}
|
|
229
171
|
onRemoveClick={() => removeLabOrder(order)}
|
|
230
172
|
orderBasketItem={order}
|
|
231
173
|
/>
|
|
@@ -237,7 +179,7 @@ function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient }: LabOrderBa
|
|
|
237
179
|
{newOrderBasketItems.map((order) => (
|
|
238
180
|
<LabOrderBasketItemTile
|
|
239
181
|
key={order.uuid}
|
|
240
|
-
onItemClick={() =>
|
|
182
|
+
onItemClick={() => launchLabOrderForm(orderTypeUuid, order)}
|
|
241
183
|
onRemoveClick={() => removeLabOrder(order)}
|
|
242
184
|
orderBasketItem={order}
|
|
243
185
|
/>
|
|
@@ -250,7 +192,7 @@ function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient }: LabOrderBa
|
|
|
250
192
|
{renewedOrderBasketItems.map((order) => (
|
|
251
193
|
<LabOrderBasketItemTile
|
|
252
194
|
key={order.uuid}
|
|
253
|
-
onItemClick={() =>
|
|
195
|
+
onItemClick={() => launchLabOrderForm(orderTypeUuid, order)}
|
|
254
196
|
onRemoveClick={() => removeLabOrder(order)}
|
|
255
197
|
orderBasketItem={order}
|
|
256
198
|
/>
|
|
@@ -263,7 +205,7 @@ function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient }: LabOrderBa
|
|
|
263
205
|
{revisedOrderBasketItems.map((order) => (
|
|
264
206
|
<LabOrderBasketItemTile
|
|
265
207
|
key={order.uuid}
|
|
266
|
-
onItemClick={() =>
|
|
208
|
+
onItemClick={() => launchLabOrderForm(orderTypeUuid, order)}
|
|
267
209
|
onRemoveClick={() => removeLabOrder(order)}
|
|
268
210
|
orderBasketItem={order}
|
|
269
211
|
/>
|
|
@@ -276,7 +218,7 @@ function LabOrderBasketPanel({ orderTypeUuid, label, icon, patient }: LabOrderBa
|
|
|
276
218
|
{discontinuedOrderBasketItems.map((order) => (
|
|
277
219
|
<LabOrderBasketItemTile
|
|
278
220
|
key={order.uuid}
|
|
279
|
-
onItemClick={() =>
|
|
221
|
+
onItemClick={() => launchLabOrderForm(orderTypeUuid, order)}
|
|
280
222
|
onRemoveClick={() => removeLabOrder(order)}
|
|
281
223
|
orderBasketItem={order}
|
|
282
224
|
/>
|