@openmrs/esm-patient-common-lib 11.3.1-patch.9508 → 11.3.1-pre.10001

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-patient-common-lib",
3
- "version": "11.3.1-patch.9508",
3
+ "version": "11.3.1-pre.10001",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Library for common patient chart components",
6
6
  "browser": "dist/openmrs-esm-patient-common-lib.js",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@carbon/react": "^1.83.0",
33
- "lodash-es": "^4.17.21",
33
+ "lodash-es": "^4.17.23",
34
34
  "uuid": "^8.3.2"
35
35
  },
36
36
  "peerDependencies": {
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import { render, screen } from '@testing-library/react';
4
- import { launchWorkspace } from '@openmrs/esm-framework';
4
+ import { launchWorkspace2 } from '@openmrs/esm-framework';
5
5
  import { EmptyState } from '.';
6
6
 
7
- const mockLaunchWorkspace = jest.mocked(launchWorkspace);
7
+ const mockLaunchWorkspace = jest.mocked(launchWorkspace2);
8
8
 
9
9
  describe('EmptyState', () => {
10
10
  it('renders an empty state widget card', () => {
@@ -12,7 +12,7 @@ describe('EmptyState', () => {
12
12
  <EmptyState
13
13
  headerTitle="appointments"
14
14
  displayText="appointments"
15
- launchForm={() => launchWorkspace('sample-form-workspace')}
15
+ launchForm={() => launchWorkspace2('sample-form-workspace')}
16
16
  />,
17
17
  );
18
18
 
@@ -28,7 +28,7 @@ describe('EmptyState', () => {
28
28
  <EmptyState
29
29
  headerTitle="appointments"
30
30
  displayText="appointments"
31
- launchForm={() => launchWorkspace('sample-form-workspace')}
31
+ launchForm={() => launchWorkspace2('sample-form-workspace')}
32
32
  />,
33
33
  );
34
34
 
@@ -1,4 +1,4 @@
1
- import { type HtmlFormEntryForm } from '../types';
1
+ import { type Encounter, type Visit, type Workspace2DefinitionProps } from '@openmrs/esm-framework';
2
2
 
3
3
  export interface FormEntryProps {
4
4
  encounterUuid?: string;
@@ -7,6 +7,27 @@ export interface FormEntryProps {
7
7
  visitTypeUuid?: string;
8
8
  visitStartDatetime?: string;
9
9
  visitStopDatetime?: string;
10
- htmlForm?: HtmlFormEntryForm;
11
10
  additionalProps?: Record<string, any>;
12
11
  }
12
+
13
+ /**
14
+ * Workspace control props are made optional to support usage in non-workspace contexts,
15
+ * such as the Fast Data Entry app or other standalone form zones.
16
+ */
17
+ export interface FormRendererProps {
18
+ additionalProps?: Record<string, any>;
19
+ encounterUuid?: string;
20
+ formUuid: string;
21
+ patientUuid: string;
22
+ patient: fhir.Patient;
23
+ visit?: Visit;
24
+ visitUuid?: string;
25
+ hideControls?: boolean;
26
+ hidePatientBanner?: boolean;
27
+ handlePostResponse?: (encounter: Encounter) => void;
28
+ preFilledQuestions?: Record<string, string>;
29
+ launchChildWorkspace?: Workspace2DefinitionProps['launchChildWorkspace'];
30
+ closeWorkspace?: Workspace2DefinitionProps['closeWorkspace'];
31
+ closeWorkspaceWithSavedChanges?: () => void;
32
+ setHasUnsavedChanges?(hasUnsavedChanges: boolean);
33
+ }
package/src/index.ts CHANGED
@@ -3,8 +3,8 @@ export * from './compare';
3
3
  export * from './dashboards/createDashboardLink';
4
4
  export * from './empty-state';
5
5
  export * from './error-state';
6
- export * from './form-entry-interop';
7
6
  export * from './form-entry/form-entry';
7
+ export * from './results';
8
8
  export * from './launchStartVisitPrompt';
9
9
  export * from './offline/visit';
10
10
  export * from './orders';
@@ -1,7 +1,8 @@
1
1
  import { showModal } from '@openmrs/esm-framework';
2
2
 
3
- export function launchStartVisitPrompt() {
3
+ export async function launchStartVisitPrompt(onVisitStarted?: () => void) {
4
4
  const dispose = showModal('start-visit-dialog', {
5
5
  closeModal: () => dispose(),
6
+ onVisitStarted,
6
7
  });
7
8
  }
@@ -1,7 +1,9 @@
1
- export * from './useOrderBasket';
2
1
  export * from './postOrders';
3
- export * from './useOrders';
2
+ export * from './showOrderSuccessToast';
4
3
  export * from './types';
4
+ export * from './useMutatePatientOrders';
5
+ export * from './useOrderBasket';
5
6
  export * from './useOrderableConceptSets';
7
+ export * from './useOrders';
6
8
  export * from './useOrderType';
7
9
  export * from './useOrderTypes';
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  type Concept,
3
+ type Encounter,
3
4
  openmrsFetch,
4
5
  type OpenmrsResource,
5
6
  parseDate,
@@ -7,20 +8,28 @@ import {
7
8
  type Visit,
8
9
  } from '@openmrs/esm-framework';
9
10
  import { type OrderBasketStore, orderBasketStore } from './store';
10
- import type {
11
- DrugOrderPost,
12
- TestOrderPost,
13
- ExtractedOrderErrorObject,
14
- OrderBasketItem,
15
- OrderErrorObject,
16
- OrderPost,
17
- } from './types';
11
+ import type { ExtractedOrderErrorObject, Order, OrderBasketItem, OrderErrorObject, OrderPost } from './types';
12
+
13
+ function getOrdersPayloadFromOrderBasket(patientUuid: string, ordererUuid: string) {
14
+ const { items, postDataPrepFunctions }: OrderBasketStore = orderBasketStore.getState();
15
+ const patientItems = items[patientUuid];
16
+
17
+ const orders: Array<OrderPost> = [];
18
+ Object.entries(patientItems).forEach(([grouping, groupOrders]) => {
19
+ groupOrders.forEach((order) => {
20
+ orders.push(postDataPrepFunctions[grouping](order, patientUuid, null, ordererUuid));
21
+ });
22
+ });
23
+
24
+ return orders;
25
+ }
18
26
 
19
27
  export async function postOrdersOnNewEncounter(
20
28
  patientUuid: string,
21
29
  orderEncounterType: string,
22
30
  currentVisit: Visit | null,
23
- sessionLocationUuid: string,
31
+ orderLocationUuid: string,
32
+ ordererUuid: string,
24
33
  abortController?: AbortController,
25
34
 
26
35
  /**
@@ -29,36 +38,23 @@ export async function postOrdersOnNewEncounter(
29
38
  */
30
39
  encounterDate?: Date,
31
40
  ) {
32
- const now = new Date();
33
- const visitStartDate = parseDate(currentVisit?.startDatetime);
34
- const visitEndDate = parseDate(currentVisit?.stopDatetime);
35
41
  if (!encounterDate) {
36
- if (!currentVisit || (visitStartDate < now && (!visitEndDate || visitEndDate > now))) {
37
- encounterDate = now;
42
+ if (currentVisit?.stopDatetime) {
43
+ encounterDate = parseDate(currentVisit.startDatetime);
38
44
  } else {
39
- console.warn(
40
- 'postOrdersOnNewEncounter received an active visit that is not currently active. This is a programming error. Attempting to place the order using the visit start date.',
41
- );
42
- encounterDate = visitStartDate;
45
+ encounterDate = null;
43
46
  }
44
47
  }
45
48
 
46
- const { items, postDataPrepFunctions }: OrderBasketStore = orderBasketStore.getState();
47
- const patientItems = items[patientUuid];
48
-
49
- const orders: Array<DrugOrderPost | TestOrderPost> = [];
50
-
51
- Object.entries(patientItems).forEach(([grouping, groupOrders]) => {
52
- groupOrders.forEach((order) => {
53
- orders.push(postDataPrepFunctions[grouping](order, patientUuid, null));
54
- });
55
- });
49
+ const orders = getOrdersPayloadFromOrderBasket(patientUuid, ordererUuid);
56
50
 
57
51
  const encounterPostData: EncounterPost = {
58
52
  patient: patientUuid,
59
- location: sessionLocationUuid,
53
+ location: orderLocationUuid,
60
54
  encounterType: orderEncounterType,
61
- encounterDatetime: encounterDate,
55
+ // only specify the encounterDatetime if it's given, otherwise
56
+ // don't specify that let the server default it to `now`
57
+ ...(encounterDate ? { encounterDatetime: encounterDate } : {}),
62
58
  visit: currentVisit?.uuid,
63
59
  obs: [],
64
60
  orders,
@@ -75,53 +71,70 @@ export interface EncounterPost {
75
71
  patient: string;
76
72
  location: string;
77
73
  encounterType: string;
78
- encounterDatetime: Date;
74
+ encounterDatetime?: Date;
79
75
  visit?: string;
80
76
  obs: ObsPayload[];
81
77
  orders: OrderPost[];
82
78
  }
83
79
 
84
80
  export async function postEncounter(encounterPostData: EncounterPost, abortController?: AbortController) {
85
- return openmrsFetch<OpenmrsResource>(`${restBaseUrl}/encounter`, {
81
+ return openmrsFetch<Encounter>(`${restBaseUrl}/encounter`, {
86
82
  headers: {
87
83
  'Content-Type': 'application/json',
88
84
  },
89
85
  method: 'POST',
90
86
  body: encounterPostData,
91
87
  signal: abortController?.signal,
92
- }).then((res) => res?.data?.uuid);
88
+ }).then((res) => res?.data);
93
89
  }
94
90
 
95
- export async function postOrders(patientUuid: string, encounterUuid: string, abortController: AbortController) {
91
+ export async function postOrders(
92
+ patientUuid: string,
93
+ encounterUuid: string,
94
+ abortController: AbortController,
95
+ ordererUuid: string,
96
+ ) {
96
97
  const { items, postDataPrepFunctions }: OrderBasketStore = orderBasketStore.getState();
97
98
  const patientItems = items[patientUuid];
98
99
 
99
100
  const erroredItems: Array<OrderBasketItem> = [];
100
- for (let grouping in patientItems) {
101
+ const postedOrders: Array<Order> = [];
102
+ const promises: Array<Promise<void>> = [];
103
+
104
+ for (const grouping in patientItems) {
101
105
  const orders = patientItems[grouping];
106
+ const dataPrepFn = postDataPrepFunctions[grouping];
107
+
108
+ if (typeof dataPrepFn !== 'function') {
109
+ console.warn(`The postDataPrep function registered for ${grouping} orders is not a function`);
110
+ continue;
111
+ }
112
+
102
113
  for (let i = 0; i < orders.length; i++) {
103
114
  const order = orders[i];
104
- const dataPrepFn = postDataPrepFunctions[grouping];
105
-
106
- if (typeof dataPrepFn !== 'function') {
107
- console.warn(`The postDataPrep function registered for ${grouping} orders is not a function`);
108
- continue;
109
- }
110
-
111
- await postOrder(dataPrepFn(order, patientUuid, encounterUuid), abortController).catch((error) => {
112
- erroredItems.push({
113
- ...order,
114
- orderError: error,
115
- extractedOrderError: extractErrorDetails(error),
115
+
116
+ const promise = postOrder(dataPrepFn(order, patientUuid, encounterUuid, ordererUuid), abortController)
117
+ .then((response) => {
118
+ postedOrders.push(response.data);
119
+ })
120
+ .catch((error) => {
121
+ erroredItems.push({
122
+ ...order,
123
+ orderError: error,
124
+ extractedOrderError: extractErrorDetails(error),
125
+ });
116
126
  });
117
- });
127
+
128
+ promises.push(promise);
118
129
  }
119
130
  }
120
- return erroredItems;
131
+ await Promise.allSettled(promises);
132
+
133
+ return { postedOrders, erroredItems };
121
134
  }
122
135
 
123
- function postOrder(body: OrderPost, abortController?: AbortController) {
124
- return openmrsFetch(`${restBaseUrl}/order`, {
136
+ export function postOrder(body: OrderPost, abortController?: AbortController) {
137
+ return openmrsFetch<Order>(`${restBaseUrl}/order`, {
125
138
  method: 'POST',
126
139
  signal: abortController?.signal,
127
140
  headers: { 'Content-Type': 'application/json' },
@@ -0,0 +1,86 @@
1
+ import { showSnackbar, translateFrom } from '@openmrs/esm-framework';
2
+ import { type OrderBasketItem } from './types';
3
+
4
+ type OrderAction = 'placed' | 'updated' | 'discontinued';
5
+
6
+ function getNotificationTitle(
7
+ moduleName: string,
8
+ placedOrders: OrderBasketItem[],
9
+ updatedOrders: OrderBasketItem[],
10
+ discontinuedOrders: OrderBasketItem[],
11
+ activeActions: OrderAction[],
12
+ ): string {
13
+ if (activeActions.length > 1) {
14
+ return translateFrom(moduleName, 'ordersCompleted', 'Orders completed');
15
+ }
16
+
17
+ const action = activeActions[0];
18
+
19
+ if (action === 'placed') {
20
+ return placedOrders.length === 1
21
+ ? translateFrom(moduleName, 'orderPlaced', 'Order placed')
22
+ : translateFrom(moduleName, 'ordersPlaced', 'Orders placed');
23
+ }
24
+
25
+ if (action === 'updated') {
26
+ return updatedOrders.length === 1
27
+ ? translateFrom(moduleName, 'orderUpdated', 'Order updated')
28
+ : translateFrom(moduleName, 'ordersUpdated', 'Orders updated');
29
+ }
30
+
31
+ // action === 'discontinued'
32
+ return discontinuedOrders.length === 1
33
+ ? translateFrom(moduleName, 'orderDiscontinued', 'Order discontinued')
34
+ : translateFrom(moduleName, 'ordersDiscontinued', 'Orders discontinued');
35
+ }
36
+
37
+ /**
38
+ * Shows a success toast notification for order operations.
39
+ * The notification title dynamically reflects the action(s) taken (placed, updated, discontinued)
40
+ * and whether it's singular or plural.
41
+ *
42
+ * @param moduleName - The module name (e.g., '@openmrs/esm-patient-orders-app') to use for translations
43
+ * @param patientOrderItems - Array of order basket items that were processed
44
+ */
45
+ export function showOrderSuccessToast(moduleName: string, patientOrderItems: OrderBasketItem[]) {
46
+ if (patientOrderItems.length === 0) {
47
+ return;
48
+ }
49
+
50
+ const placedOrders = patientOrderItems.filter((item) => ['NEW', 'RENEW'].includes(item.action));
51
+ const updatedOrders = patientOrderItems.filter((item) => item.action === 'REVISE');
52
+ const discontinuedOrders = patientOrderItems.filter((item) => item.action === 'DISCONTINUE');
53
+
54
+ const orderedString = placedOrders.map((item) => item.display).join(', ');
55
+ const updatedString = updatedOrders.map((item) => item.display).join(', ');
56
+ const discontinuedString = discontinuedOrders.map((item) => item.display).join(', ');
57
+
58
+ const activeActions: OrderAction[] = [
59
+ orderedString && 'placed',
60
+ updatedString && 'updated',
61
+ discontinuedString && 'discontinued',
62
+ ].filter(Boolean) as OrderAction[];
63
+
64
+ const title = getNotificationTitle(moduleName, placedOrders, updatedOrders, discontinuedOrders, activeActions);
65
+
66
+ const subtitleParts: string[] = [];
67
+
68
+ if (orderedString) {
69
+ subtitleParts.push(`${translateFrom(moduleName, 'orderedFor', 'Placed order for')} ${orderedString}.`);
70
+ }
71
+
72
+ if (updatedString) {
73
+ subtitleParts.push(`${translateFrom(moduleName, 'updated', 'Updated')} ${updatedString}.`);
74
+ }
75
+
76
+ if (discontinuedString) {
77
+ subtitleParts.push(`${translateFrom(moduleName, 'discontinued', 'Discontinued')} ${discontinuedString}.`);
78
+ }
79
+
80
+ showSnackbar({
81
+ isLowContrast: true,
82
+ kind: 'success',
83
+ title,
84
+ subtitle: subtitleParts.join(' '),
85
+ });
86
+ }
@@ -1,4 +1,4 @@
1
- import type { OpenmrsResource } from '@openmrs/esm-framework';
1
+ import type { Encounter, OpenmrsResource, Visit, Workspace2DefinitionProps } from '@openmrs/esm-framework';
2
2
 
3
3
  export interface Concept extends OpenmrsResource {
4
4
  name?: {
@@ -47,8 +47,6 @@ export interface OrderBasketItem {
47
47
  action: OrderAction;
48
48
  display: string;
49
49
  uuid?: string;
50
- orderer?: string;
51
- careSetting?: string;
52
50
  orderError?: Error & {
53
51
  responseBody?: {
54
52
  error?: {
@@ -71,6 +69,8 @@ export interface OrderBasketItem {
71
69
  orderType?: string;
72
70
  orderNumber?: string;
73
71
  scheduledDate?: Date;
72
+ encounterUuid?: string;
73
+ visit: Visit;
74
74
  }
75
75
 
76
76
  export type OrderUrgency = 'ROUTINE' | 'STAT' | 'ON_SCHEDULED_DATE';
@@ -116,7 +116,7 @@ export interface DrugOrderPost extends OrderPost {
116
116
  dosingInstructions?: string;
117
117
  }
118
118
 
119
- export interface TestOrderPost extends OrderPost {}
119
+ export type TestOrderPost = OrderPost;
120
120
 
121
121
  export interface PatientOrderFetchResponse {
122
122
  results: Array<Order>;
@@ -127,7 +127,7 @@ export interface Order {
127
127
  action: OrderAction;
128
128
  asNeeded: boolean;
129
129
  asNeededCondition?: string;
130
- autoExpireDate: string;
130
+ autoExpireDate?: string | null;
131
131
  brandName?: string;
132
132
  careSetting: OpenmrsResource;
133
133
  commentToFulfiller: string;
@@ -135,17 +135,17 @@ export interface Order {
135
135
  dateActivated: string;
136
136
  dateStopped?: string | null;
137
137
  dispenseAsWritten: boolean;
138
- dose: number;
139
- doseUnits: OpenmrsResource;
138
+ dose: number | null;
139
+ doseUnits: OpenmrsResource | null;
140
140
  dosingInstructions: string | null;
141
141
  dosingType?: 'org.openmrs.FreeTextDosingInstructions' | 'org.openmrs.SimpleDosingInstructions';
142
- drug: Drug;
143
- duration: number;
144
- durationUnits: OpenmrsResource;
145
- encounter: OpenmrsResource;
146
- frequency: OpenmrsResource;
142
+ drug: Drug | null;
143
+ duration: number | null;
144
+ durationUnits: OpenmrsResource | null;
145
+ encounter: Encounter;
146
+ frequency: OpenmrsResource | null;
147
147
  instructions?: string | null;
148
- numRefills: number;
148
+ numRefills: number | null;
149
149
  orderNumber: string;
150
150
  orderReason: string | null;
151
151
  orderReasonNonCoded: string | null;
@@ -167,9 +167,9 @@ export interface Order {
167
167
  };
168
168
  patient: OpenmrsResource;
169
169
  previousOrder: { uuid: string; type: string; display: string } | null;
170
- quantity: number;
171
- quantityUnits: OpenmrsResource;
172
- route: OpenmrsResource;
170
+ quantity: number | null;
171
+ quantityUnits: OpenmrsResource | null;
172
+ route: OpenmrsResource | null;
173
173
  scheduleDate: null;
174
174
  urgency: OrderUrgency;
175
175
 
@@ -207,16 +207,121 @@ export interface OrderType {
207
207
  description: string;
208
208
  }
209
209
 
210
- export type FulfillerStatus =
211
- | 'RECEIVED'
212
- | 'IN_PROGRESS'
213
- | 'EXCEPTION'
214
- | 'ON_HOLD'
215
- | 'DECLINED'
216
- | 'COMPLETED';
210
+ export type FulfillerStatus = 'RECEIVED' | 'IN_PROGRESS' | 'EXCEPTION' | 'ON_HOLD' | 'DECLINED' | 'COMPLETED';
217
211
 
212
+ /**
213
+ * A function type that converts a OrderBasketItem into
214
+ * a POST order payload
215
+ */
218
216
  export type PostDataPrepFunction = (
219
217
  order: OrderBasketItem,
220
218
  patientUuid: string,
221
219
  encounterUuid: string | null,
220
+ orderingProviderUuid: string,
222
221
  ) => OrderPost;
222
+
223
+ export interface OrderBasketExtensionProps {
224
+ patient: fhir.Patient;
225
+ launchDrugOrderForm(order?: DrugOrderBasketItem): void;
226
+ launchLabOrderForm(orderTypeUuid: string, order?: TestOrderBasketItem): void;
227
+ launchGeneralOrderForm(orderTypeUuid: string, order?: OrderBasketItem): void;
228
+ }
229
+
230
+ export interface DrugOrderBasketItem extends OrderBasketItem {
231
+ drug: Drug;
232
+ unit: DosingUnit | null;
233
+ commonMedicationName: string;
234
+ dosage: number | null;
235
+ frequency: MedicationFrequency | null;
236
+ route: MedicationRoute | null;
237
+ quantityUnits: QuantityUnit | null;
238
+ patientInstructions: string | null;
239
+ asNeeded: boolean;
240
+ asNeededCondition: string | null;
241
+ startDate: Date | string;
242
+ durationUnit: DurationUnit | null;
243
+ duration: number | null;
244
+ pillsDispensed: number | null;
245
+ numRefills: number | null;
246
+ indication: string | null;
247
+ isFreeTextDosage: boolean;
248
+ freeTextDosage: string;
249
+ previousOrder?: string;
250
+ template?: OrderTemplate;
251
+ }
252
+
253
+ export interface DrugOrderTemplate {
254
+ uuid: string;
255
+ name: string;
256
+ drug: Drug;
257
+ template: OrderTemplate;
258
+ }
259
+
260
+ export interface OrderTemplate {
261
+ type: string;
262
+ dosingType: string;
263
+ dosingInstructions: DosingInstructions;
264
+ }
265
+
266
+ export interface DosingInstructions {
267
+ dose: Array<MedicationDosage>;
268
+ units: Array<DosingUnit>;
269
+ route: Array<MedicationRoute>;
270
+ frequency: Array<MedicationFrequency>;
271
+ instructions?: Array<MedicationInstructions>;
272
+ durationUnits?: Array<DurationUnit>;
273
+ quantityUnits?: Array<QuantityUnit>;
274
+ asNeeded?: boolean;
275
+ asNeededCondition?: string;
276
+ }
277
+
278
+ export interface MedicationDosage extends Omit<CommonMedicationProps, 'value'> {
279
+ value: number;
280
+ }
281
+
282
+ export type MedicationFrequency = CommonMedicationValueCoded;
283
+
284
+ export type MedicationRoute = CommonMedicationValueCoded;
285
+
286
+ export type MedicationInstructions = CommonMedicationProps;
287
+
288
+ export type DosingUnit = CommonMedicationValueCoded;
289
+
290
+ export type QuantityUnit = CommonMedicationValueCoded;
291
+
292
+ export type DurationUnit = CommonMedicationValueCoded;
293
+
294
+ interface CommonMedicationProps {
295
+ value: string;
296
+ default?: boolean;
297
+ }
298
+
299
+ export interface CommonMedicationValueCoded extends CommonMedicationProps {
300
+ valueCoded: string;
301
+ names?: string[];
302
+ }
303
+ export interface TestOrderBasketItem extends OrderBasketItem {
304
+ testType: {
305
+ label: string;
306
+ conceptUuid: string;
307
+ };
308
+ orderReason?: string;
309
+ specimenSource?: string;
310
+ }
311
+
312
+ export interface OrderBasketWindowProps {
313
+ encounterUuid: string;
314
+ onOrderBasketSubmitted?: (encounterUuid: string, postedOrders: Array<Order>) => void;
315
+ }
316
+
317
+ export interface ExportedOrderBasketWindowProps {
318
+ encounterUuid: string;
319
+ drugOrderWorkspaceName: string;
320
+ labOrderWorkspaceName: string;
321
+ generalOrderWorkspaceName: string;
322
+ patient: fhir.Patient;
323
+ patientUuid: string;
324
+ visitContext: Visit;
325
+ mutateVisitContext: () => void;
326
+ onOrderBasketSubmitted?: (encounterUuid: string, postedOrders: Array<Order>) => void;
327
+ }
@@ -0,0 +1,28 @@
1
+ import { useCallback } from 'react';
2
+ import { useSWRConfig } from 'swr';
3
+ import { restBaseUrl } from '@openmrs/esm-framework';
4
+
5
+ /**
6
+ * Returns a function which refreshes the patient orders cache. Uses SWR's mutate function.
7
+ * Refreshes patient orders for all kinds of orders.
8
+ *
9
+ * @param patientUuid The UUID of the patient to get an order mutate function for.
10
+ */
11
+ export function useMutatePatientOrders(patientUuid: string) {
12
+ const { mutate } = useSWRConfig();
13
+ const mutateOrders = useCallback(
14
+ () =>
15
+ mutate(
16
+ (key) => {
17
+ return typeof key === 'string' && key.startsWith(`${restBaseUrl}/order?patient=${patientUuid}`);
18
+ },
19
+ undefined,
20
+ { revalidate: true },
21
+ ),
22
+ [patientUuid, mutate],
23
+ );
24
+
25
+ return {
26
+ mutate: mutateOrders,
27
+ };
28
+ }
@@ -1,7 +1,7 @@
1
- import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
1
+ import { useMemo } from 'react';
2
2
  import useSWRImmutable from 'swr/immutable';
3
+ import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
3
4
  import type { OrderTypeFetchResponse } from './types';
4
- import { useMemo } from 'react';
5
5
 
6
6
  export function useOrderTypes() {
7
7
  const orderTypesUrl = `${restBaseUrl}/ordertype`;
@@ -60,7 +60,7 @@ function useOrderableConceptSWR(searchTerm: string, orderableConceptSets?: Array
60
60
  };
61
61
  }
62
62
 
63
- export interface OrderableConcept extends OpenmrsResource {}
63
+ export type OrderableConcept = OpenmrsResource;
64
64
 
65
65
  export function useOrderableConceptSets(searchTerm: string, orderableConcepts: Array<string>) {
66
66
  const { data, isLoading, error } = useOrderableConceptSWR(