@kenyaemr/esm-service-queues-app 7.0.2-pre.67 → 7.0.2-pre.68
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 +14 -13
- package/dist/130.js +1 -1
- package/dist/130.js.map +1 -1
- package/dist/199.js +1 -0
- package/dist/{738.js.map → 199.js.map} +1 -1
- package/dist/271.js +1 -1
- package/dist/276.js +1 -1
- package/dist/319.js +1 -1
- package/dist/401.js +1 -1
- package/dist/430.js +1 -2
- package/dist/430.js.map +1 -1
- package/dist/460.js +1 -1
- package/dist/490.js +2 -0
- package/dist/490.js.map +1 -0
- package/dist/574.js +1 -1
- package/dist/6.js +1 -0
- package/dist/6.js.map +1 -0
- package/dist/60.js +1 -0
- package/dist/60.js.map +1 -0
- package/dist/600.js +1 -0
- package/dist/600.js.map +1 -0
- package/dist/644.js +1 -1
- package/dist/647.js +1 -1
- package/dist/647.js.map +1 -1
- package/dist/650.js +1 -1
- package/dist/650.js.map +1 -1
- package/dist/669.js +1 -1
- package/dist/669.js.map +1 -1
- package/dist/{806.js → 752.js} +1 -1
- package/dist/{806.js.map → 752.js.map} +1 -1
- package/dist/757.js +1 -1
- package/dist/764.js +1 -1
- package/dist/764.js.map +1 -1
- package/dist/788.js +1 -1
- package/dist/{981.js → 800.js} +1 -1
- package/dist/{981.js.map → 800.js.map} +1 -1
- package/dist/807.js +1 -1
- package/dist/{696.js → 828.js} +1 -1
- package/dist/{696.js.map → 828.js.map} +1 -1
- package/dist/833.js +1 -1
- package/dist/877.js +1 -1
- package/dist/877.js.map +1 -1
- package/dist/917.js +1 -1
- package/dist/917.js.map +1 -1
- package/dist/kenyaemr-esm-service-queues-app.js +1 -1
- package/dist/kenyaemr-esm-service-queues-app.js.buildmanifest.json +193 -193
- package/dist/kenyaemr-esm-service-queues-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +2 -2
- package/src/add-patient-toqueue/add-patient-toqueue-dialog.component.tsx +4 -4
- package/src/add-provider-queue-room/add-provider-queue-room.component.tsx +12 -15
- package/src/config-schema.ts +20 -0
- package/src/helpers/helpers.ts +42 -32
- package/src/home.component.tsx +1 -1
- package/src/hooks/useQueueEntries.ts +1 -1
- package/src/hooks/useQueueService.ts +21 -0
- package/src/hooks/useQueueStatuses.ts +40 -0
- package/src/index.ts +5 -5
- package/src/patient-info/patient-info.component.tsx +9 -9
- package/src/patient-queue-header/patient-queue-header.component.tsx +30 -24
- package/src/patient-queue-header/patient-queue-header.scss +1 -2
- package/src/patient-queue-metrics/clinic-metrics.component.tsx +16 -27
- package/src/patient-queue-metrics/queue-metrics.resource.ts +1 -2
- package/src/patient-search/patient-scheduled-visits.scss +1 -1
- package/src/patient-search/patient-search.scss +6 -0
- package/src/patient-search/patient-search.workspace.tsx +30 -30
- package/src/patient-search/visit-form/visit-form.component.tsx +8 -8
- package/src/patient-search/visit-form/visit-form.scss +5 -3
- package/src/patient-search/visit-form-queue-fields/visit-form-queue-fields.component.tsx +14 -7
- package/src/queue-patient-linelists/queue-linelist-filter.scss +2 -12
- package/src/queue-rooms/queue-room-form.scss +1 -1
- package/src/queue-screen/queue-screen.component.tsx +1 -1
- package/src/queue-services/queue-service-form.scss +2 -2
- package/src/queue-table/cells/queue-table-action-cell.component.tsx +6 -4
- package/src/queue-table/cells/queue-table-action-cell.scss +7 -0
- package/src/queue-table/default-queue-table.component.tsx +69 -38
- package/src/queue-table/queue-entry-actions/{edit-queue-entry-modal.component.tsx → edit-queue-entry.modal.tsx} +1 -1
- package/src/queue-table/queue-entry-actions/{end-queue-entry-modal.component.tsx → end-queue-entry.modal.tsx} +1 -1
- package/src/queue-table/queue-entry-actions/{queue-entry-actions-modal.test.tsx → queue-entry-actions.test.tsx} +2 -2
- package/src/queue-table/queue-entry-actions/{queue-entry-confirm-action-modal.test.tsx → queue-entry-confirm-action.test.tsx} +3 -3
- package/src/queue-table/queue-entry-actions/{queue-entry-undo-actions-modal.test.tsx → queue-entry-undo-actions.test.tsx} +2 -2
- package/src/queue-table/queue-entry-actions/{transition-queue-entry-modal.component.tsx → transition-queue-entry.modal.tsx} +1 -1
- package/src/queue-table/queue-entry-actions/{undo-transition-queue-entry-modal.component.tsx → undo-transition-queue-entry.modal.tsx} +1 -1
- package/src/queue-table/queue-entry-actions/{void-queue-entry-modal.component.tsx → void-queue-entry.modal.tsx} +1 -1
- package/src/queue-table/queue-table-by-status-skeleton.component.tsx +18 -18
- package/src/queue-table/queue-table-metrics-card.scss +1 -1
- package/src/queue-table/queue-table-metrics.scss +1 -1
- package/src/queue-table/queue-table.component.tsx +35 -18
- package/src/queue-table/queue-table.scss +12 -4
- package/src/types/index.ts +3 -1
- package/src/views/queue-table-by-status-view.component.tsx +2 -14
- package/src/views/queue-tables-for-all-statuses.component.tsx +81 -43
- package/translations/am.json +29 -19
- package/translations/ar.json +33 -23
- package/translations/en.json +3 -2
- package/translations/es.json +29 -19
- package/translations/fr.json +29 -19
- package/translations/he.json +33 -23
- package/translations/km.json +31 -21
- package/translations/zh.json +39 -29
- package/translations/zh_CN.json +38 -28
- package/dist/185.js +0 -1
- package/dist/185.js.map +0 -1
- package/dist/233.js +0 -1
- package/dist/233.js.map +0 -1
- package/dist/237.js +0 -1
- package/dist/237.js.map +0 -1
- package/dist/703.js +0 -1
- package/dist/703.js.map +0 -1
- package/dist/738.js +0 -1
- /package/dist/{430.js.LICENSE.txt → 490.js.LICENSE.txt} +0 -0
- /package/src/queue-table/queue-entry-actions/{queue-entry-actions-modal.component.tsx → queue-entry-actions.modal.tsx} +0 -0
- /package/src/queue-table/queue-entry-actions/{queue-entry-confirm-action-modal.component.tsx → queue-entry-confirm-action.modal.tsx} +0 -0
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.2.0","queue":"^2.4.0-0"},"extensions":[{"name":"outpatient-side-nav-ext","component":"outpatientSideNav","slot":"outpatient-sidebar-slot","online":true,"offline":true},{"name":"service-queues-dashboard-link","component":"serviceQueuesDashboardLink","slot":"homepage-dashboard-slot","meta":{"name":"service-queues","slot":"service-queues-dashboard-slot","title":"Service queues"},"online":true,"offline":true},{"name":"queue-table-by-status-menu-dashboard-link","component":"queueTableByStatusMenu","meta":{"name":"service-queues","slot":"service-queues-dashboard-slot","title":"Service queues"},"online":true,"offline":true},{"component":"root","name":"service-queues-dashboard","slot":"service-queues-dashboard-slot"},{"name":"edit-queue-entry-status-modal","component":"editQueueEntryStatusModal"},{"name":"patient-info-banner-slot","component":"patientInfoBannerSlot"},{"name":"remove-queue-entry","component":"removeQueueEntry"},{"name":"clear-all-queue-entries","component":"clearAllQueueEntries"},{"name":"add-visit-to-queue-modal","component":"addVisitToQueueModal"},{"name":"transition-queue-entry-status-modal","component":"transitionQueueEntryStatusModal"},{"name":"previous-visit-summary-widget","component":"pastVisitSummary","slot":"previous-visit-summary-slot"},{"name":"add-provider-to-room-modal","component":"addProviderToRoomModal"},{"name":"transition-queue-entry-modal","component":"transitionQueueEntryModal"},{"name":"edit-queue-entry-modal","component":"editQueueEntryModal"},{"name":"undo-transition-queue-entry-modal","component":"undoTransitionQueueEntryModal"},{"name":"void-queue-entry-modal","component":"voidQueueEntryModal"},{"name":"end-queue-entry-modal","component":"endQueueEntryModal"},{"name":"active-visits-row-actions","component":"activeVisitsRowActions","slot":"queue-table-serve-patient-slot"},{"name":"visit-form-queue-fields","component":"visitFormQueueFields","slot":"visit-form-queue-slot"}],"workspaces":[{"name":"service-queues-service-form","title":"addNewQueueService","component":"addNewQueueServiceWorkspace","type":"service-queues"},{"name":"service-queues-room-form","title":"addNewQueueServiceRoom","component":"addNewQueueServiceRoomWorkspace","type":"service-queues"},{"name":"service-queues-linelist-filter","title":"filter","component":"queueLinelistFilterWorkspace","type":"service-queues"},{"name":"service-queues-patient-search","title":"searchPatient","component":"patientSearchWorkspace","type":"service-queues"}],"version":"7.0.2-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.2.0","queue":"^2.4.0-0"},"extensions":[{"name":"outpatient-side-nav-ext","component":"outpatientSideNav","slot":"outpatient-sidebar-slot","online":true,"offline":true},{"name":"service-queues-dashboard-link","component":"serviceQueuesDashboardLink","slot":"homepage-dashboard-slot","meta":{"name":"service-queues","slot":"service-queues-dashboard-slot","title":"Service queues"},"online":true,"offline":true},{"name":"queue-table-by-status-menu-dashboard-link","component":"queueTableByStatusMenu","meta":{"name":"service-queues","slot":"service-queues-dashboard-slot","title":"Service queues"},"online":true,"offline":true},{"component":"root","name":"service-queues-dashboard","slot":"service-queues-dashboard-slot"},{"name":"edit-queue-entry-status-modal","component":"editQueueEntryStatusModal"},{"name":"patient-info-banner-slot","component":"patientInfoBannerSlot"},{"name":"remove-queue-entry","component":"removeQueueEntry"},{"name":"clear-all-queue-entries","component":"clearAllQueueEntries"},{"name":"add-visit-to-queue-modal","component":"addVisitToQueueModal"},{"name":"transition-queue-entry-status-modal","component":"transitionQueueEntryStatusModal"},{"name":"previous-visit-summary-widget","component":"pastVisitSummary","slot":"previous-visit-summary-slot"},{"name":"add-provider-to-room-modal","component":"addProviderToRoomModal"},{"name":"transition-queue-entry-modal","component":"transitionQueueEntryModal"},{"name":"edit-queue-entry-modal","component":"editQueueEntryModal"},{"name":"undo-transition-queue-entry-modal","component":"undoTransitionQueueEntryModal"},{"name":"void-queue-entry-modal","component":"voidQueueEntryModal"},{"name":"end-queue-entry-modal","component":"endQueueEntryModal"},{"name":"active-visits-row-actions","component":"activeVisitsRowActions","slot":"queue-table-serve-patient-slot"},{"name":"visit-form-queue-fields","component":"visitFormQueueFields","slot":"visit-form-queue-slot"}],"workspaces":[{"name":"service-queues-service-form","title":"addNewQueueService","component":"addNewQueueServiceWorkspace","type":"service-queues"},{"name":"service-queues-room-form","title":"addNewQueueServiceRoom","component":"addNewQueueServiceRoomWorkspace","type":"service-queues"},{"name":"service-queues-linelist-filter","title":"filter","component":"queueLinelistFilterWorkspace","type":"service-queues"},{"name":"service-queues-patient-search","title":"searchPatient","component":"patientSearchWorkspace","type":"service-queues"}],"version":"7.0.2-pre.68"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenyaemr/esm-service-queues-app",
|
|
3
|
-
"version": "7.0.2-pre.
|
|
3
|
+
"version": "7.0.2-pre.68",
|
|
4
4
|
"description": "Outpatient front-end module for the OpenMRS SPA",
|
|
5
5
|
"browser": "dist/kenyaemr-esm-service-queues-app.js",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js --color",
|
|
19
19
|
"coverage": "yarn test --coverage",
|
|
20
20
|
"typescript": "tsc",
|
|
21
|
-
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.extension.tsx' 'src/**/*.workspace.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js"
|
|
21
|
+
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.extension.tsx' 'src/**/*modal.tsx' 'src/**/*.workspace.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js"
|
|
22
22
|
},
|
|
23
23
|
"browserslist": [
|
|
24
24
|
"extends browserslist-config-openmrs"
|
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
SelectItem,
|
|
12
12
|
RadioButtonGroup,
|
|
13
13
|
RadioButton,
|
|
14
|
+
RadioButtonSkeleton,
|
|
15
|
+
SelectSkeleton,
|
|
14
16
|
} from '@carbon/react';
|
|
15
17
|
import { showSnackbar, useConfig } from '@openmrs/esm-framework';
|
|
16
18
|
import { postQueueEntry } from '../active-visits/active-visits-table.resource';
|
|
17
|
-
import
|
|
18
|
-
import { type ActiveVisit, useMissingQueueEntries } from '../visits-missing-inqueue/visits-missing-inqueue.resource';
|
|
19
|
+
import { type ActiveVisit } from '../visits-missing-inqueue/visits-missing-inqueue.resource';
|
|
19
20
|
import { useQueueLocations } from '../patient-search/hooks/useQueueLocations';
|
|
20
21
|
import { useQueues } from '../hooks/useQueues';
|
|
21
22
|
import { useMutateQueueEntries } from '../hooks/useQueueEntries';
|
|
22
23
|
import { type ConfigObject } from '../config-schema';
|
|
23
|
-
import
|
|
24
|
-
import { SelectSkeleton } from '@carbon/react';
|
|
24
|
+
import styles from './add-patient-toqueue-dialog.scss';
|
|
25
25
|
|
|
26
26
|
interface AddVisitToQueueDialogProps {
|
|
27
27
|
visitDetails: ActiveVisit;
|
|
@@ -25,15 +25,14 @@ import {
|
|
|
25
25
|
updateIsPermanentProviderQueueRoom,
|
|
26
26
|
updateSelectedQueueLocationName,
|
|
27
27
|
updateSelectedQueueLocationUuid,
|
|
28
|
-
|
|
29
|
-
updateSelectedServiceUuid,
|
|
28
|
+
updateSelectedService,
|
|
30
29
|
useIsPermanentProviderQueueRoom,
|
|
30
|
+
useSelectedQueueLocationName,
|
|
31
31
|
useSelectedQueueLocationUuid,
|
|
32
|
-
|
|
33
|
-
useSelectedServiceUuid,
|
|
32
|
+
useSelectedService,
|
|
34
33
|
} from '../helpers/helpers';
|
|
35
34
|
import styles from './add-provider-queue-room.scss';
|
|
36
|
-
import
|
|
35
|
+
import useQueueServices from '../hooks/useQueueService';
|
|
37
36
|
|
|
38
37
|
interface AddProviderQueueRoomProps {
|
|
39
38
|
providerUuid: string;
|
|
@@ -43,10 +42,9 @@ interface AddProviderQueueRoomProps {
|
|
|
43
42
|
const AddProviderQueueRoom: React.FC<AddProviderQueueRoomProps> = ({ providerUuid, closeModal }) => {
|
|
44
43
|
const { t } = useTranslation();
|
|
45
44
|
|
|
46
|
-
const currentLocationName =
|
|
45
|
+
const currentLocationName = useSelectedQueueLocationName();
|
|
47
46
|
const currentLocationUuid = useSelectedQueueLocationUuid();
|
|
48
|
-
const
|
|
49
|
-
const currentServiceName = useSelectedServiceName();
|
|
47
|
+
const currentService = useSelectedService();
|
|
50
48
|
const currentIsPermanentProviderQueueRoom = useIsPermanentProviderQueueRoom();
|
|
51
49
|
const { providerRoom, isLoading: loading } = useProvidersQueueRoom(providerUuid);
|
|
52
50
|
const [queueRoomUuid, setQueueRoomUuid] = useState('');
|
|
@@ -60,16 +58,15 @@ const AddProviderQueueRoom: React.FC<AddProviderQueueRoomProps> = ({ providerUui
|
|
|
60
58
|
}, [providerRoom]);
|
|
61
59
|
|
|
62
60
|
const { mutate } = useProvidersQueueRoom(providerUuid);
|
|
63
|
-
const {
|
|
64
|
-
const { rooms } = useQueueRooms(currentLocationUuid,
|
|
61
|
+
const { services } = useQueueServices();
|
|
62
|
+
const { rooms } = useQueueRooms(currentLocationUuid, currentService?.serviceUuid);
|
|
65
63
|
const { queueLocations } = useQueueLocations();
|
|
66
64
|
const [isMissingQueueRoom, setIsMissingQueueRoom] = useState(false);
|
|
67
65
|
|
|
68
66
|
const handleServiceChange = ({ selectedItem }) => {
|
|
69
67
|
localStorage.setItem('queueServiceName', selectedItem.name);
|
|
70
|
-
localStorage.setItem('
|
|
71
|
-
|
|
72
|
-
updateSelectedServiceUuid(selectedItem.uuid);
|
|
68
|
+
localStorage.setItem('queueService', selectedItem.uuid);
|
|
69
|
+
updateSelectedService(selectedItem.uuid, selectedItem.name);
|
|
73
70
|
};
|
|
74
71
|
|
|
75
72
|
const handleQueueLocationChange = ({ selectedItem }) => {
|
|
@@ -172,11 +169,11 @@ const AddProviderQueueRoom: React.FC<AddProviderQueueRoomProps> = ({ providerUui
|
|
|
172
169
|
aria-label={t('selectService', 'Select a service')}
|
|
173
170
|
type="default"
|
|
174
171
|
label=""
|
|
175
|
-
items={
|
|
172
|
+
items={services ?? []}
|
|
176
173
|
itemToString={(item) => (item ? item.display : '')}
|
|
177
174
|
onChange={handleServiceChange}
|
|
178
175
|
size="md"
|
|
179
|
-
initialSelectedItem={{ uuid:
|
|
176
|
+
initialSelectedItem={{ uuid: currentService?.serviceUuid, display: currentService?.serviceDisplay }}
|
|
180
177
|
/>
|
|
181
178
|
</section>
|
|
182
179
|
|
package/src/config-schema.ts
CHANGED
|
@@ -60,6 +60,22 @@ export const defaultQueueTable: TableDefinitions = {
|
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
export const configSchema = {
|
|
63
|
+
dashboardTitle: {
|
|
64
|
+
_type: Type.Object,
|
|
65
|
+
_description: 'The title to be displayed on the service queues dashboard',
|
|
66
|
+
key: {
|
|
67
|
+
_type: Type.String,
|
|
68
|
+
_description: 'The translation key of the title to be displayed on the service queues dashboard',
|
|
69
|
+
},
|
|
70
|
+
value: {
|
|
71
|
+
_type: Type.String,
|
|
72
|
+
_description: 'The translation value of the title to be displayed on the service queues dashboard',
|
|
73
|
+
},
|
|
74
|
+
_default: {
|
|
75
|
+
key: 'serviceQueues',
|
|
76
|
+
value: 'Service queues',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
63
79
|
concepts: {
|
|
64
80
|
defaultPriorityConceptUuid: {
|
|
65
81
|
_type: Type.ConceptUuid,
|
|
@@ -377,6 +393,10 @@ function columnHasType(columnDef: ColumnDefinition, type: ColumnType): boolean {
|
|
|
377
393
|
}
|
|
378
394
|
|
|
379
395
|
export interface ConfigObject {
|
|
396
|
+
dashboardTitle: {
|
|
397
|
+
key: string;
|
|
398
|
+
value: string;
|
|
399
|
+
};
|
|
380
400
|
concepts: {
|
|
381
401
|
defaultPriorityConceptUuid: string;
|
|
382
402
|
defaultStatusConceptUuid: string;
|
package/src/helpers/helpers.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import { getGlobalStore } from '@openmrs/esm-framework';
|
|
3
3
|
import type { AppointmentSummary } from '../types';
|
|
4
|
-
import { useTranslation } from 'react-i18next';
|
|
5
4
|
|
|
6
5
|
export const getServiceCountByAppointmentType = (
|
|
7
6
|
appointmentSummary: Array<AppointmentSummary>,
|
|
@@ -15,22 +14,24 @@ export const getServiceCountByAppointmentType = (
|
|
|
15
14
|
.reduce((count, val) => count + val, 0);
|
|
16
15
|
};
|
|
17
16
|
|
|
18
|
-
const initialServiceNameState = { serviceName: sessionStorage.getItem('queueServiceName') };
|
|
19
|
-
const initialServiceUuidState = { serviceUuid: sessionStorage.getItem('queueServiceUuid') };
|
|
20
|
-
const intialStatusNameState = { status: '' };
|
|
21
17
|
const initialQueueLocationNameState = { queueLocationName: sessionStorage.getItem('queueLocationName') };
|
|
22
18
|
const initialQueueLocationUuidState = { queueLocationUuid: sessionStorage.getItem('queueLocationUuid') };
|
|
19
|
+
const initialServiceUuidState = {
|
|
20
|
+
serviceUuid: sessionStorage.getItem('queueServiceUuid'),
|
|
21
|
+
serviceDisplay: sessionStorage.getItem('queueServiceDisplay'),
|
|
22
|
+
};
|
|
23
|
+
const intialStatusNameState = { status: '' };
|
|
24
|
+
const initialQueueStatusState = { statusUuid: null, statusDisplay: null };
|
|
23
25
|
const initialSelectedQueueRoomTimestamp = { providerQueueRoomTimestamp: new Date() };
|
|
24
26
|
const initialPermanentProviderQueueRoomState = {
|
|
25
27
|
isPermanentProviderQueueRoom: sessionStorage.getItem('isPermanentProviderQueueRoom'),
|
|
26
28
|
};
|
|
27
29
|
|
|
28
|
-
export function
|
|
29
|
-
return getGlobalStore<{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return getGlobalStore<{ serviceUuid: string }>('queueSelectedServiceUuid', initialServiceUuidState);
|
|
30
|
+
export function getSelectedService() {
|
|
31
|
+
return getGlobalStore<{ serviceUuid: string; serviceDisplay: string }>(
|
|
32
|
+
'queueSelectedServiceUuid',
|
|
33
|
+
initialServiceUuidState,
|
|
34
|
+
);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export function getSelectedAppointmentStatus() {
|
|
@@ -45,6 +46,13 @@ export function getSelectedQueueLocationUuid() {
|
|
|
45
46
|
return getGlobalStore<{ queueLocationUuid: string }>('queueLocationUuidSelected', initialQueueLocationUuidState);
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
export function getSelectedQueueStatus() {
|
|
50
|
+
return getGlobalStore<{ statusUuid: string; statusDisplay: string }>(
|
|
51
|
+
'queueStatusUuidSelected',
|
|
52
|
+
initialQueueStatusState,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
export function getSelectedQueueRoomTimestamp() {
|
|
49
57
|
return getGlobalStore<{ providerQueueRoomTimestamp: Date }>(
|
|
50
58
|
'queueProviderRoomTimestamp',
|
|
@@ -59,16 +67,11 @@ export function getIsPermanentProviderQueueRoom() {
|
|
|
59
67
|
);
|
|
60
68
|
}
|
|
61
69
|
|
|
62
|
-
export const
|
|
63
|
-
const store =
|
|
64
|
-
sessionStorage.setItem('
|
|
65
|
-
store.setState({ serviceName: currentServiceName });
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export const updateSelectedServiceUuid = (currentServiceUuid: string) => {
|
|
69
|
-
const store = getSelectedServiceUuid();
|
|
70
|
+
export const updateSelectedService = (currentServiceUuid: string, currentServiceDisplay: string) => {
|
|
71
|
+
const store = getSelectedService();
|
|
72
|
+
sessionStorage.setItem('queueServiceDisplay', currentServiceDisplay);
|
|
70
73
|
sessionStorage.setItem('queueServiceUuid', currentServiceUuid);
|
|
71
|
-
store.setState({ serviceUuid: currentServiceUuid });
|
|
74
|
+
store.setState({ serviceUuid: currentServiceUuid, serviceDisplay: currentServiceDisplay });
|
|
72
75
|
};
|
|
73
76
|
|
|
74
77
|
export const updateSelectedAppointmentStatus = (currentAppointmentStatus: string) => {
|
|
@@ -99,24 +102,18 @@ export const updateIsPermanentProviderQueueRoom = (currentIsPermanentProviderQue
|
|
|
99
102
|
store.setState({ isPermanentProviderQueueRoom: currentIsPermanentProviderQueueRoom });
|
|
100
103
|
};
|
|
101
104
|
|
|
102
|
-
export const
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
useEffect(() => {
|
|
107
|
-
getSelectedServiceName().subscribe(({ serviceName }) => setCurrentServiceName(serviceName));
|
|
108
|
-
}, []);
|
|
109
|
-
|
|
110
|
-
return currentServiceName;
|
|
105
|
+
export const updateSelectedQueueStatus = (currentQueueStatusUuid: string, currentQueueStatusDisplay: string) => {
|
|
106
|
+
const store = getSelectedQueueStatus();
|
|
107
|
+
store.setState({ statusUuid: currentQueueStatusUuid, statusDisplay: currentQueueStatusDisplay });
|
|
111
108
|
};
|
|
112
109
|
|
|
113
|
-
export const
|
|
114
|
-
const [
|
|
110
|
+
export const useSelectedService = () => {
|
|
111
|
+
const [currentService, setCurrentService] = useState(getSelectedService()?.getState());
|
|
115
112
|
|
|
116
113
|
useEffect(() => {
|
|
117
|
-
|
|
114
|
+
getSelectedService().subscribe((newSelectedService) => setCurrentService(newSelectedService));
|
|
118
115
|
}, []);
|
|
119
|
-
return
|
|
116
|
+
return currentService;
|
|
120
117
|
};
|
|
121
118
|
|
|
122
119
|
export const useSelectedAppointmentStatus = () => {
|
|
@@ -175,3 +172,16 @@ export const useIsPermanentProviderQueueRoom = () => {
|
|
|
175
172
|
}, []);
|
|
176
173
|
return currentIsPermanentProviderQueueRoom;
|
|
177
174
|
};
|
|
175
|
+
|
|
176
|
+
export const useSelectedQueueStatus = () => {
|
|
177
|
+
const [currentQueueStatus, setCurrentQueueStatus] = useState(getSelectedQueueStatus()?.getState());
|
|
178
|
+
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
getSelectedQueueStatus().subscribe((newStatus) => setCurrentQueueStatus(newStatus));
|
|
181
|
+
}, []);
|
|
182
|
+
return currentQueueStatus;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export function isUuid(value: string) {
|
|
186
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value) || /^[0-9a-f]{36}$/i.test(value);
|
|
187
|
+
}
|
package/src/home.component.tsx
CHANGED
|
@@ -154,7 +154,7 @@ export function useQueueEntries(searchCriteria?: QueueEntrySearchCriteria, rep:
|
|
|
154
154
|
return {
|
|
155
155
|
queueEntries,
|
|
156
156
|
totalCount,
|
|
157
|
-
isLoading: totalCount && queueEntries.length < totalCount,
|
|
157
|
+
isLoading: !totalCount || (totalCount && queueEntries.length < totalCount),
|
|
158
158
|
isValidating: isValidating || currentPage < data.length,
|
|
159
159
|
error,
|
|
160
160
|
mutate: mutateQueueEntries,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getLocale } from '@openmrs/esm-framework';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { useQueues } from './useQueues';
|
|
4
|
+
|
|
5
|
+
function useQueueServices() {
|
|
6
|
+
const { queues, isLoading } = useQueues();
|
|
7
|
+
|
|
8
|
+
const results = useMemo(
|
|
9
|
+
() => ({
|
|
10
|
+
services: [...new Set(queues?.map((queue) => queue.service) ?? [])].sort((a, b) =>
|
|
11
|
+
a.display.localeCompare(b.display, getLocale()),
|
|
12
|
+
),
|
|
13
|
+
isLoadingQueueServices: isLoading,
|
|
14
|
+
}),
|
|
15
|
+
[queues, isLoading],
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
return results;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default useQueueServices;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type FetchResponse,
|
|
3
|
+
OpenmrsResource,
|
|
4
|
+
openmrsFetch,
|
|
5
|
+
restBaseUrl,
|
|
6
|
+
useOpenmrsSWR,
|
|
7
|
+
getLocale,
|
|
8
|
+
} from '@openmrs/esm-framework';
|
|
9
|
+
import { useSystemSetting } from './useSystemSetting';
|
|
10
|
+
import { useMemo } from 'react';
|
|
11
|
+
import type { Concept } from '../types';
|
|
12
|
+
import useSWRImmutable from 'swr/immutable';
|
|
13
|
+
import { useQueues } from './useQueues';
|
|
14
|
+
|
|
15
|
+
function useQueueStatuses() {
|
|
16
|
+
const { queues, isLoading } = useQueues();
|
|
17
|
+
|
|
18
|
+
const results = useMemo(() => {
|
|
19
|
+
const allStatuses = ([] as Array<Concept>).concat(...(queues ?? [])?.map((queue) => queue?.allowedStatuses));
|
|
20
|
+
|
|
21
|
+
const uuidSet = new Set<string>();
|
|
22
|
+
|
|
23
|
+
const statuses: Array<Concept> = [];
|
|
24
|
+
|
|
25
|
+
allStatuses.forEach((status) => {
|
|
26
|
+
if (!uuidSet.has(status?.uuid)) {
|
|
27
|
+
uuidSet.add(status?.uuid);
|
|
28
|
+
statuses.push(status);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
statuses: statuses.sort((a, b) => a.display.localeCompare(b.display, getLocale())),
|
|
34
|
+
isLoadingQueueStatuses: isLoading,
|
|
35
|
+
};
|
|
36
|
+
}, [isLoading, queues]);
|
|
37
|
+
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
export default useQueueStatuses;
|
package/src/index.ts
CHANGED
|
@@ -91,7 +91,7 @@ export const addProviderToRoomModal = getAsyncLifecycle(
|
|
|
91
91
|
);
|
|
92
92
|
|
|
93
93
|
export const transitionQueueEntryModal = getAsyncLifecycle(
|
|
94
|
-
() => import('./queue-table/queue-entry-actions/transition-queue-entry
|
|
94
|
+
() => import('./queue-table/queue-entry-actions/transition-queue-entry.modal'),
|
|
95
95
|
{
|
|
96
96
|
featureName: 'transfer patient to a different queue',
|
|
97
97
|
moduleName,
|
|
@@ -99,7 +99,7 @@ export const transitionQueueEntryModal = getAsyncLifecycle(
|
|
|
99
99
|
);
|
|
100
100
|
|
|
101
101
|
export const editQueueEntryModal = getAsyncLifecycle(
|
|
102
|
-
() => import('./queue-table/queue-entry-actions/edit-queue-entry
|
|
102
|
+
() => import('./queue-table/queue-entry-actions/edit-queue-entry.modal'),
|
|
103
103
|
{
|
|
104
104
|
featureName: 'edit queue entry of a patient',
|
|
105
105
|
moduleName,
|
|
@@ -107,7 +107,7 @@ export const editQueueEntryModal = getAsyncLifecycle(
|
|
|
107
107
|
);
|
|
108
108
|
|
|
109
109
|
export const undoTransitionQueueEntryModal = getAsyncLifecycle(
|
|
110
|
-
() => import('./queue-table/queue-entry-actions/undo-transition-queue-entry
|
|
110
|
+
() => import('./queue-table/queue-entry-actions/undo-transition-queue-entry.modal'),
|
|
111
111
|
{
|
|
112
112
|
featureName: 'undo queue entry transiion of a patient',
|
|
113
113
|
moduleName,
|
|
@@ -115,7 +115,7 @@ export const undoTransitionQueueEntryModal = getAsyncLifecycle(
|
|
|
115
115
|
);
|
|
116
116
|
|
|
117
117
|
export const voidQueueEntryModal = getAsyncLifecycle(
|
|
118
|
-
() => import('./queue-table/queue-entry-actions/void-queue-entry
|
|
118
|
+
() => import('./queue-table/queue-entry-actions/void-queue-entry.modal'),
|
|
119
119
|
{
|
|
120
120
|
featureName: 'void queue entry of a patient',
|
|
121
121
|
moduleName,
|
|
@@ -123,7 +123,7 @@ export const voidQueueEntryModal = getAsyncLifecycle(
|
|
|
123
123
|
);
|
|
124
124
|
|
|
125
125
|
export const endQueueEntryModal = getAsyncLifecycle(
|
|
126
|
-
() => import('./queue-table/queue-entry-actions/end-queue-entry
|
|
126
|
+
() => import('./queue-table/queue-entry-actions/end-queue-entry.modal'),
|
|
127
127
|
{
|
|
128
128
|
featureName: 'end queue entry of a patient',
|
|
129
129
|
moduleName,
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import classNames from 'classnames';
|
|
3
|
-
import { useTranslation } from 'react-i18next';
|
|
4
1
|
import { ClickableTile } from '@carbon/react';
|
|
5
2
|
import { Edit } from '@carbon/react/icons';
|
|
6
3
|
import {
|
|
4
|
+
ConfigurableLink,
|
|
5
|
+
PatientBannerContactDetails,
|
|
6
|
+
PatientBannerToggleContactDetailsButton,
|
|
7
|
+
PatientPhoto,
|
|
7
8
|
age,
|
|
8
|
-
displayName,
|
|
9
9
|
formatDate,
|
|
10
|
+
getPatientName,
|
|
10
11
|
parseDate,
|
|
11
|
-
ConfigurableLink,
|
|
12
|
-
PatientPhoto,
|
|
13
|
-
PatientBannerToggleContactDetailsButton,
|
|
14
|
-
PatientBannerContactDetails,
|
|
15
12
|
} from '@openmrs/esm-framework';
|
|
13
|
+
import classNames from 'classnames';
|
|
14
|
+
import React, { useState } from 'react';
|
|
15
|
+
import { useTranslation } from 'react-i18next';
|
|
16
16
|
import AppointmentDetails from './appointment-details.component';
|
|
17
17
|
import styles from './patient-info.scss';
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ interface PatientInfoProps {
|
|
|
24
24
|
const PatientInfo: React.FC<PatientInfoProps> = ({ patient, handlePatientInfoClick }) => {
|
|
25
25
|
const { t } = useTranslation();
|
|
26
26
|
const [showContactDetails, setShowContactDetails] = useState<boolean>(false);
|
|
27
|
-
const patientName =
|
|
27
|
+
const patientName = getPatientName(patient);
|
|
28
28
|
|
|
29
29
|
const toggleShowMore = (e: React.MouseEvent) => {
|
|
30
30
|
e.stopPropagation();
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
import React, { useCallback, useEffect } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import {
|
|
3
|
+
import { Location } from '@carbon/react/icons';
|
|
4
4
|
import { Dropdown } from '@carbon/react';
|
|
5
|
-
import {
|
|
5
|
+
import { useConfig, useSession } from '@openmrs/esm-framework';
|
|
6
6
|
import PatientQueueIllustration from './patient-queue-illustration.component';
|
|
7
7
|
import { useQueueLocations } from '../patient-search/hooks/useQueueLocations';
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
updateSelectedQueueLocationUuid,
|
|
11
11
|
updateSelectedQueueLocationName,
|
|
12
|
-
|
|
12
|
+
updateSelectedService,
|
|
13
13
|
useSelectedQueueLocationName,
|
|
14
14
|
useSelectedQueueLocationUuid,
|
|
15
15
|
} from '../helpers/helpers';
|
|
16
16
|
import styles from './patient-queue-header.scss';
|
|
17
|
+
import type { ConfigObject } from '../config-schema';
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
interface PatientQueueHeaderProps {
|
|
20
|
+
title?: string | JSX.Element;
|
|
21
|
+
showLocationDropdown: boolean;
|
|
22
|
+
actions?: React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const PatientQueueHeader: React.FC<PatientQueueHeaderProps> = ({ title, showLocationDropdown, actions }) => {
|
|
19
26
|
const { t } = useTranslation();
|
|
20
27
|
const { queueLocations, isLoading, error } = useQueueLocations();
|
|
28
|
+
const { dashboardTitle } = useConfig<ConfigObject>();
|
|
21
29
|
const userSession = useSession();
|
|
22
30
|
const userLocation = userSession?.sessionLocation?.display;
|
|
23
31
|
const currentQueueLocationName = useSelectedQueueLocationName();
|
|
@@ -30,7 +38,7 @@ const PatientQueueHeader: React.FC<{ title?: string }> = ({ title }) => {
|
|
|
30
38
|
} else {
|
|
31
39
|
updateSelectedQueueLocationUuid(selectedItem.id);
|
|
32
40
|
updateSelectedQueueLocationName(selectedItem.name);
|
|
33
|
-
|
|
41
|
+
updateSelectedService(null, t('all', 'All'));
|
|
34
42
|
}
|
|
35
43
|
}, []);
|
|
36
44
|
|
|
@@ -58,24 +66,21 @@ const PatientQueueHeader: React.FC<{ title?: string }> = ({ title }) => {
|
|
|
58
66
|
]);
|
|
59
67
|
|
|
60
68
|
return (
|
|
61
|
-
|
|
62
|
-
<div className={styles
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
<div className={styles.header} data-testid="patient-queue-header">
|
|
70
|
+
<div className={styles['left-justified-items']}>
|
|
71
|
+
<PatientQueueIllustration />
|
|
72
|
+
<div className={styles['page-labels']}>
|
|
73
|
+
<p>{dashboardTitle ? t(dashboardTitle.key, dashboardTitle.value) : t('serviceQueues', 'Service queues')}</p>
|
|
74
|
+
<p className={styles['page-name']}>{title ?? t('home', 'Home')}</p>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<div className={styles['right-justified-items']}>
|
|
78
|
+
<div className={styles['date-and-location']}>
|
|
79
|
+
<Location size={16} />
|
|
80
|
+
<span className={styles.value}>{userLocation}</span>
|
|
69
81
|
</div>
|
|
70
|
-
<div className={styles
|
|
71
|
-
|
|
72
|
-
<Location size={16} />
|
|
73
|
-
<span className={styles.value}>{userLocation}</span>
|
|
74
|
-
<span className={styles.middot}>·</span>
|
|
75
|
-
<Calendar size={16} />
|
|
76
|
-
<span className={styles.value}>{formatDate(new Date(), { mode: 'standard' })}</span>
|
|
77
|
-
</div>
|
|
78
|
-
<div className={styles.dropdownContainer}>
|
|
82
|
+
<div className={styles.dropdownContainer}>
|
|
83
|
+
{showLocationDropdown && (
|
|
79
84
|
<Dropdown
|
|
80
85
|
aria-label="Select queue location"
|
|
81
86
|
className={styles.dropdown}
|
|
@@ -89,10 +94,11 @@ const PatientQueueHeader: React.FC<{ title?: string }> = ({ title }) => {
|
|
|
89
94
|
type="inline"
|
|
90
95
|
onChange={handleQueueLocationChange}
|
|
91
96
|
/>
|
|
92
|
-
|
|
97
|
+
)}
|
|
98
|
+
{actions}
|
|
93
99
|
</div>
|
|
94
100
|
</div>
|
|
95
|
-
|
|
101
|
+
</div>
|
|
96
102
|
);
|
|
97
103
|
};
|
|
98
104
|
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
.header {
|
|
6
6
|
@include type.type-style('body-compact-02');
|
|
7
7
|
color: $text-02;
|
|
8
|
-
height: spacing.$spacing-12;
|
|
9
8
|
background-color: $ui-02;
|
|
10
9
|
border: 1px solid $ui-03;
|
|
11
10
|
border-left: 0px;
|
|
12
11
|
display: flex;
|
|
13
12
|
justify-content: space-between;
|
|
13
|
+
padding-right: 1rem;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.left-justified-items {
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
display: flex;
|
|
40
40
|
justify-content: flex-end;
|
|
41
41
|
align-items: center;
|
|
42
|
-
margin-right: 1rem;
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
.value {
|
|
@@ -3,18 +3,14 @@ import { useTranslation } from 'react-i18next';
|
|
|
3
3
|
import { Dropdown } from '@carbon/react';
|
|
4
4
|
import MetricsCard from './metrics-card.component';
|
|
5
5
|
import MetricsHeader from './metrics-header.component';
|
|
6
|
-
import {
|
|
7
|
-
updateSelectedServiceName,
|
|
8
|
-
updateSelectedServiceUuid,
|
|
9
|
-
useSelectedServiceName,
|
|
10
|
-
useSelectedServiceUuid,
|
|
11
|
-
useSelectedQueueLocationUuid,
|
|
12
|
-
} from '../helpers/helpers';
|
|
6
|
+
import { updateSelectedService, useSelectedService, useSelectedQueueLocationUuid } from '../helpers/helpers';
|
|
13
7
|
import { useActiveVisits, useAverageWaitTime } from './clinic-metrics.resource';
|
|
14
8
|
import { useServiceMetricsCount } from './queue-metrics.resource';
|
|
15
9
|
import styles from './clinic-metrics.scss';
|
|
16
10
|
import { useQueues } from '../hooks/useQueues';
|
|
17
11
|
import { useQueueEntries } from '../hooks/useQueueEntries';
|
|
12
|
+
import useQueueServices from '../hooks/useQueueService';
|
|
13
|
+
import { isDesktop, useLayoutType } from '@openmrs/esm-framework';
|
|
18
14
|
|
|
19
15
|
export interface Service {
|
|
20
16
|
uuid: string;
|
|
@@ -23,32 +19,25 @@ export interface Service {
|
|
|
23
19
|
|
|
24
20
|
function ClinicMetrics() {
|
|
25
21
|
const { t } = useTranslation();
|
|
22
|
+
const layout = useLayoutType();
|
|
26
23
|
|
|
27
24
|
const currentQueueLocation = useSelectedQueueLocationUuid();
|
|
28
|
-
const {
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const { serviceCount } = useServiceMetricsCount(currentServiceUuid, currentQueueLocation);
|
|
25
|
+
const { services } = useQueueServices();
|
|
26
|
+
const currentService = useSelectedService();
|
|
27
|
+
const { serviceCount } = useServiceMetricsCount(currentService?.serviceUuid, currentQueueLocation);
|
|
32
28
|
const [initialSelectedItem, setInitialSelectItem] = useState(() => {
|
|
33
|
-
|
|
34
|
-
return false;
|
|
35
|
-
} else if (currentServiceName === t('all', 'All')) {
|
|
36
|
-
return true;
|
|
37
|
-
} else {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
29
|
+
return !currentService?.serviceDisplay || !currentService?.serviceUuid;
|
|
40
30
|
});
|
|
41
|
-
const {
|
|
42
|
-
|
|
31
|
+
const { totalCount } = useQueueEntries({
|
|
32
|
+
service: currentService?.serviceUuid,
|
|
43
33
|
location: currentQueueLocation,
|
|
44
34
|
isEnded: false,
|
|
45
35
|
});
|
|
46
36
|
const { activeVisitsCount, isLoading: loading } = useActiveVisits();
|
|
47
|
-
const { waitTime } = useAverageWaitTime(
|
|
37
|
+
const { waitTime } = useAverageWaitTime(currentService?.serviceUuid, '');
|
|
48
38
|
|
|
49
39
|
const handleServiceChange = ({ selectedItem }) => {
|
|
50
|
-
|
|
51
|
-
updateSelectedServiceName(selectedItem.display);
|
|
40
|
+
updateSelectedService(selectedItem.uuid, selectedItem.display);
|
|
52
41
|
if (selectedItem.uuid == undefined) {
|
|
53
42
|
setInitialSelectItem(true);
|
|
54
43
|
} else {
|
|
@@ -70,18 +59,18 @@ function ClinicMetrics() {
|
|
|
70
59
|
label={t('patients', 'Patients')}
|
|
71
60
|
value={initialSelectedItem ? totalCount ?? '--' : serviceCount}
|
|
72
61
|
headerLabel={`${t('waitingFor', 'Waiting for')}:`}
|
|
73
|
-
service={
|
|
74
|
-
serviceUuid={
|
|
62
|
+
service={currentService?.serviceDisplay}
|
|
63
|
+
serviceUuid={currentService?.serviceUuid}
|
|
75
64
|
locationUuid={currentQueueLocation}>
|
|
76
65
|
<Dropdown
|
|
77
66
|
id="inline"
|
|
78
67
|
type="inline"
|
|
79
|
-
|
|
80
|
-
items={[{ display: `${t('all', 'All')}` }, ...queues]}
|
|
68
|
+
items={[{ display: `${t('all', 'All')}` }, ...(services ?? [])]}
|
|
81
69
|
itemToString={(item) =>
|
|
82
70
|
item ? `${item.display} ${item.location?.display ? `- ${item.location.display}` : ''}` : ''
|
|
83
71
|
}
|
|
84
72
|
onChange={handleServiceChange}
|
|
73
|
+
size={isDesktop(layout) ? 'sm' : 'lg'}
|
|
85
74
|
/>
|
|
86
75
|
</MetricsCard>
|
|
87
76
|
<MetricsCard
|