@openmrs/esm-patient-orders-app 11.3.1-pre.9637 → 11.3.1-pre.9645

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.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +13 -13
  2. package/dist/1253.js +1 -1
  3. package/dist/1253.js.map +1 -1
  4. package/dist/3685.js +1 -1
  5. package/dist/375.js +1 -1
  6. package/dist/375.js.map +1 -1
  7. package/dist/4300.js +1 -1
  8. package/dist/4341.js +1 -1
  9. package/dist/4341.js.map +1 -1
  10. package/dist/4558.js +1 -1
  11. package/dist/4558.js.map +1 -1
  12. package/dist/5937.js +1 -1
  13. package/dist/5937.js.map +1 -1
  14. package/dist/6411.js +1 -1
  15. package/dist/6542.js +1 -1
  16. package/dist/701.js +2 -0
  17. package/dist/701.js.map +1 -0
  18. package/dist/7160.js +1 -1
  19. package/dist/8154.js +1 -1
  20. package/dist/8376.js +1 -1
  21. package/dist/8376.js.map +1 -1
  22. package/dist/main.js +1 -1
  23. package/dist/main.js.map +1 -1
  24. package/dist/openmrs-esm-patient-orders-app.js +1 -1
  25. package/dist/openmrs-esm-patient-orders-app.js.buildmanifest.json +61 -61
  26. package/dist/openmrs-esm-patient-orders-app.js.map +1 -1
  27. package/dist/routes.json +1 -1
  28. package/package.json +2 -2
  29. package/src/api/api.ts +43 -46
  30. package/src/components/order-details-table.component.tsx +48 -68
  31. package/src/config-schema.ts +7 -0
  32. package/src/order-basket/exported-order-basket.workspace.tsx +2 -0
  33. package/src/order-basket/general-order-type/add-general-order/search-results.component.tsx +3 -11
  34. package/src/order-basket/general-order-type/general-order-form/general-order-form.component.tsx +5 -5
  35. package/src/order-basket/general-order-type/resources.ts +15 -15
  36. package/src/order-basket/order-basket.component.tsx +122 -36
  37. package/src/order-basket/order-basket.scss +15 -0
  38. package/src/utils/index.ts +1 -6
  39. package/translations/en.json +5 -0
  40. package/dist/7657.js +0 -2
  41. package/dist/7657.js.map +0 -1
  42. /package/dist/{7657.js.LICENSE.txt → 701.js.LICENSE.txt} +0 -0
@@ -30,7 +30,6 @@ import {
30
30
  CardHeader,
31
31
  EmptyState,
32
32
  ErrorState,
33
- getDrugOrderByUuid,
34
33
  PatientChartPagination,
35
34
  type Order,
36
35
  type OrderBasketItem,
@@ -39,6 +38,8 @@ import {
39
38
  useOrderBasket,
40
39
  useOrderTypes,
41
40
  usePatientOrders,
41
+ getDrugOrderByUuid,
42
+ invalidateVisitByUuid,
42
43
  } from '@openmrs/esm-patient-common-lib';
43
44
  import { prepMedicationOrderPostData } from '@openmrs/esm-patient-medications-app/src/api/api';
44
45
  import { prepTestOrderPostData } from '@openmrs/esm-patient-tests-app/src/test-orders/api';
@@ -65,6 +66,7 @@ import MedicationRecord from './medication-record.component';
65
66
  import PrintComponent from '../print/print.component';
66
67
  import TestOrder from './test-order.component';
67
68
  import styles from './order-details-table.scss';
69
+ import { useSWRConfig } from 'swr';
68
70
 
69
71
  interface OrderDetailsProps {
70
72
  patientUuid: string;
@@ -75,8 +77,6 @@ interface OrderDetailsProps {
75
77
  }
76
78
 
77
79
  interface OrderBasketItemActionsProps {
78
- openOrderBasket: (encounterUuid) => void;
79
- launchOrderForm: (order: Order) => void;
80
80
  orderItem: Order;
81
81
  patient: fhir.Patient;
82
82
  }
@@ -103,9 +103,6 @@ const OrderDetailsTable: React.FC<OrderDetailsProps> = ({
103
103
  const isTablet = useLayoutType() === 'tablet';
104
104
  const responsiveSize = isTablet ? 'lg' : 'md';
105
105
  const _launchOrderBasket = useLaunchWorkspaceRequiringVisit(patientUuid, 'order-basket');
106
- const launchAddDrugOrder = useLaunchWorkspaceRequiringVisit(patientUuid, 'add-drug-order');
107
- const launchModifyLabOrder = useLaunchWorkspaceRequiringVisit(patientUuid, 'add-lab-order');
108
- const launchModifyGeneralOrder = useLaunchWorkspaceRequiringVisit(patientUuid, 'orderable-concept-workspace');
109
106
  const contentToPrintRef = useRef<HTMLDivElement | null>(null);
110
107
  const { excludePatientIdentifierCodeTypes } = useConfig();
111
108
  const [isPrinting, setIsPrinting] = useState(false);
@@ -184,49 +181,11 @@ const OrderDetailsTable: React.FC<OrderDetailsProps> = ({
184
181
  }
185
182
  return allOrders.filter((order) => order.orderType?.uuid === selectedOrderTypeUuid);
186
183
  }, [allOrders, selectedOrderTypeUuid]);
187
-
188
- const launchOrderBasket = useCallback(
189
- (encounterUuid: string) => {
190
- _launchOrderBasket(null, { encounterUuid });
191
- },
184
+ const launchOrderBasketForNewItem = useCallback(
185
+ () => _launchOrderBasket(null, { encounterUuid: '' }),
192
186
  [_launchOrderBasket],
193
187
  );
194
188
 
195
- // launch respective order basket based on order type
196
- const launchOrderForm = useCallback(
197
- (orderItem: Order) => {
198
- switch (orderItem.type) {
199
- case ORDER_TYPES.DRUG_ORDER:
200
- launchAddDrugOrder(
201
- { order: buildMedicationOrder(orderItem, 'REVISE') },
202
- { encounterUuid: orderItem.encounter.uuid },
203
- );
204
- break;
205
- case ORDER_TYPES.TEST_ORDER:
206
- launchModifyLabOrder(
207
- {
208
- order: buildLabOrder(orderItem, 'REVISE'),
209
- orderTypeUuid: orderItem.orderType.uuid,
210
- },
211
- { encounterUuid: orderItem.encounter.uuid },
212
- );
213
- break;
214
- case ORDER_TYPES.GENERAL_ORDER:
215
- launchModifyGeneralOrder(
216
- {
217
- order: buildGeneralOrder(orderItem, 'REVISE'),
218
- orderTypeUuid: orderItem.orderType.uuid,
219
- },
220
- { encounterUuid: orderItem.encounter.uuid },
221
- );
222
- break;
223
- default:
224
- launchOrderBasket(orderItem.encounter.uuid);
225
- }
226
- },
227
- [launchAddDrugOrder, launchModifyGeneralOrder, launchModifyLabOrder, launchOrderBasket],
228
- );
229
-
230
189
  const tableHeaders: Array<OrderHeaderProps> = [
231
190
  {
232
191
  key: 'orderNumber',
@@ -439,7 +398,7 @@ const OrderDetailsTable: React.FC<OrderDetailsProps> = ({
439
398
  <EmptyState
440
399
  headerTitle={headerTitle}
441
400
  displayText={emptyStateDisplayText}
442
- launchForm={() => launchOrderBasket('')}
401
+ launchForm={() => launchOrderBasketForNewItem()}
443
402
  />
444
403
  ) : (
445
404
  <div className={styles.widgetCard}>
@@ -467,7 +426,7 @@ const OrderDetailsTable: React.FC<OrderDetailsProps> = ({
467
426
  kind="ghost"
468
427
  renderIcon={AddIcon}
469
428
  iconDescription={t('launchOrderBasket', 'Launch order basket')}
470
- onClick={() => launchOrderBasket('')}
429
+ onClick={() => launchOrderBasketForNewItem()}
471
430
  >
472
431
  {t('add', 'Add')}
473
432
  </Button>
@@ -541,12 +500,7 @@ const OrderDetailsTable: React.FC<OrderDetailsProps> = ({
541
500
  {!isPrinting && (
542
501
  <TableCell className="cds--table-column-menu">
543
502
  {matchingOrder && isOmrsOrder(matchingOrder) ? (
544
- <OrderBasketItemActions
545
- patient={patient}
546
- launchOrderForm={launchOrderForm}
547
- openOrderBasket={launchOrderBasket}
548
- orderItem={matchingOrder}
549
- />
503
+ <OrderBasketItemActions patient={patient} orderItem={matchingOrder} />
550
504
  ) : (
551
505
  <ExtensionSlot
552
506
  name={`${matchingOrder?.type}-action-menu-items-slot`}
@@ -628,7 +582,7 @@ const OrderDetailsTable: React.FC<OrderDetailsProps> = ({
628
582
  );
629
583
  };
630
584
 
631
- function OrderBasketItemActions({ orderItem, openOrderBasket, launchOrderForm, patient }: OrderBasketItemActionsProps) {
585
+ function OrderBasketItemActions({ orderItem, patient }: OrderBasketItemActionsProps) {
632
586
  const { t } = useTranslation();
633
587
 
634
588
  // Use the appropriate grouping key and postDataPrepFunction based on order type
@@ -654,48 +608,74 @@ function OrderBasketItemActions({ orderItem, openOrderBasket, launchOrderForm, p
654
608
  const { grouping, postDataPrepFn } = getOrderBasketConfig();
655
609
  const { orders, setOrders } = useOrderBasket<MutableOrderBasketItem>(patient, grouping, postDataPrepFn);
656
610
  const alreadyInBasket = orders.some((x) => x.uuid === orderItem.uuid);
611
+ const { mutate: globalMutate } = useSWRConfig();
612
+
613
+ const windowProps = useMemo(() => ({ encounterUuid: orderItem.encounter.uuid }), [orderItem.encounter.uuid]);
614
+ const groupProps = useMemo(
615
+ () => ({
616
+ patient,
617
+ patientUuid: patient.id,
618
+ visitContext: orderItem.encounter.visit,
619
+ mutateVisitContext: invalidateVisitByUuid(globalMutate, orderItem.encounter.visit.uuid),
620
+ }),
621
+ [patient, orderItem.encounter.visit, globalMutate],
622
+ );
657
623
 
658
624
  const handleCancelOrder = useCallback(() => {
659
625
  if (orderItem.type === ORDER_TYPES.DRUG_ORDER) {
660
626
  getDrugOrderByUuid(orderItem.uuid).then((res) => {
661
627
  const medicationOrder = res.data;
662
628
  const discontinueItem = buildMedicationOrder(medicationOrder, 'DISCONTINUE');
663
- openOrderBasket(orderItem.encounter.uuid);
664
629
  setOrders([...orders, discontinueItem]);
665
630
  });
666
631
  } else if (orderItem.type === ORDER_TYPES.TEST_ORDER) {
667
632
  const labItem = buildLabOrder(orderItem, 'DISCONTINUE');
668
- openOrderBasket(orderItem.encounter.uuid);
669
633
  setOrders([...orders, labItem]);
670
634
  } else {
671
635
  const order = buildGeneralOrder(orderItem, 'DISCONTINUE');
672
- openOrderBasket(orderItem.encounter.uuid);
673
636
  setOrders([...orders, order]);
674
637
  }
675
- }, [orderItem, setOrders, orders, openOrderBasket]);
638
+ launchWorkspace2('order-basket', {}, windowProps, groupProps);
639
+ }, [orderItem, setOrders, orders, windowProps, groupProps]);
676
640
 
677
641
  const handleModifyOrder = useCallback(() => {
678
642
  if (orderItem.type === ORDER_TYPES.DRUG_ORDER) {
643
+ // make another call to fetch the order,
644
+ // this time with custom rep to include the drug field
645
+ // (when we fetch the array containing orderItem, we fetched for
646
+ // all order types and including the drug field in the custom rep will
647
+ // yield an error)
679
648
  getDrugOrderByUuid(orderItem.uuid)
680
649
  .then((res) => {
681
650
  const medicationOrder = res.data;
682
- const medicationItem = buildMedicationOrder(medicationOrder, 'REVISE');
683
- setOrders([...orders, medicationItem]);
684
- launchOrderForm(medicationOrder);
651
+ launchWorkspace2(
652
+ 'add-drug-order',
653
+ { order: buildMedicationOrder(medicationOrder, 'REVISE'), orderToEditOrdererUuid: orderItem.orderer.uuid },
654
+ windowProps,
655
+ groupProps,
656
+ );
685
657
  })
686
658
  .catch((e) => {
687
659
  console.error('Error modifying drug order: ', e);
688
660
  });
689
661
  } else if (orderItem.type === ORDER_TYPES.TEST_ORDER) {
690
662
  const labItem = buildLabOrder(orderItem, 'REVISE');
691
- setOrders([...orders, labItem]);
692
- launchOrderForm(orderItem);
663
+ launchWorkspace2(
664
+ 'add-lab-order',
665
+ { order: labItem, orderTypeUuid: orderItem.orderType.uuid, orderToEditOrdererUuid: orderItem.orderer.uuid },
666
+ windowProps,
667
+ groupProps,
668
+ );
693
669
  } else if (orderItem.type === ORDER_TYPES.GENERAL_ORDER) {
694
- const order = buildGeneralOrder(orderItem, 'REVISE');
695
- setOrders([...orders, order]);
696
- launchOrderForm(orderItem);
670
+ const generalItem = buildGeneralOrder(orderItem, 'REVISE');
671
+ launchWorkspace2(
672
+ 'orderable-concept-workspace',
673
+ { order: generalItem, orderTypeUuid: orderItem.orderType.uuid, orderToEditOrdererUuid: orderItem.orderer.uuid },
674
+ windowProps,
675
+ groupProps,
676
+ );
697
677
  }
698
- }, [orderItem, launchOrderForm, orders, setOrders]);
678
+ }, [orderItem, windowProps, groupProps]);
699
679
 
700
680
  const handleAddOrEditTestResults = useCallback(() => {
701
681
  launchWorkspace2('test-results-form-workspace', { order: orderItem, patient });
@@ -53,6 +53,12 @@ export const configSchema = {
53
53
  _description:
54
54
  'Whether to display the "Reference number" field in the Order form. This field maps to the accession_number property in the Order data model',
55
55
  },
56
+ ordererProviderRoles: {
57
+ _type: Type.Array,
58
+ _description:
59
+ 'Array of provider roles uuids. If specified, the order basket 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 orders form may still do so with themselves as the prescriber.',
60
+ _default: [],
61
+ },
56
62
  };
57
63
 
58
64
  export interface OrderTypeDefinition {
@@ -68,4 +74,5 @@ export interface ConfigObject {
68
74
  showPrintButton: boolean;
69
75
  orderTypes: Array<OrderTypeDefinition>;
70
76
  showReferenceNumberField: boolean;
77
+ ordererProviderRoles: Array<string>;
71
78
  }
@@ -21,6 +21,7 @@ const ExportedOrderBasketWorkspace: React.FC<Workspace2DefinitionProps<{}, Expor
21
21
  drugOrderWorkspaceName,
22
22
  labOrderWorkspaceName,
23
23
  generalOrderWorkspaceName,
24
+ onOrderBasketSubmitted,
24
25
  },
25
26
  closeWorkspace,
26
27
  launchChildWorkspace,
@@ -52,6 +53,7 @@ const ExportedOrderBasketWorkspace: React.FC<Workspace2DefinitionProps<{}, Expor
52
53
  mutateVisitContext={mutateVisitContext}
53
54
  closeWorkspace={closeWorkspace}
54
55
  orderBasketExtensionProps={orderBasketExtensionProps}
56
+ onOrderBasketSubmitted={onOrderBasketSubmitted}
55
57
  />
56
58
  );
57
59
  };
@@ -174,7 +174,6 @@ const TestTypeSearchResultItem: React.FC<TestTypeSearchResultItemProps> = ({
174
174
  }) => {
175
175
  const { t } = useTranslation();
176
176
  const isTablet = useLayoutType() === 'tablet';
177
- const session = useSession();
178
177
  const { orders, setOrders } = useOrderBasket<OrderBasketItem>(patient, orderTypeUuid, prepOrderPostData);
179
178
 
180
179
  const orderAlreadyInBasket = useMemo(
@@ -182,19 +181,12 @@ const TestTypeSearchResultItem: React.FC<TestTypeSearchResultItemProps> = ({
182
181
  [orders, concept],
183
182
  );
184
183
 
185
- const createOrderBasketItem = useCallback(
186
- (testType: OrderableConcept, visit: Visit) => {
187
- return createEmptyOrder(testType, session.currentProvider?.uuid, visit);
188
- },
189
- [session.currentProvider.uuid],
190
- );
191
-
192
184
  const addToBasket = useCallback(() => {
193
- const orderBasketItem = createOrderBasketItem(concept, visit);
185
+ const orderBasketItem = createEmptyOrder(concept, visit);
194
186
  orderBasketItem.isOrderIncomplete = true;
195
187
  setOrders([...orders, orderBasketItem]);
196
188
  closeWorkspace({ discardUnsavedChanges: true });
197
- }, [orders, setOrders, createOrderBasketItem, concept, closeWorkspace, visit]);
189
+ }, [orders, setOrders, concept, closeWorkspace, visit]);
198
190
 
199
191
  const removeFromBasket = useCallback(() => {
200
192
  setOrders(orders.filter((order) => order?.concept?.uuid !== concept?.uuid));
@@ -233,7 +225,7 @@ const TestTypeSearchResultItem: React.FC<TestTypeSearchResultItemProps> = ({
233
225
  <Button
234
226
  kind="ghost"
235
227
  renderIcon={(props: ComponentProps<typeof ArrowRightIcon>) => <ArrowRightIcon size={16} {...props} />}
236
- onClick={() => openOrderForm(createOrderBasketItem(concept, visit))}
228
+ onClick={() => openOrderForm(createEmptyOrder(concept, visit))}
237
229
  >
238
230
  {t('goToDrugOrderForm', 'Order form')}
239
231
  </Button>
@@ -41,6 +41,7 @@ import styles from './general-order-form.scss';
41
41
 
42
42
  export interface OrderFormProps {
43
43
  initialOrder: OrderBasketItem;
44
+ orderToEditOrdererUuid?: string;
44
45
  orderTypeUuid: string;
45
46
  closeWorkspace: Workspace2DefinitionProps['closeWorkspace'];
46
47
  setHasUnsavedChanges: (hasUnsavedChanges: boolean) => void;
@@ -53,6 +54,7 @@ export interface OrderFormProps {
53
54
  export function OrderForm({
54
55
  patient,
55
56
  initialOrder,
57
+ orderToEditOrdererUuid,
56
58
  orderTypeUuid,
57
59
  closeWorkspace,
58
60
  setHasUnsavedChanges,
@@ -117,7 +119,6 @@ export function OrderForm({
117
119
  ...initialOrder,
118
120
  ...data,
119
121
  };
120
- finalizedOrder.orderer = session.currentProvider.uuid;
121
122
 
122
123
  const newOrders = [...orders];
123
124
  const existingOrder = orders.find((order) => ordersEqual(order, finalizedOrder));
@@ -136,7 +137,7 @@ export function OrderForm({
136
137
 
137
138
  closeWorkspace({ discardUnsavedChanges: true });
138
139
  },
139
- [orders, setOrders, session?.currentProvider?.uuid, initialOrder, closeWorkspace],
140
+ [orders, setOrders, initialOrder, closeWorkspace],
140
141
  );
141
142
 
142
143
  const submitDrugOrderToServer = useCallback(
@@ -145,9 +146,8 @@ export function OrderForm({
145
146
  ...initialOrder,
146
147
  ...data,
147
148
  };
148
- finalizedOrder.orderer = session.currentProvider.uuid;
149
149
 
150
- postOrder(prepOrderPostData(finalizedOrder, patient.id, finalizedOrder?.encounterUuid))
150
+ postOrder(prepOrderPostData(finalizedOrder, patient.id, finalizedOrder?.encounterUuid, orderToEditOrdererUuid))
151
151
  .then(() => {
152
152
  clearOrders();
153
153
  mutateOrders();
@@ -167,7 +167,7 @@ export function OrderForm({
167
167
  });
168
168
  });
169
169
  },
170
- [clearOrders, closeWorkspace, initialOrder, mutateOrders, patient.id, session.currentProvider.uuid, t],
170
+ [clearOrders, closeWorkspace, initialOrder, mutateOrders, patient.id, orderToEditOrdererUuid, t],
171
171
  );
172
172
 
173
173
  const cancelOrder = useCallback(() => {
@@ -5,15 +5,16 @@ import {
5
5
  type OrderUrgency,
6
6
  type OrderPost,
7
7
  type OrderableConcept,
8
+ careSettingUuid,
9
+ type PostDataPrepFunction,
8
10
  } from '@openmrs/esm-patient-common-lib';
9
11
 
10
- export function createEmptyOrder(concept: OrderableConcept, orderer: string, visit: Visit): OrderBasketItem {
12
+ export function createEmptyOrder(concept: OrderableConcept, visit: Visit): OrderBasketItem {
11
13
  return {
12
14
  action: 'NEW',
13
15
  urgency: priorityOptions[0].value as OrderUrgency,
14
16
  display: concept.display,
15
17
  concept,
16
- orderer,
17
18
  visit,
18
19
  };
19
20
  }
@@ -22,20 +23,19 @@ export function ordersEqual(order1: OrderBasketItem, order2: OrderBasketItem) {
22
23
  return order1.action === order2.action && order1.concept.uuid === order2.concept.uuid;
23
24
  }
24
25
 
25
- const careSettingUuid = '6f0c9a92-6f24-11e3-af88-005056821db0';
26
-
27
- export function prepOrderPostData(
28
- order: OrderBasketItem,
29
- patientUuid: string,
30
- encounterUuid: string | null,
31
- ): OrderPost {
26
+ export const prepOrderPostData: PostDataPrepFunction = (
27
+ order,
28
+ patientUuid,
29
+ encounterUuid,
30
+ orderingProviderUuid,
31
+ ): OrderPost => {
32
32
  if (order.action === 'NEW' || order.action === 'RENEW') {
33
33
  return {
34
34
  action: 'NEW',
35
35
  type: 'order',
36
36
  patient: patientUuid,
37
37
  careSetting: careSettingUuid,
38
- orderer: order.orderer,
38
+ orderer: orderingProviderUuid,
39
39
  encounter: encounterUuid,
40
40
  concept: order.concept.uuid,
41
41
  instructions: order.instructions,
@@ -49,8 +49,8 @@ export function prepOrderPostData(
49
49
  action: 'REVISE',
50
50
  type: 'order',
51
51
  patient: patientUuid,
52
- careSetting: order.careSetting,
53
- orderer: order.orderer,
52
+ careSetting: careSettingUuid,
53
+ orderer: orderingProviderUuid,
54
54
  encounter: encounterUuid,
55
55
  concept: order?.concept?.uuid,
56
56
  instructions: order.instructions,
@@ -64,8 +64,8 @@ export function prepOrderPostData(
64
64
  action: 'DISCONTINUE',
65
65
  type: 'order',
66
66
  patient: patientUuid,
67
- careSetting: order.careSetting,
68
- orderer: order.orderer,
67
+ careSetting: careSettingUuid,
68
+ orderer: orderingProviderUuid,
69
69
  encounter: encounterUuid,
70
70
  concept: order?.concept?.uuid,
71
71
  previousOrder: order.previousOrder,
@@ -76,4 +76,4 @@ export function prepOrderPostData(
76
76
  } else {
77
77
  throw new Error(`Unknown order action: ${order.action}.`);
78
78
  }
79
- }
79
+ };