@ampath/esm-dispensing-app 1.10.0-next.2 → 1.10.0-next.21

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 (51) hide show
  1. package/dist/3568.js +1 -1
  2. package/dist/3568.js.map +1 -1
  3. package/dist/3693.js +1 -0
  4. package/dist/3693.js.map +1 -0
  5. package/dist/{7252.js → 4099.js} +1 -1
  6. package/dist/{7252.js.map → 4099.js.map} +1 -1
  7. package/dist/4300.js +1 -1
  8. package/dist/6841.js +1 -1
  9. package/dist/6841.js.map +1 -1
  10. package/dist/963.js +1 -1
  11. package/dist/963.js.map +1 -1
  12. package/dist/9764.js +1 -0
  13. package/dist/9764.js.map +1 -0
  14. package/dist/main.js +1 -1
  15. package/dist/main.js.map +1 -1
  16. package/dist/openmrs-esm-dispensing-app.js +1 -1
  17. package/dist/openmrs-esm-dispensing-app.js.buildmanifest.json +87 -87
  18. package/dist/routes.json +1 -1
  19. package/package.json +2 -1
  20. package/src/bill/bill.resource.ts +89 -0
  21. package/src/components/action-buttons.component.tsx +97 -5
  22. package/src/components/action-buttons.test.tsx +22 -2
  23. package/src/components/prescription-actions/close-action-button.component.tsx +3 -0
  24. package/src/components/prescription-actions/dispense-action-button.component.tsx +17 -4
  25. package/src/components/prescription-actions/generate-bill-action-button.component.tsx +53 -0
  26. package/src/components/prescription-actions/pause-action-button.component.tsx +3 -0
  27. package/src/config-schema.ts +36 -0
  28. package/src/forms/close-dispense-form.workspace.tsx +13 -1
  29. package/src/forms/pause-dispense-form.workspace.tsx +13 -1
  30. package/src/index.ts +3 -1
  31. package/src/location/location.resource.test.tsx +46 -8
  32. package/src/location/location.resource.tsx +7 -4
  33. package/src/medication-request/medication-request.resource.test.tsx +2 -6
  34. package/src/medication-request/medication-request.resource.tsx +97 -11
  35. package/src/prescriptions/prescription-details.component.tsx +59 -18
  36. package/src/prescriptions/prescription-details.test.tsx +70 -1
  37. package/src/prescriptions/prescription-tab-panel.component.tsx +23 -2
  38. package/src/prescriptions/prescriptions-table.component.tsx +53 -23
  39. package/src/prescriptions/priority-tag.component.tsx +44 -0
  40. package/src/prescriptions/priority-tag.scss +12 -0
  41. package/src/print-prescription/prescription-printout.component.tsx +10 -3
  42. package/src/routes.json +5 -0
  43. package/src/types.ts +53 -1
  44. package/src/utils.test.ts +9 -9
  45. package/src/utils.ts +36 -2
  46. package/src/visit/visit.resource.ts +1 -1
  47. package/translations/en.json +5 -0
  48. package/dist/609.js +0 -1
  49. package/dist/609.js.map +0 -1
  50. package/dist/8885.js +0 -1
  51. package/dist/8885.js.map +0 -1
@@ -1,7 +1,15 @@
1
- import { useMemo } from 'react';
1
+ import { useEffect, useMemo, useState } from 'react';
2
2
  import dayjs from 'dayjs';
3
3
  import useSWR from 'swr';
4
- import { fhirBaseUrl, openmrsFetch, parseDate } from '@openmrs/esm-framework';
4
+ import {
5
+ fhirBaseUrl,
6
+ openmrsFetch,
7
+ type Order,
8
+ parseDate,
9
+ restBaseUrl,
10
+ useConfig,
11
+ useSession,
12
+ } from '@openmrs/esm-framework';
5
13
  import { JSON_MERGE_PATH_MIME_TYPE, OPENMRS_FHIR_EXT_REQUEST_FULFILLER_STATUS } from '../constants';
6
14
  import {
7
15
  type AllergyIntoleranceResponse,
@@ -14,6 +22,7 @@ import {
14
22
  type MedicationRequestFulfillerStatus,
15
23
  type MedicationRequestBundle,
16
24
  type SimpleLocation,
25
+ type QueueEntryResult,
17
26
  } from '../types';
18
27
  import {
19
28
  getPrescriptionDetailsEndpoint,
@@ -23,7 +32,11 @@ import {
23
32
  sortMedicationDispensesByWhenHandedOver,
24
33
  computePrescriptionStatusMessageCode,
25
34
  getAssociatedMedicationDispenses,
35
+ getEtlBaseUrl,
26
36
  } from '../utils';
37
+ import { type PharmacyConfig } from '../config-schema';
38
+
39
+ const ACTIVE_STATUS_FETCH_COUNT = 100;
27
40
 
28
41
  export function usePrescriptionsTable(
29
42
  loadData: boolean,
@@ -36,14 +49,16 @@ export function usePrescriptionsTable(
36
49
  medicationRequestExpirationPeriodInDays: number,
37
50
  refreshInterval: number,
38
51
  ) {
52
+ const fetchPageSize = status === 'ACTIVE' ? ACTIVE_STATUS_FETCH_COUNT : pageSize;
53
+ const fetchPageOffset = status === 'ACTIVE' ? 0 : pageOffset;
39
54
  const { data, error } = useSWR<{ data: EncounterResponse }, Error>(
40
55
  loadData
41
56
  ? getPrescriptionTableEndpoint(
42
57
  customPrescriptionsTableEndpoint,
43
58
  status,
44
- pageOffset,
45
- pageSize,
46
- dayjs(new Date()).startOf('day').subtract(medicationRequestExpirationPeriodInDays, 'day').toISOString(),
59
+ fetchPageOffset,
60
+ fetchPageSize,
61
+ '',
47
62
  patientSearchTerm,
48
63
  locations?.map((location) => location.id).join(','),
49
64
  )
@@ -51,18 +66,28 @@ export function usePrescriptionsTable(
51
66
  openmrsFetch,
52
67
  { refreshInterval: refreshInterval },
53
68
  );
69
+ const { queueEntries } = useQueueEntries();
54
70
 
55
71
  let prescriptionsTableRows: PrescriptionsTableRow[];
56
72
  if (data) {
57
73
  const entries = data?.data.entry;
58
- if (entries) {
59
- const encounters = entries
74
+ const filteredEntries =
75
+ status === 'ACTIVE' && entries
76
+ ? entries.filter((entry) =>
77
+ dayjs(entry?.resource?.meta?.lastUpdated).isAfter(
78
+ dayjs().startOf('day').subtract(medicationRequestExpirationPeriodInDays, 'day'),
79
+ ),
80
+ )
81
+ : entries;
82
+
83
+ if (filteredEntries) {
84
+ const encounters = filteredEntries
60
85
  .filter((entry) => entry?.resource?.resourceType == 'Encounter')
61
86
  .map((entry) => entry.resource as Encounter);
62
- const medicationRequests = entries
87
+ const medicationRequests = filteredEntries
63
88
  .filter((entry) => entry?.resource?.resourceType == 'MedicationRequest')
64
89
  .map((entry) => entry.resource as MedicationRequest);
65
- const medicationDispenses = entries
90
+ const medicationDispenses = filteredEntries
66
91
  .filter((entry) => entry?.resource?.resourceType == 'MedicationDispense')
67
92
  .map((entry) => entry.resource as MedicationDispense)
68
93
  .sort(sortMedicationDispensesByWhenHandedOver);
@@ -77,11 +102,16 @@ export function usePrescriptionsTable(
77
102
  const medicationDispensesForMedicationRequests = medicationDispenses.filter((medicationDispense) =>
78
103
  medicationRequestReferences.includes(medicationDispense.authorizingPrescription[0]?.reference),
79
104
  );
105
+
106
+ const patientUuid = encounter?.subject?.reference?.split('/')[1];
107
+ const priority = queueEntries?.find((q) => q.patient_uuid === patientUuid)?.priority ?? 'NON-URGENT';
108
+
80
109
  return buildPrescriptionsTableRow(
81
110
  encounter,
82
111
  medicationRequestsForEncounter,
83
112
  medicationDispensesForMedicationRequests,
84
113
  medicationRequestExpirationPeriodInDays,
114
+ priority,
85
115
  );
86
116
  });
87
117
  prescriptionsTableRows.sort((a, b) => (a.created < b.created ? 1 : -1));
@@ -94,7 +124,7 @@ export function usePrescriptionsTable(
94
124
  prescriptionsTableRows,
95
125
  error: error,
96
126
  isLoading: !prescriptionsTableRows && !error,
97
- totalOrders: data?.data.total,
127
+ totalOrders: status === 'ACTIVE' ? prescriptionsTableRows?.length ?? 0 : data?.data.total,
98
128
  };
99
129
  }
100
130
 
@@ -103,10 +133,11 @@ function buildPrescriptionsTableRow(
103
133
  medicationRequests: Array<MedicationRequest>,
104
134
  medicationDispense: Array<MedicationDispense>,
105
135
  medicationRequestExpirationPeriodInDays: number,
136
+ priority: string,
106
137
  ): PrescriptionsTableRow {
107
138
  return {
108
139
  id: encounter?.id,
109
- created: encounter?.period?.start,
140
+ created: encounter?.meta?.lastUpdated, //encounter?.period?.start,
110
141
  patient: {
111
142
  name: encounter?.subject?.display,
112
143
  uuid: encounter?.subject?.reference?.split('/')[1],
@@ -125,6 +156,7 @@ function buildPrescriptionsTableRow(
125
156
  prescriber: [...new Set(medicationRequests.map((o) => o.requester.display))].join(', '),
126
157
  status: computePrescriptionStatusMessageCode(medicationRequests, medicationRequestExpirationPeriodInDays),
127
158
  location: encounter?.location ? encounter?.location[0]?.location.display : null,
159
+ priority: priority,
128
160
  };
129
161
  }
130
162
 
@@ -255,3 +287,57 @@ export function updateMedicationRequestFulfillerStatus(
255
287
  },
256
288
  });
257
289
  }
290
+
291
+ export function useOrders(encounterUuid: string) {
292
+ // const customRepresentation = `custom:(uuid,display,orders:(uuid,orderNumber,concept:(uuid,display)))`;
293
+ const customRepresentation = `full`;
294
+ const url = `${restBaseUrl}/encounter/${encounterUuid}?v=${customRepresentation}`;
295
+ const { data, error, mutate, isLoading, isValidating } = useSWR<{
296
+ data: {
297
+ orders: Array<Order>;
298
+ };
299
+ }>(`${url}`, openmrsFetch);
300
+
301
+ const orders = data?.data?.orders;
302
+
303
+ return {
304
+ orders: orders ?? [],
305
+ isLoading,
306
+ isError: error,
307
+ mutate,
308
+ isValidating,
309
+ };
310
+ }
311
+
312
+ export function useQueueEntries(patientUuid: string = '') {
313
+ const [etlBaseUrl, setEtlBaseUrl] = useState('');
314
+ const { sessionLocation } = useSession();
315
+ const { serviceUuid } = useConfig<PharmacyConfig>();
316
+
317
+ useEffect(() => {
318
+ const fetchEtlBaseUrl = async () => {
319
+ const baseUrl = await getEtlBaseUrl();
320
+ setEtlBaseUrl(baseUrl);
321
+ };
322
+ fetchEtlBaseUrl();
323
+ }, []);
324
+
325
+ const url = `${etlBaseUrl}/queue-entry?locationUuid=${sessionLocation?.uuid}&serviceUuid=${serviceUuid}`;
326
+ const { data, error, mutate, isLoading, isValidating } = useSWR<{
327
+ data: { data: Array<QueueEntryResult> };
328
+ }>(etlBaseUrl ? `${url}` : null, openmrsFetch);
329
+
330
+ let filteredQueueEntries = data?.data?.data;
331
+
332
+ if (patientUuid) {
333
+ filteredQueueEntries = filteredQueueEntries?.filter((queueEntry) => queueEntry.patient_uuid === patientUuid);
334
+ }
335
+
336
+ return {
337
+ queueEntries: filteredQueueEntries ?? [],
338
+ isLoading,
339
+ isError: error,
340
+ mutate,
341
+ isValidating,
342
+ };
343
+ }
@@ -1,17 +1,27 @@
1
- import React from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import { SkeletonText, Tag, Tile } from '@carbon/react';
3
3
  import { WarningFilled } from '@carbon/react/icons';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { type PatientUuid, useConfig, UserHasAccess } from '@openmrs/esm-framework';
6
6
  import { computeMedicationRequestCombinedStatus, getConceptCodingDisplay, useStaleEncounterUuids } from '../utils';
7
7
  import { PRIVILEGE_CREATE_DISPENSE } from '../constants';
8
- import { type AllergyIntolerance, type MedicationRequest, MedicationRequestCombinedStatus } from '../types';
8
+ import {
9
+ type AllergyIntolerance,
10
+ type MedicationRequest,
11
+ MedicationRequestCombinedStatus,
12
+ MedicationRequestStatus,
13
+ } from '../types';
9
14
  import { type PharmacyConfig } from '../config-schema';
10
- import { usePatientAllergies, usePrescriptionDetails } from '../medication-request/medication-request.resource';
15
+ import {
16
+ useOrders,
17
+ usePatientAllergies,
18
+ usePrescriptionDetails,
19
+ } from '../medication-request/medication-request.resource';
11
20
  import ActionButtons from '../components/action-buttons.component';
12
21
  import MedicationEvent from '../components/medication-event.component';
13
22
  import PrescriptionsActionsFooter from './prescription-actions.component';
14
23
  import styles from './prescription-details.scss';
24
+ import { useBills, useInvalidateBills } from '../bill/bill.resource';
15
25
 
16
26
  const PrescriptionDetails: React.FC<{
17
27
  encounterUuid: string;
@@ -27,6 +37,21 @@ const PrescriptionDetails: React.FC<{
27
37
  } = usePatientAllergies(patientUuid, config.refreshInterval);
28
38
  const { medicationRequestBundles, error, isLoading } = usePrescriptionDetails(encounterUuid, config.refreshInterval);
29
39
  const { staleEncounterUuids } = useStaleEncounterUuids();
40
+ const { orders, isLoading: isLoadingOrders } = useOrders(encounterUuid);
41
+ const { bills, isLoading: loadingBills } = useBills(patientUuid);
42
+ const hasActiveRequests = useMemo(() => {
43
+ return medicationRequestBundles.some(
44
+ (bundle) =>
45
+ computeMedicationRequestCombinedStatus(bundle.request, config.medicationRequestExpirationPeriodInDays) ===
46
+ MedicationRequestCombinedStatus.active,
47
+ );
48
+ }, [medicationRequestBundles, config]);
49
+
50
+ const invalidateBills = useInvalidateBills(patientUuid);
51
+
52
+ const mutated = () => {
53
+ invalidateBills();
54
+ };
30
55
 
31
56
  const generateStatusTag = (medicationRequest: MedicationRequest): React.ReactNode => {
32
57
  const combinedStatus: MedicationRequestCombinedStatus = computeMedicationRequestCombinedStatus(
@@ -124,21 +149,37 @@ const PrescriptionDetails: React.FC<{
124
149
  )}
125
150
  {medicationRequestBundles &&
126
151
  (medicationRequestBundles.length > 0 ? (
127
- medicationRequestBundles.map((bundle) => (
128
- <MedicationEvent
129
- key={bundle.request.id}
130
- medicationEvent={bundle.request}
131
- status={generateStatusTag(bundle.request)}>
132
- <UserHasAccess privilege={PRIVILEGE_CREATE_DISPENSE}>
133
- <ActionButtons
134
- patientUuid={patientUuid}
135
- encounterUuid={encounterUuid}
136
- medicationRequestBundle={bundle}
137
- disabled={staleEncounterUuids.includes(encounterUuid)}
138
- />
139
- </UserHasAccess>
140
- </MedicationEvent>
141
- ))
152
+ medicationRequestBundles.map((bundle) => {
153
+ const medicationEvent =
154
+ bundle.request.status === MedicationRequestStatus.completed
155
+ ? bundle.dispenses.find(
156
+ (b) =>
157
+ b.quantity.code === bundle.request.dispenseRequest.quantity.code ||
158
+ b.medicationReference.reference === bundle.request.medicationReference.reference,
159
+ )
160
+ : bundle.request;
161
+ return (
162
+ <MedicationEvent
163
+ key={bundle.request.id}
164
+ medicationEvent={medicationEvent}
165
+ status={generateStatusTag(bundle.request)}>
166
+ <UserHasAccess privilege={PRIVILEGE_CREATE_DISPENSE}>
167
+ <ActionButtons
168
+ patientUuid={patientUuid}
169
+ encounterUuid={encounterUuid}
170
+ medicationRequestBundle={bundle}
171
+ disabled={staleEncounterUuids.includes(encounterUuid)}
172
+ orders={orders}
173
+ bills={bills}
174
+ isLoading={loadingBills}
175
+ isLoadingOrders={isLoadingOrders}
176
+ hasActiveRequests={hasActiveRequests}
177
+ mutated={mutated}
178
+ />
179
+ </UserHasAccess>
180
+ </MedicationEvent>
181
+ );
182
+ })
142
183
  ) : (
143
184
  <p className={styles.emptyState}>{t('noPrescriptionsFound', 'No prescriptions found')}</p>
144
185
  ))}
@@ -1,7 +1,11 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
3
  import { useConfig } from '@openmrs/esm-framework';
4
- import { usePrescriptionDetails, usePatientAllergies } from '../medication-request/medication-request.resource';
4
+ import {
5
+ usePrescriptionDetails,
6
+ usePatientAllergies,
7
+ useOrders,
8
+ } from '../medication-request/medication-request.resource';
5
9
  import { useStaleEncounterUuids } from '../utils';
6
10
  import PrescriptionDetails from './prescription-details.component';
7
11
 
@@ -15,6 +19,7 @@ const mockUseConfig = jest.mocked(useConfig);
15
19
  const mockUsePrescriptionDetails = jest.mocked(usePrescriptionDetails);
16
20
  const mockUsePatientAllergies = jest.mocked(usePatientAllergies);
17
21
  const mockUseStaleEncounterUuids = jest.mocked(useStaleEncounterUuids);
22
+ const mockUseOrders = jest.mocked(useOrders);
18
23
 
19
24
  const mockEncounterUuid = 'test-encounter-uuid';
20
25
  const mockPatientUuid = 'test-patient-uuid';
@@ -51,6 +56,14 @@ describe('PrescriptionDetails', () => {
51
56
  isValidating: false,
52
57
  });
53
58
 
59
+ mockUseOrders.mockReturnValue({
60
+ orders: [],
61
+ isLoading: false,
62
+ isValidating: false,
63
+ isError: undefined,
64
+ mutate: jest.fn(),
65
+ });
66
+
54
67
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
55
68
 
56
69
  // While loading allergies, should not show allergy details or no allergies message
@@ -73,6 +86,13 @@ describe('PrescriptionDetails', () => {
73
86
  mutate: jest.fn(),
74
87
  isValidating: false,
75
88
  });
89
+ mockUseOrders.mockReturnValue({
90
+ orders: [],
91
+ isLoading: false,
92
+ isValidating: false,
93
+ isError: undefined,
94
+ mutate: jest.fn(),
95
+ });
76
96
 
77
97
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
78
98
 
@@ -94,6 +114,13 @@ describe('PrescriptionDetails', () => {
94
114
  mutate: jest.fn(),
95
115
  isValidating: false,
96
116
  });
117
+ mockUseOrders.mockReturnValue({
118
+ orders: [],
119
+ isLoading: false,
120
+ isValidating: false,
121
+ isError: undefined,
122
+ mutate: jest.fn(),
123
+ });
97
124
 
98
125
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
99
126
 
@@ -130,6 +157,13 @@ describe('PrescriptionDetails', () => {
130
157
  mutate: jest.fn(),
131
158
  isValidating: false,
132
159
  });
160
+ mockUseOrders.mockReturnValue({
161
+ orders: [],
162
+ isLoading: false,
163
+ isValidating: false,
164
+ isError: undefined,
165
+ mutate: jest.fn(),
166
+ });
133
167
 
134
168
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
135
169
 
@@ -164,6 +198,13 @@ describe('PrescriptionDetails', () => {
164
198
  mutate: jest.fn(),
165
199
  isValidating: false,
166
200
  });
201
+ mockUseOrders.mockReturnValue({
202
+ orders: [],
203
+ isLoading: false,
204
+ isValidating: false,
205
+ isError: undefined,
206
+ mutate: jest.fn(),
207
+ });
167
208
 
168
209
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
169
210
 
@@ -193,6 +234,13 @@ describe('PrescriptionDetails', () => {
193
234
  mutate: jest.fn(),
194
235
  isValidating: false,
195
236
  });
237
+ mockUseOrders.mockReturnValue({
238
+ orders: [],
239
+ isLoading: false,
240
+ isValidating: false,
241
+ isError: undefined,
242
+ mutate: jest.fn(),
243
+ });
196
244
 
197
245
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
198
246
 
@@ -216,6 +264,13 @@ describe('PrescriptionDetails', () => {
216
264
  mutate: jest.fn(),
217
265
  isValidating: false,
218
266
  });
267
+ mockUseOrders.mockReturnValue({
268
+ orders: [],
269
+ isLoading: false,
270
+ isValidating: false,
271
+ isError: undefined,
272
+ mutate: jest.fn(),
273
+ });
219
274
 
220
275
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
221
276
 
@@ -237,6 +292,13 @@ describe('PrescriptionDetails', () => {
237
292
  mutate: jest.fn(),
238
293
  isValidating: false,
239
294
  });
295
+ mockUseOrders.mockReturnValue({
296
+ orders: [],
297
+ isLoading: false,
298
+ isValidating: false,
299
+ isError: undefined,
300
+ mutate: jest.fn(),
301
+ });
240
302
 
241
303
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
242
304
 
@@ -258,6 +320,13 @@ describe('PrescriptionDetails', () => {
258
320
  mutate: jest.fn(),
259
321
  isValidating: false,
260
322
  });
323
+ mockUseOrders.mockReturnValue({
324
+ orders: [],
325
+ isLoading: false,
326
+ isValidating: false,
327
+ isError: undefined,
328
+ mutate: jest.fn(),
329
+ });
261
330
 
262
331
  render(<PrescriptionDetails encounterUuid={mockEncounterUuid} patientUuid={mockPatientUuid} />);
263
332
 
@@ -31,10 +31,31 @@ const PrescriptionTabPanel: React.FC<PrescriptionTabPanelProps> = ({
31
31
  // set any initially selected locations
32
32
  useEffect(() => {
33
33
  if (!isInitialized.current && !isFilterLocationsLoading && sessionLocation?.uuid) {
34
- setFilterLocations(locations?.filter((l) => sessionLocation?.uuid === l.associatedPharmacyLocation) || []);
34
+ const initialLocations: SimpleLocation[] = [];
35
+ // Should display from the location associated with the pharmacy location
36
+ initialLocations.push(
37
+ ...(locations?.filter((l) => l.associatedPharmacyLocations?.includes(sessionLocation?.uuid)) || []),
38
+ );
39
+
40
+ // Should display from all the associated pharmacy locations of the current location
41
+ if (config.locationBehavior.locationFilter.useAssociatedPharmacyLocations) {
42
+ initialLocations.push(
43
+ ...(locations?.filter((v) =>
44
+ locations?.find((l) => l.id === sessionLocation?.uuid).associatedPharmacyLocations?.includes(v.id),
45
+ ) || []),
46
+ );
47
+ }
48
+
49
+ // Should display from current location
50
+ if (config.locationBehavior.locationFilter.useCurrentLocation) {
51
+ initialLocations.push(...(locations?.filter((l) => l.id === sessionLocation?.uuid) || []));
52
+ }
53
+
54
+ setFilterLocations(initialLocations || []);
55
+
35
56
  isInitialized.current = true; // we only want to run when the component is first mounted so we don't override user changes
36
57
  }
37
- }, [isFilterLocationsLoading, sessionLocation, locations]);
58
+ }, [isFilterLocationsLoading, sessionLocation, locations, config]);
38
59
 
39
60
  return (
40
61
  <TabPanel>
@@ -17,13 +17,14 @@ import {
17
17
  Tile,
18
18
  } from '@carbon/react';
19
19
  import { useTranslation } from 'react-i18next';
20
- import { formatDatetime, parseDate, useConfig } from '@openmrs/esm-framework';
20
+ import { formatDatetime, parseDate, useConfig, usePagination } from '@openmrs/esm-framework';
21
21
  import { usePrescriptionsTable } from '../medication-request/medication-request.resource';
22
22
  import { type PharmacyConfig } from '../config-schema';
23
23
  import { type SimpleLocation } from '../types';
24
24
  import PatientInfoCell from '../patient/patient-info-cell.component';
25
25
  import PrescriptionExpanded from './prescription-expanded.component';
26
26
  import styles from './prescriptions.scss';
27
+ import PriorityTag from './priority-tag.component';
27
28
 
28
29
  interface PrescriptionsTableProps {
29
30
  loadData: boolean;
@@ -57,10 +58,20 @@ const PrescriptionsTable: React.FC<PrescriptionsTableProps> = ({
57
58
  config.refreshInterval,
58
59
  );
59
60
 
61
+ const isActiveClientPaged = status === 'ACTIVE';
62
+ const { results: paginatedRows, currentPage, goTo } = usePagination(prescriptionsTableRows ?? [], pageSize);
63
+ const rowsToDisplay = isActiveClientPaged ? paginatedRows : prescriptionsTableRows;
64
+ const paginationPage = isActiveClientPaged ? currentPage : page;
65
+ const paginationTotalItems = isActiveClientPaged ? prescriptionsTableRows?.length ?? 0 : totalOrders;
66
+
60
67
  // reset back to page 1 whenever search term changes
61
68
  useEffect(() => {
62
- setPage(1);
63
- }, [debouncedSearchTerm]);
69
+ if (isActiveClientPaged) {
70
+ goTo(1);
71
+ } else {
72
+ setPage(1);
73
+ }
74
+ }, [debouncedSearchTerm, isActiveClientPaged, goTo]);
64
75
 
65
76
  // dynamic status keys we need to maintain
66
77
  // t('active', 'Active')
@@ -76,6 +87,7 @@ const PrescriptionsTable: React.FC<PrescriptionsTableProps> = ({
76
87
  { header: t('prescriber', 'Prescriber'), key: 'prescriber' },
77
88
  { header: t('drugs', 'Drugs'), key: 'drugs' },
78
89
  { header: t('lastDispenser', 'Last dispenser'), key: 'lastDispenser' },
90
+ { header: t('priority', 'Priority'), key: 'priority' },
79
91
  { header: t('status', 'Status'), key: 'status' },
80
92
  ];
81
93
 
@@ -101,7 +113,7 @@ const PrescriptionsTable: React.FC<PrescriptionsTableProps> = ({
101
113
  )}
102
114
  {prescriptionsTableRows && (
103
115
  <>
104
- <DataTable rows={prescriptionsTableRows} headers={columns} isSortable>
116
+ <DataTable rows={rowsToDisplay} headers={columns} isSortable>
105
117
  {({ rows, headers, getExpandHeaderProps, getHeaderProps, getRowProps, getTableProps }) => (
106
118
  <TableContainer>
107
119
  <Table {...getTableProps()} useZebraStyles>
@@ -117,19 +129,28 @@ const PrescriptionsTable: React.FC<PrescriptionsTableProps> = ({
117
129
  {rows.map((row) => (
118
130
  <React.Fragment key={row.id}>
119
131
  <TableExpandRow {...getRowProps({ row })}>
120
- {row.cells.map((cell) => (
121
- <TableCell key={cell.id}>
122
- {cell.id.endsWith('created') ? (
123
- formatDatetime(parseDate(cell.value))
124
- ) : cell.id.endsWith('patient') ? (
125
- <PatientInfoCell patient={cell.value} />
126
- ) : cell.id.endsWith('status') ? (
127
- t(cell.value)
128
- ) : (
129
- cell.value
130
- )}
131
- </TableCell>
132
- ))}
132
+ {row.cells.map((cell) => {
133
+ if (cell.info.header === 'priority') {
134
+ return (
135
+ <TableCell key={cell.id}>
136
+ <PriorityTag status={cell.value?.content ?? cell.value} />
137
+ </TableCell>
138
+ );
139
+ }
140
+ return (
141
+ <TableCell key={cell.id}>
142
+ {cell.id.endsWith('created') ? (
143
+ formatDatetime(parseDate(cell.value))
144
+ ) : cell.id.endsWith('patient') ? (
145
+ <PatientInfoCell patient={cell.value} />
146
+ ) : cell.id.endsWith('status') ? (
147
+ t(cell.value)
148
+ ) : (
149
+ cell.value
150
+ )}
151
+ </TableCell>
152
+ );
153
+ })}
133
154
  </TableExpandRow>
134
155
  {row.isExpanded ? (
135
156
  <TableExpandedRow colSpan={headers.length + 1}>
@@ -165,17 +186,26 @@ const PrescriptionsTable: React.FC<PrescriptionsTableProps> = ({
165
186
  {prescriptionsTableRows?.length > 0 && (
166
187
  <div className={styles.paginationContainer}>
167
188
  <Pagination
168
- page={page}
189
+ page={paginationPage}
169
190
  pageSize={pageSize}
170
191
  pageSizes={[10, 20, 30, 40, 50, 100]}
171
- totalItems={totalOrders}
192
+ totalItems={paginationTotalItems}
172
193
  onChange={({ page: newPage, pageSize: newPageSize }) => {
173
- if (newPageSize !== pageSize) {
174
- setPage(1);
194
+ if (isActiveClientPaged) {
195
+ if (newPageSize !== pageSize) {
196
+ setPageSize(newPageSize);
197
+ goTo(1);
198
+ } else {
199
+ goTo(newPage);
200
+ }
175
201
  } else {
176
- setPage(newPage);
202
+ if (newPageSize !== pageSize) {
203
+ setPage(1);
204
+ } else {
205
+ setPage(newPage);
206
+ }
207
+ setPageSize(newPageSize);
177
208
  }
178
- setPageSize(newPageSize);
179
209
  }}
180
210
  />
181
211
  </div>
@@ -0,0 +1,44 @@
1
+ import { Tag } from '@carbon/react';
2
+ import React, { useMemo } from 'react';
3
+ import styles from './priority-tag.scss';
4
+
5
+ interface PriorityTagProps {
6
+ status: string;
7
+ }
8
+
9
+ export enum QueueEntryPriority {
10
+ Emergency = 'EMERGENCY',
11
+ Priority = 'PRIORITY',
12
+ NonUrgent = 'NON-URGENT',
13
+ }
14
+
15
+ const PriorityTag: React.FC<PriorityTagProps> = ({ status }) => {
16
+ const tagClassName = useMemo(() => {
17
+ let className = 'gray';
18
+ if (
19
+ status.toUpperCase() === `${QueueEntryPriority.Emergency}` ||
20
+ status.toUpperCase() === `${QueueEntryPriority.Emergency} PRIORITY`
21
+ )
22
+ className = 'emergencyTag';
23
+ if (
24
+ status.toUpperCase() === `${QueueEntryPriority.Priority}` ||
25
+ status.toUpperCase() === `${QueueEntryPriority.Priority} PRIORITY` ||
26
+ status.toUpperCase() === 'NORMAL PRIORITY' ||
27
+ status.toUpperCase() === 'NOT URGENT'
28
+ )
29
+ className = 'priorityTag';
30
+ if (
31
+ status.toUpperCase() === `${QueueEntryPriority.NonUrgent}` ||
32
+ status.toUpperCase() === `${QueueEntryPriority.NonUrgent} PRIORITY`
33
+ )
34
+ className = 'nonUrgentTag';
35
+ return className;
36
+ }, [status]);
37
+ return (
38
+ <Tag size="md" className={styles[tagClassName]}>
39
+ {status}
40
+ </Tag>
41
+ );
42
+ };
43
+
44
+ export default PriorityTag;
@@ -0,0 +1,12 @@
1
+ .nonUrgentTag {
2
+ background-color: rgb(167, 240, 186);
3
+ color: rgb(14, 96, 39);
4
+ }
5
+ .emergencyTag {
6
+ background-color: rgb(255, 215, 217);
7
+ color: rgb(162, 25, 31);
8
+ }
9
+ .priorityTag {
10
+ background-color: rgb(248, 237, 98);
11
+ color: brown;
12
+ }