@kenyaemr/esm-service-queues-app 7.0.2-pre.66 → 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.
Files changed (115) hide show
  1. package/.turbo/turbo-build.log +14 -13
  2. package/dist/130.js +1 -1
  3. package/dist/130.js.map +1 -1
  4. package/dist/199.js +1 -0
  5. package/dist/{738.js.map → 199.js.map} +1 -1
  6. package/dist/271.js +1 -1
  7. package/dist/276.js +1 -1
  8. package/dist/319.js +1 -1
  9. package/dist/401.js +1 -1
  10. package/dist/430.js +1 -2
  11. package/dist/430.js.map +1 -1
  12. package/dist/460.js +1 -1
  13. package/dist/490.js +2 -0
  14. package/dist/490.js.map +1 -0
  15. package/dist/574.js +1 -1
  16. package/dist/6.js +1 -0
  17. package/dist/6.js.map +1 -0
  18. package/dist/60.js +1 -0
  19. package/dist/60.js.map +1 -0
  20. package/dist/600.js +1 -0
  21. package/dist/600.js.map +1 -0
  22. package/dist/644.js +1 -1
  23. package/dist/647.js +1 -1
  24. package/dist/647.js.map +1 -1
  25. package/dist/650.js +1 -1
  26. package/dist/650.js.map +1 -1
  27. package/dist/669.js +1 -1
  28. package/dist/669.js.map +1 -1
  29. package/dist/{806.js → 752.js} +1 -1
  30. package/dist/{806.js.map → 752.js.map} +1 -1
  31. package/dist/757.js +1 -1
  32. package/dist/764.js +1 -1
  33. package/dist/764.js.map +1 -1
  34. package/dist/788.js +1 -1
  35. package/dist/{981.js → 800.js} +1 -1
  36. package/dist/{981.js.map → 800.js.map} +1 -1
  37. package/dist/807.js +1 -1
  38. package/dist/{696.js → 828.js} +1 -1
  39. package/dist/{696.js.map → 828.js.map} +1 -1
  40. package/dist/833.js +1 -1
  41. package/dist/877.js +1 -1
  42. package/dist/877.js.map +1 -1
  43. package/dist/917.js +1 -1
  44. package/dist/917.js.map +1 -1
  45. package/dist/kenyaemr-esm-service-queues-app.js +1 -1
  46. package/dist/kenyaemr-esm-service-queues-app.js.buildmanifest.json +193 -193
  47. package/dist/kenyaemr-esm-service-queues-app.js.map +1 -1
  48. package/dist/main.js +1 -1
  49. package/dist/main.js.map +1 -1
  50. package/dist/routes.json +1 -1
  51. package/package.json +2 -2
  52. package/src/add-patient-toqueue/add-patient-toqueue-dialog.component.tsx +4 -4
  53. package/src/add-provider-queue-room/add-provider-queue-room.component.tsx +12 -15
  54. package/src/config-schema.ts +20 -0
  55. package/src/helpers/helpers.ts +42 -32
  56. package/src/home.component.tsx +1 -1
  57. package/src/hooks/useQueueEntries.ts +1 -1
  58. package/src/hooks/useQueueService.ts +21 -0
  59. package/src/hooks/useQueueStatuses.ts +40 -0
  60. package/src/index.ts +5 -5
  61. package/src/patient-info/patient-info.component.tsx +9 -9
  62. package/src/patient-queue-header/patient-queue-header.component.tsx +30 -24
  63. package/src/patient-queue-header/patient-queue-header.scss +1 -2
  64. package/src/patient-queue-metrics/clinic-metrics.component.tsx +16 -27
  65. package/src/patient-queue-metrics/queue-metrics.resource.ts +1 -2
  66. package/src/patient-search/patient-scheduled-visits.scss +1 -1
  67. package/src/patient-search/patient-search.scss +6 -0
  68. package/src/patient-search/patient-search.workspace.tsx +30 -30
  69. package/src/patient-search/visit-form/visit-form.component.tsx +8 -8
  70. package/src/patient-search/visit-form/visit-form.scss +5 -3
  71. package/src/patient-search/visit-form-queue-fields/visit-form-queue-fields.component.tsx +14 -7
  72. package/src/queue-patient-linelists/queue-linelist-filter.scss +2 -12
  73. package/src/queue-rooms/queue-room-form.scss +1 -1
  74. package/src/queue-screen/queue-screen.component.tsx +1 -1
  75. package/src/queue-services/queue-service-form.scss +2 -2
  76. package/src/queue-table/cells/queue-table-action-cell.component.tsx +6 -4
  77. package/src/queue-table/cells/queue-table-action-cell.scss +7 -0
  78. package/src/queue-table/default-queue-table.component.tsx +69 -38
  79. package/src/queue-table/queue-entry-actions/{edit-queue-entry-modal.component.tsx → edit-queue-entry.modal.tsx} +1 -1
  80. package/src/queue-table/queue-entry-actions/{end-queue-entry-modal.component.tsx → end-queue-entry.modal.tsx} +1 -1
  81. package/src/queue-table/queue-entry-actions/{queue-entry-actions-modal.test.tsx → queue-entry-actions.test.tsx} +2 -2
  82. package/src/queue-table/queue-entry-actions/{queue-entry-confirm-action-modal.test.tsx → queue-entry-confirm-action.test.tsx} +3 -3
  83. package/src/queue-table/queue-entry-actions/{queue-entry-undo-actions-modal.test.tsx → queue-entry-undo-actions.test.tsx} +2 -2
  84. package/src/queue-table/queue-entry-actions/{transition-queue-entry-modal.component.tsx → transition-queue-entry.modal.tsx} +1 -1
  85. package/src/queue-table/queue-entry-actions/{undo-transition-queue-entry-modal.component.tsx → undo-transition-queue-entry.modal.tsx} +1 -1
  86. package/src/queue-table/queue-entry-actions/{void-queue-entry-modal.component.tsx → void-queue-entry.modal.tsx} +1 -1
  87. package/src/queue-table/queue-table-by-status-skeleton.component.tsx +18 -18
  88. package/src/queue-table/queue-table-metrics-card.scss +1 -1
  89. package/src/queue-table/queue-table-metrics.scss +1 -1
  90. package/src/queue-table/queue-table.component.tsx +35 -18
  91. package/src/queue-table/queue-table.scss +12 -4
  92. package/src/types/index.ts +3 -1
  93. package/src/views/queue-table-by-status-view.component.tsx +2 -14
  94. package/src/views/queue-tables-for-all-statuses.component.tsx +81 -43
  95. package/translations/am.json +29 -19
  96. package/translations/ar.json +33 -23
  97. package/translations/en.json +3 -2
  98. package/translations/es.json +29 -19
  99. package/translations/fr.json +29 -19
  100. package/translations/he.json +33 -23
  101. package/translations/km.json +31 -21
  102. package/translations/zh.json +39 -29
  103. package/translations/zh_CN.json +38 -28
  104. package/dist/185.js +0 -1
  105. package/dist/185.js.map +0 -1
  106. package/dist/233.js +0 -1
  107. package/dist/233.js.map +0 -1
  108. package/dist/237.js +0 -1
  109. package/dist/237.js.map +0 -1
  110. package/dist/703.js +0 -1
  111. package/dist/703.js.map +0 -1
  112. package/dist/738.js +0 -1
  113. /package/dist/{430.js.LICENSE.txt → 490.js.LICENSE.txt} +0 -0
  114. /package/src/queue-table/queue-entry-actions/{queue-entry-actions-modal.component.tsx → queue-entry-actions.modal.tsx} +0 -0
  115. /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.66"}
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.66",
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 styles from './add-patient-toqueue-dialog.scss';
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 { RadioButtonSkeleton } from '@carbon/react';
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
- updateSelectedServiceName,
29
- updateSelectedServiceUuid,
28
+ updateSelectedService,
30
29
  useIsPermanentProviderQueueRoom,
30
+ useSelectedQueueLocationName,
31
31
  useSelectedQueueLocationUuid,
32
- useSelectedServiceName,
33
- useSelectedServiceUuid,
32
+ useSelectedService,
34
33
  } from '../helpers/helpers';
35
34
  import styles from './add-provider-queue-room.scss';
36
- import { useQueues } from '../hooks/useQueues';
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 = useSelectedServiceName();
45
+ const currentLocationName = useSelectedQueueLocationName();
47
46
  const currentLocationUuid = useSelectedQueueLocationUuid();
48
- const currentServiceUuid = useSelectedServiceUuid();
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 { queues } = useQueues(currentLocationUuid);
64
- const { rooms } = useQueueRooms(currentLocationUuid, currentServiceUuid);
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('queueServiceUuid', selectedItem.uuid);
71
- updateSelectedServiceName(selectedItem.name);
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={queues}
172
+ items={services ?? []}
176
173
  itemToString={(item) => (item ? item.display : '')}
177
174
  onChange={handleServiceChange}
178
175
  size="md"
179
- initialSelectedItem={{ uuid: currentServiceUuid, display: currentServiceName }}
176
+ initialSelectedItem={{ uuid: currentService?.serviceUuid, display: currentService?.serviceDisplay }}
180
177
  />
181
178
  </section>
182
179
 
@@ -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;
@@ -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 getSelectedServiceName() {
29
- return getGlobalStore<{ serviceName: string }>('queueSelectedServiceName', initialServiceNameState);
30
- }
31
-
32
- export function getSelectedServiceUuid() {
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 updateSelectedServiceName = (currentServiceName: string) => {
63
- const store = getSelectedServiceName();
64
- sessionStorage.setItem('queueServiceName', currentServiceName);
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 useSelectedServiceName = () => {
103
- const { t } = useTranslation();
104
- const [currentServiceName, setCurrentServiceName] = useState(initialServiceNameState.serviceName ?? t('all', 'All'));
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 useSelectedServiceUuid = () => {
114
- const [currentServiceUuid, setCurrentServiceUuid] = useState(initialServiceUuidState.serviceUuid);
110
+ export const useSelectedService = () => {
111
+ const [currentService, setCurrentService] = useState(getSelectedService()?.getState());
115
112
 
116
113
  useEffect(() => {
117
- getSelectedServiceUuid().subscribe(({ serviceUuid }) => setCurrentServiceUuid(serviceUuid));
114
+ getSelectedService().subscribe((newSelectedService) => setCurrentService(newSelectedService));
118
115
  }, []);
119
- return currentServiceUuid;
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
+ }
@@ -6,7 +6,7 @@ import DefaultQueueTable from './queue-table/default-queue-table.component';
6
6
  const Home: React.FC = () => {
7
7
  return (
8
8
  <>
9
- <PatientQueueHeader />
9
+ <PatientQueueHeader showLocationDropdown />
10
10
  <ClinicMetrics />
11
11
  <DefaultQueueTable />
12
12
  </>
@@ -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-modal.component'),
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-modal.component'),
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-modal.component'),
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-modal.component'),
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-modal.component'),
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 = displayName(patient);
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 { Calendar, Location } from '@carbon/react/icons';
3
+ import { Location } from '@carbon/react/icons';
4
4
  import { Dropdown } from '@carbon/react';
5
- import { formatDate, useSession } from '@openmrs/esm-framework';
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
- updateSelectedServiceName,
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
- const PatientQueueHeader: React.FC<{ title?: string }> = ({ title }) => {
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
- updateSelectedServiceName('All');
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.header} data-testid="patient-queue-header">
63
- <div className={styles['left-justified-items']}>
64
- <PatientQueueIllustration />
65
- <div className={styles['page-labels']}>
66
- <p>{t('serviceQueues', 'Service queues')}</p>
67
- <p className={styles['page-name']}>{title ?? t('home', 'Home')}</p>
68
- </div>
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['right-justified-items']}>
71
- <div className={styles['date-and-location']}>
72
- <Location size={16} />
73
- <span className={styles.value}>{userLocation}</span>
74
- <span className={styles.middot}>&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
- </div>
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 { queues } = useQueues(currentQueueLocation);
29
- const currentServiceUuid = useSelectedServiceUuid();
30
- const currentServiceName = useSelectedServiceName();
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
- if (currentServiceName && currentServiceUuid) {
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 { queueEntries, totalCount } = useQueueEntries({
42
- queue: currentServiceUuid,
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(currentServiceUuid, '');
37
+ const { waitTime } = useAverageWaitTime(currentService?.serviceUuid, '');
48
38
 
49
39
  const handleServiceChange = ({ selectedItem }) => {
50
- updateSelectedServiceUuid(selectedItem.uuid);
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={currentServiceName}
74
- serviceUuid={currentServiceUuid}
62
+ service={currentService?.serviceDisplay}
63
+ serviceUuid={currentService?.serviceUuid}
75
64
  locationUuid={currentQueueLocation}>
76
65
  <Dropdown
77
66
  id="inline"
78
67
  type="inline"
79
- label={currentServiceName ?? `${t('all', 'All')}`}
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