@kenyaemr/esm-service-queues-app 7.0.2-pre.65

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 (289) hide show
  1. package/.turbo/turbo-build.log +40 -0
  2. package/README.md +20 -0
  3. package/dist/130.js +2 -0
  4. package/dist/130.js.LICENSE.txt +3 -0
  5. package/dist/130.js.map +1 -0
  6. package/dist/152.js +1 -0
  7. package/dist/152.js.map +1 -0
  8. package/dist/169.js +1 -0
  9. package/dist/169.js.map +1 -0
  10. package/dist/185.js +1 -0
  11. package/dist/185.js.map +1 -0
  12. package/dist/233.js +1 -0
  13. package/dist/233.js.map +1 -0
  14. package/dist/237.js +1 -0
  15. package/dist/237.js.map +1 -0
  16. package/dist/255.js +2 -0
  17. package/dist/255.js.LICENSE.txt +9 -0
  18. package/dist/255.js.map +1 -0
  19. package/dist/271.js +1 -0
  20. package/dist/276.js +1 -0
  21. package/dist/276.js.map +1 -0
  22. package/dist/303.js +1 -0
  23. package/dist/303.js.map +1 -0
  24. package/dist/319.js +1 -0
  25. package/dist/401.js +1 -0
  26. package/dist/401.js.map +1 -0
  27. package/dist/430.js +2 -0
  28. package/dist/430.js.LICENSE.txt +50 -0
  29. package/dist/430.js.map +1 -0
  30. package/dist/460.js +1 -0
  31. package/dist/501.js +1 -0
  32. package/dist/501.js.map +1 -0
  33. package/dist/574.js +1 -0
  34. package/dist/591.js +2 -0
  35. package/dist/591.js.LICENSE.txt +32 -0
  36. package/dist/591.js.map +1 -0
  37. package/dist/644.js +1 -0
  38. package/dist/647.js +1 -0
  39. package/dist/647.js.map +1 -0
  40. package/dist/650.js +1 -0
  41. package/dist/650.js.map +1 -0
  42. package/dist/669.js +1 -0
  43. package/dist/669.js.map +1 -0
  44. package/dist/696.js +1 -0
  45. package/dist/696.js.map +1 -0
  46. package/dist/703.js +1 -0
  47. package/dist/703.js.map +1 -0
  48. package/dist/729.js +1 -0
  49. package/dist/729.js.map +1 -0
  50. package/dist/738.js +1 -0
  51. package/dist/738.js.map +1 -0
  52. package/dist/757.js +1 -0
  53. package/dist/764.js +1 -0
  54. package/dist/764.js.map +1 -0
  55. package/dist/784.js +2 -0
  56. package/dist/784.js.LICENSE.txt +9 -0
  57. package/dist/784.js.map +1 -0
  58. package/dist/788.js +1 -0
  59. package/dist/806.js +1 -0
  60. package/dist/806.js.map +1 -0
  61. package/dist/807.js +1 -0
  62. package/dist/833.js +1 -0
  63. package/dist/877.js +1 -0
  64. package/dist/877.js.map +1 -0
  65. package/dist/917.js +1 -0
  66. package/dist/917.js.map +1 -0
  67. package/dist/940.js +1 -0
  68. package/dist/940.js.map +1 -0
  69. package/dist/981.js +1 -0
  70. package/dist/981.js.map +1 -0
  71. package/dist/kenyaemr-esm-service-queues-app.js +1 -0
  72. package/dist/kenyaemr-esm-service-queues-app.js.buildmanifest.json +965 -0
  73. package/dist/kenyaemr-esm-service-queues-app.js.map +1 -0
  74. package/dist/main.js +2 -0
  75. package/dist/main.js.LICENSE.txt +60 -0
  76. package/dist/main.js.map +1 -0
  77. package/dist/routes.json +1 -0
  78. package/jest.config.js +3 -0
  79. package/package.json +54 -0
  80. package/src/active-visits/active-visits-row-actions.component.tsx +25 -0
  81. package/src/active-visits/active-visits-row-actions.scss +4 -0
  82. package/src/active-visits/active-visits-table.resource.ts +273 -0
  83. package/src/active-visits/change-status-dialog.component.tsx +272 -0
  84. package/src/active-visits/change-status-dialog.scss +47 -0
  85. package/src/active-visits/change-status-dialog.test.tsx +154 -0
  86. package/src/add-patient-toqueue/add-patient-toqueue-dialog.component.tsx +228 -0
  87. package/src/add-patient-toqueue/add-patient-toqueue-dialog.scss +32 -0
  88. package/src/add-provider-queue-room/add-provider-queue-room.component.tsx +238 -0
  89. package/src/add-provider-queue-room/add-provider-queue-room.resource.ts +76 -0
  90. package/src/add-provider-queue-room/add-provider-queue-room.scss +17 -0
  91. package/src/add-provider-queue-room/add-provider-queue-room.test.tsx +105 -0
  92. package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.component.tsx +76 -0
  93. package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.resource.ts +7 -0
  94. package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.scss +8 -0
  95. package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.test.tsx +43 -0
  96. package/src/clear-queue-entries-dialog/clear-queue-entries.component.tsx +43 -0
  97. package/src/config-schema.ts +465 -0
  98. package/src/constants.ts +10 -0
  99. package/src/createDashboardLink.component.tsx +39 -0
  100. package/src/current-visit/current-visit-summary.component.tsx +38 -0
  101. package/src/current-visit/current-visit-summary.test.tsx +43 -0
  102. package/src/current-visit/current-visit.resource.ts +84 -0
  103. package/src/current-visit/current-visit.scss +34 -0
  104. package/src/current-visit/hooks/useVitalsConceptMetadata.tsx +101 -0
  105. package/src/current-visit/visit-details/biometrics-config-schema.ts +14 -0
  106. package/src/current-visit/visit-details/current-visit-details.component.tsx +96 -0
  107. package/src/current-visit/visit-details/triage-note.component.tsx +53 -0
  108. package/src/current-visit/visit-details/triage-note.scss +89 -0
  109. package/src/current-visit/visit-details/vitals-config-schema.ts +17 -0
  110. package/src/current-visit/visit-details/vitals.component.tsx +165 -0
  111. package/src/dashboard.meta.ts +5 -0
  112. package/src/declarations.d.ts +4 -0
  113. package/src/helpers/functions.ts +28 -0
  114. package/src/helpers/helpers.ts +177 -0
  115. package/src/helpers/time-helpers.ts +15 -0
  116. package/src/home.component.tsx +16 -0
  117. package/src/home.test.tsx +48 -0
  118. package/src/hooks/useConcept.ts +13 -0
  119. package/src/hooks/useQueue.ts +10 -0
  120. package/src/hooks/useQueueEntries.ts +187 -0
  121. package/src/hooks/useQueues.ts +22 -0
  122. package/src/hooks/useSystemSetting.ts +18 -0
  123. package/src/index.ts +172 -0
  124. package/src/past-visit/past-visit-details/encounter-list.component.tsx +54 -0
  125. package/src/past-visit/past-visit-details/medications-list.component.tsx +98 -0
  126. package/src/past-visit/past-visit-details/notes-list.component.tsx +41 -0
  127. package/src/past-visit/past-visit-details/past-visit-summary.component.tsx +181 -0
  128. package/src/past-visit/past-visit-details/past-visit-summary.scss +58 -0
  129. package/src/past-visit/past-visit.component.tsx +37 -0
  130. package/src/past-visit/past-visit.resource.ts +83 -0
  131. package/src/past-visit/past-visit.scss +126 -0
  132. package/src/past-visit/past-visit.test.tsx +41 -0
  133. package/src/patient-info/appointment-details.component.tsx +98 -0
  134. package/src/patient-info/appointment-details.scss +34 -0
  135. package/src/patient-info/appointment-details.test.tsx +36 -0
  136. package/src/patient-info/appointments.resource.ts +43 -0
  137. package/src/patient-info/hooks/usePatientAttributes.tsx +42 -0
  138. package/src/patient-info/patient-info.component.tsx +82 -0
  139. package/src/patient-info/patient-info.scss +60 -0
  140. package/src/patient-info/patient-info.test.tsx +43 -0
  141. package/src/patient-queue-header/patient-queue-header.component.tsx +99 -0
  142. package/src/patient-queue-header/patient-queue-header.scss +90 -0
  143. package/src/patient-queue-header/patient-queue-illustration.component.tsx +22 -0
  144. package/src/patient-queue-metrics/clinic-metrics.component.tsx +98 -0
  145. package/src/patient-queue-metrics/clinic-metrics.resource.ts +58 -0
  146. package/src/patient-queue-metrics/clinic-metrics.scss +11 -0
  147. package/src/patient-queue-metrics/clinic-metrics.test.tsx +76 -0
  148. package/src/patient-queue-metrics/metrics-card.component.tsx +68 -0
  149. package/src/patient-queue-metrics/metrics-card.scss +80 -0
  150. package/src/patient-queue-metrics/metrics-header.component.tsx +61 -0
  151. package/src/patient-queue-metrics/metrics-header.scss +26 -0
  152. package/src/patient-queue-metrics/queue-metrics.resource.ts +42 -0
  153. package/src/patient-search/advanced-search.component.tsx +191 -0
  154. package/src/patient-search/advanced-search.scss +154 -0
  155. package/src/patient-search/advanced-search.test.tsx +29 -0
  156. package/src/patient-search/basic-search.component.tsx +112 -0
  157. package/src/patient-search/basic-search.scss +139 -0
  158. package/src/patient-search/basic-search.test.tsx +23 -0
  159. package/src/patient-search/empty-data-illustration.component.tsx +41 -0
  160. package/src/patient-search/hooks/useActivePatientEnrollment.tsx +29 -0
  161. package/src/patient-search/hooks/useDefaultLocation.ts +14 -0
  162. package/src/patient-search/hooks/usePatients.tsx +25 -0
  163. package/src/patient-search/hooks/useQueueLocations.tsx +23 -0
  164. package/src/patient-search/hooks/useRecommendedVisitTypes.tsx +35 -0
  165. package/src/patient-search/hooks/useScheduledVisits.ts +52 -0
  166. package/src/patient-search/patient-scheduled-visits.component.tsx +324 -0
  167. package/src/patient-search/patient-scheduled-visits.scss +131 -0
  168. package/src/patient-search/patient-scheduled-visits.test.tsx +44 -0
  169. package/src/patient-search/patient-search.scss +43 -0
  170. package/src/patient-search/patient-search.workspace.tsx +135 -0
  171. package/src/patient-search/search-illustration.component.tsx +27 -0
  172. package/src/patient-search/search-results.component.tsx +75 -0
  173. package/src/patient-search/search-results.scss +80 -0
  174. package/src/patient-search/search-results.test.tsx +77 -0
  175. package/src/patient-search/search.resource.ts +10 -0
  176. package/src/patient-search/visit-form/existing-visit-form.component.tsx +112 -0
  177. package/src/patient-search/visit-form/queue.resource.ts +64 -0
  178. package/src/patient-search/visit-form/visit-form.component.tsx +344 -0
  179. package/src/patient-search/visit-form/visit-form.scss +73 -0
  180. package/src/patient-search/visit-form/visit-type-selector.component.tsx +155 -0
  181. package/src/patient-search/visit-form/visit-type-selector.scss +100 -0
  182. package/src/patient-search/visit-form/visit-type-selector.test.tsx +83 -0
  183. package/src/patient-search/visit-form-queue-fields/visit-form-queue-fields.component.tsx +178 -0
  184. package/src/patient-search/visit-form-queue-fields/visit-form-queue-fields.scss +19 -0
  185. package/src/patient-search/visit-form-queue-fields/visit-form-queue-fields.test.tsx +63 -0
  186. package/src/queue-entry-table-components/edit-entry.scss +14 -0
  187. package/src/queue-entry-table-components/queue-duration.component.tsx +41 -0
  188. package/src/queue-entry-table-components/queue-priority.component.tsx +38 -0
  189. package/src/queue-entry-table-components/queue-priority.scss +12 -0
  190. package/src/queue-entry-table-components/queue-status.component.tsx +39 -0
  191. package/src/queue-entry-table-components/transition-entry.component.tsx +55 -0
  192. package/src/queue-entry-table-components/transition-entry.scss +22 -0
  193. package/src/queue-patient-linelists/queue-linelist-base-table.component.tsx +241 -0
  194. package/src/queue-patient-linelists/queue-linelist-base-table.scss +110 -0
  195. package/src/queue-patient-linelists/queue-linelist-base-table.test.tsx +93 -0
  196. package/src/queue-patient-linelists/queue-linelist-filter.scss +63 -0
  197. package/src/queue-patient-linelists/queue-linelist-filter.test.tsx +94 -0
  198. package/src/queue-patient-linelists/queue-linelist-filter.workspace.tsx +185 -0
  199. package/src/queue-patient-linelists/queue-linelist.resource.ts +84 -0
  200. package/src/queue-patient-linelists/queue-services-table.component.tsx +63 -0
  201. package/src/queue-patient-linelists/scheduled-appointments-table.component.tsx +305 -0
  202. package/src/queue-patient-linelists/scheduled-appointments-table.test.tsx +41 -0
  203. package/src/queue-rooms/queue-room-form.scss +56 -0
  204. package/src/queue-rooms/queue-room-form.test.tsx +80 -0
  205. package/src/queue-rooms/queue-room-form.workspace.tsx +169 -0
  206. package/src/queue-rooms/queue-room.resource.ts +20 -0
  207. package/src/queue-screen/queue-screen.component.tsx +47 -0
  208. package/src/queue-screen/queue-screen.scss +39 -0
  209. package/src/queue-screen/queue-screen.test.tsx +51 -0
  210. package/src/queue-screen/useActiveTickets.tsx +13 -0
  211. package/src/queue-services/queue-service-form.scss +61 -0
  212. package/src/queue-services/queue-service-form.test.tsx +60 -0
  213. package/src/queue-services/queue-service-form.workspace.tsx +179 -0
  214. package/src/queue-services/queue-service.resource.ts +33 -0
  215. package/src/queue-table/cells/columns.resource.ts +135 -0
  216. package/src/queue-table/cells/queue-table-action-cell.component.tsx +88 -0
  217. package/src/queue-table/cells/queue-table-action-cell.scss +7 -0
  218. package/src/queue-table/cells/queue-table-coming-from-cell.component.tsx +13 -0
  219. package/src/queue-table/cells/queue-table-extension-cell.component.tsx +16 -0
  220. package/src/queue-table/cells/queue-table-name-cell.component.tsx +20 -0
  221. package/src/queue-table/cells/queue-table-patient-age-cell.component.tsx +18 -0
  222. package/src/queue-table/cells/queue-table-patient-identifier-cell.component.tsx +25 -0
  223. package/src/queue-table/cells/queue-table-priority-cell.component.tsx +23 -0
  224. package/src/queue-table/cells/queue-table-queue-name-cell.component.tsx +14 -0
  225. package/src/queue-table/cells/queue-table-status-cell.component.tsx +18 -0
  226. package/src/queue-table/cells/queue-table-visit-attribute-queue-number-cell.component.tsx +37 -0
  227. package/src/queue-table/cells/queue-table-visit-start-time-cell.component.tsx +20 -0
  228. package/src/queue-table/cells/queue-table-wait-time-cell.component.tsx +17 -0
  229. package/src/queue-table/default-queue-table.component.tsx +174 -0
  230. package/src/queue-table/default-queue-table.test.tsx +131 -0
  231. package/src/queue-table/queue-entry-actions/edit-queue-entry-modal.component.tsx +52 -0
  232. package/src/queue-table/queue-entry-actions/end-queue-entry-modal.component.tsx +39 -0
  233. package/src/queue-table/queue-entry-actions/queue-entry-actions-modal.component.tsx +362 -0
  234. package/src/queue-table/queue-entry-actions/queue-entry-actions-modal.test.tsx +152 -0
  235. package/src/queue-table/queue-entry-actions/queue-entry-actions.resource.ts +83 -0
  236. package/src/queue-table/queue-entry-actions/queue-entry-actons-modal.scss +36 -0
  237. package/src/queue-table/queue-entry-actions/queue-entry-confirm-action-modal.component.tsx +97 -0
  238. package/src/queue-table/queue-entry-actions/queue-entry-confirm-action-modal.test.tsx +106 -0
  239. package/src/queue-table/queue-entry-actions/queue-entry-undo-actions-modal.test.tsx +76 -0
  240. package/src/queue-table/queue-entry-actions/transition-queue-entry-modal.component.tsx +51 -0
  241. package/src/queue-table/queue-entry-actions/undo-transition-queue-entry-modal.component.tsx +58 -0
  242. package/src/queue-table/queue-entry-actions/void-queue-entry-modal.component.tsx +34 -0
  243. package/src/queue-table/queue-table-by-status-menu.component.tsx +42 -0
  244. package/src/queue-table/queue-table-by-status-menu.scss +11 -0
  245. package/src/queue-table/queue-table-by-status-skeleton.component.tsx +32 -0
  246. package/src/queue-table/queue-table-by-status.component.tsx +96 -0
  247. package/src/queue-table/queue-table-expanded-row.component.tsx +29 -0
  248. package/src/queue-table/queue-table-metrics-card.component.tsx +50 -0
  249. package/src/queue-table/queue-table-metrics-card.scss +48 -0
  250. package/src/queue-table/queue-table-metrics.component.tsx +30 -0
  251. package/src/queue-table/queue-table-metrics.scss +11 -0
  252. package/src/queue-table/queue-table.component.tsx +179 -0
  253. package/src/queue-table/queue-table.scss +192 -0
  254. package/src/queue-table/queue-table.test.tsx +210 -0
  255. package/src/remove-queue-entry-dialog/remove-queue-entry.component.tsx +87 -0
  256. package/src/remove-queue-entry-dialog/remove-queue-entry.resource.ts +93 -0
  257. package/src/remove-queue-entry-dialog/remove-queue-entry.scss +7 -0
  258. package/src/remove-queue-entry-dialog/remove-queue-entry.test.tsx +45 -0
  259. package/src/root.component.tsx +28 -0
  260. package/src/root.scss +15 -0
  261. package/src/root.test.tsx +24 -0
  262. package/src/routes.json +133 -0
  263. package/src/side-menu/nav-group/createNavGroup.tsx +17 -0
  264. package/src/side-menu/nav-group/nav-group.component.tsx +24 -0
  265. package/src/side-menu/nav-group/nav-group.test.tsx +32 -0
  266. package/src/side-menu/nav-group/nav-group.ts +10 -0
  267. package/src/side-menu/side-menu.component.tsx +6 -0
  268. package/src/side-menu/side-menu.test.tsx +17 -0
  269. package/src/transition-queue-entry/transition-queue-entry-dialog.component.tsx +134 -0
  270. package/src/transition-queue-entry/transition-queue-entry-dialog.scss +12 -0
  271. package/src/transition-queue-entry/transition-queue-entry-dialog.test.tsx +102 -0
  272. package/src/transition-queue-entry/transition-queue-entry.resource.ts +16 -0
  273. package/src/types/index.ts +494 -0
  274. package/src/views/queue-table-by-status-view.component.tsx +25 -0
  275. package/src/views/queue-tables-for-all-statuses.component.tsx +150 -0
  276. package/src/visits-missing-inqueue/visits-missing-inqueue.component.tsx +277 -0
  277. package/src/visits-missing-inqueue/visits-missing-inqueue.resource.ts +93 -0
  278. package/src/visits-missing-inqueue/visits-missing-inqueue.scss +108 -0
  279. package/translations/am.json +295 -0
  280. package/translations/ar.json +295 -0
  281. package/translations/en.json +305 -0
  282. package/translations/es.json +295 -0
  283. package/translations/fr.json +295 -0
  284. package/translations/he.json +295 -0
  285. package/translations/km.json +295 -0
  286. package/translations/zh.json +295 -0
  287. package/translations/zh_CN.json +295 -0
  288. package/tsconfig.json +5 -0
  289. package/webpack.config.js +1 -0
@@ -0,0 +1,177 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { getGlobalStore } from '@openmrs/esm-framework';
3
+ import type { AppointmentSummary } from '../types';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ export const getServiceCountByAppointmentType = (
7
+ appointmentSummary: Array<AppointmentSummary>,
8
+ appointmentType: string,
9
+ ) => {
10
+ return appointmentSummary
11
+ .map((appointment) =>
12
+ Object.entries(appointment.appointmentCountMap).flatMap((appointment) => appointment[1][appointmentType]),
13
+ )
14
+ .flat(1)
15
+ .reduce((count, val) => count + val, 0);
16
+ };
17
+
18
+ const initialServiceNameState = { serviceName: sessionStorage.getItem('queueServiceName') };
19
+ const initialServiceUuidState = { serviceUuid: sessionStorage.getItem('queueServiceUuid') };
20
+ const intialStatusNameState = { status: '' };
21
+ const initialQueueLocationNameState = { queueLocationName: sessionStorage.getItem('queueLocationName') };
22
+ const initialQueueLocationUuidState = { queueLocationUuid: sessionStorage.getItem('queueLocationUuid') };
23
+ const initialSelectedQueueRoomTimestamp = { providerQueueRoomTimestamp: new Date() };
24
+ const initialPermanentProviderQueueRoomState = {
25
+ isPermanentProviderQueueRoom: sessionStorage.getItem('isPermanentProviderQueueRoom'),
26
+ };
27
+
28
+ export function getSelectedServiceName() {
29
+ return getGlobalStore<{ serviceName: string }>('queueSelectedServiceName', initialServiceNameState);
30
+ }
31
+
32
+ export function getSelectedServiceUuid() {
33
+ return getGlobalStore<{ serviceUuid: string }>('queueSelectedServiceUuid', initialServiceUuidState);
34
+ }
35
+
36
+ export function getSelectedAppointmentStatus() {
37
+ return getGlobalStore<{ status: string }>('appointmentSelectedStatus', intialStatusNameState);
38
+ }
39
+
40
+ export function getSelectedQueueLocationName() {
41
+ return getGlobalStore<{ queueLocationName: string }>('queueLocationNameSelected', initialQueueLocationNameState);
42
+ }
43
+
44
+ export function getSelectedQueueLocationUuid() {
45
+ return getGlobalStore<{ queueLocationUuid: string }>('queueLocationUuidSelected', initialQueueLocationUuidState);
46
+ }
47
+
48
+ export function getSelectedQueueRoomTimestamp() {
49
+ return getGlobalStore<{ providerQueueRoomTimestamp: Date }>(
50
+ 'queueProviderRoomTimestamp',
51
+ initialSelectedQueueRoomTimestamp,
52
+ );
53
+ }
54
+
55
+ export function getIsPermanentProviderQueueRoom() {
56
+ return getGlobalStore<{ isPermanentProviderQueueRoom: string }>(
57
+ 'isPermanentProviderQueueRoom',
58
+ initialPermanentProviderQueueRoomState,
59
+ );
60
+ }
61
+
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
+ sessionStorage.setItem('queueServiceUuid', currentServiceUuid);
71
+ store.setState({ serviceUuid: currentServiceUuid });
72
+ };
73
+
74
+ export const updateSelectedAppointmentStatus = (currentAppointmentStatus: string) => {
75
+ const store = getSelectedAppointmentStatus();
76
+ store.setState({ status: currentAppointmentStatus });
77
+ };
78
+
79
+ export const updateSelectedQueueLocationName = (currentLocationName: string) => {
80
+ const store = getSelectedQueueLocationName();
81
+ sessionStorage.setItem('queueLocationName', currentLocationName);
82
+ store.setState({ queueLocationName: currentLocationName });
83
+ };
84
+
85
+ export const updateSelectedQueueLocationUuid = (currentLocationUuid: string) => {
86
+ const store = getSelectedQueueLocationUuid();
87
+ sessionStorage.setItem('queueLocationUuid', currentLocationUuid);
88
+ store.setState({ queueLocationUuid: currentLocationUuid });
89
+ };
90
+
91
+ export const updatedSelectedQueueRoomTimestamp = (currentProviderRoomTimestamp: Date) => {
92
+ const store = getSelectedQueueRoomTimestamp();
93
+ store.setState({ providerQueueRoomTimestamp: currentProviderRoomTimestamp });
94
+ };
95
+
96
+ export const updateIsPermanentProviderQueueRoom = (currentIsPermanentProviderQueueRoom) => {
97
+ const store = getIsPermanentProviderQueueRoom();
98
+ sessionStorage.setItem('isPermanentProviderQueueRoom', currentIsPermanentProviderQueueRoom);
99
+ store.setState({ isPermanentProviderQueueRoom: currentIsPermanentProviderQueueRoom });
100
+ };
101
+
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;
111
+ };
112
+
113
+ export const useSelectedServiceUuid = () => {
114
+ const [currentServiceUuid, setCurrentServiceUuid] = useState(initialServiceUuidState.serviceUuid);
115
+
116
+ useEffect(() => {
117
+ getSelectedServiceUuid().subscribe(({ serviceUuid }) => setCurrentServiceUuid(serviceUuid));
118
+ }, []);
119
+ return currentServiceUuid;
120
+ };
121
+
122
+ export const useSelectedAppointmentStatus = () => {
123
+ const [currentAppointmentStatus, setCurrentAppointmentStatus] = useState(intialStatusNameState.status);
124
+
125
+ useEffect(() => {
126
+ getSelectedAppointmentStatus().subscribe(({ status }) => setCurrentAppointmentStatus(status));
127
+ }, []);
128
+ return currentAppointmentStatus;
129
+ };
130
+
131
+ export const useSelectedQueueLocationName = () => {
132
+ const [currentQueueLocationName, setCurrentQueueLocationName] = useState(
133
+ initialQueueLocationNameState.queueLocationName,
134
+ );
135
+
136
+ useEffect(() => {
137
+ getSelectedQueueLocationName().subscribe(({ queueLocationName }) => setCurrentQueueLocationName(queueLocationName));
138
+ }, []);
139
+ return currentQueueLocationName;
140
+ };
141
+
142
+ export const useSelectedQueueLocationUuid = () => {
143
+ const [currentQueueLocationUuid, setCurrentQueueLocationUuid] = useState(
144
+ initialQueueLocationUuidState.queueLocationUuid,
145
+ );
146
+
147
+ useEffect(() => {
148
+ getSelectedQueueLocationUuid().subscribe(({ queueLocationUuid }) => setCurrentQueueLocationUuid(queueLocationUuid));
149
+ }, []);
150
+ return currentQueueLocationUuid;
151
+ };
152
+
153
+ export const useSelectedProviderRoomTimestamp = () => {
154
+ const [currentProviderRoomTimestamp, setCurrentProviderRoomTimestamp] = useState(
155
+ initialSelectedQueueRoomTimestamp.providerQueueRoomTimestamp,
156
+ );
157
+
158
+ useEffect(() => {
159
+ getSelectedQueueRoomTimestamp().subscribe(({ providerQueueRoomTimestamp }) =>
160
+ setCurrentProviderRoomTimestamp(providerQueueRoomTimestamp),
161
+ );
162
+ }, []);
163
+ return currentProviderRoomTimestamp;
164
+ };
165
+
166
+ export const useIsPermanentProviderQueueRoom = () => {
167
+ const [currentIsPermanentProviderQueueRoom, setCurrentIsPermanentProviderQueueRoom] = useState(
168
+ initialPermanentProviderQueueRoomState.isPermanentProviderQueueRoom,
169
+ );
170
+
171
+ useEffect(() => {
172
+ getIsPermanentProviderQueueRoom().subscribe(({ isPermanentProviderQueueRoom }) =>
173
+ setCurrentIsPermanentProviderQueueRoom(isPermanentProviderQueueRoom),
174
+ );
175
+ }, []);
176
+ return currentIsPermanentProviderQueueRoom;
177
+ };
@@ -0,0 +1,15 @@
1
+ export type amPm = 'AM' | 'PM';
2
+
3
+ export const convertTime12to24 = (time12h, timeFormat: amPm) => {
4
+ let [hours, minutes] = time12h.split(':');
5
+
6
+ if (hours === '12' && timeFormat === 'AM') {
7
+ hours = '00';
8
+ }
9
+
10
+ if (timeFormat === 'PM') {
11
+ hours = hours === '12' ? hours : parseInt(hours, 10) + 12;
12
+ }
13
+
14
+ return [hours, minutes];
15
+ };
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import PatientQueueHeader from './patient-queue-header/patient-queue-header.component';
3
+ import ClinicMetrics from './patient-queue-metrics/clinic-metrics.component';
4
+ import DefaultQueueTable from './queue-table/default-queue-table.component';
5
+
6
+ const Home: React.FC = () => {
7
+ return (
8
+ <>
9
+ <PatientQueueHeader />
10
+ <ClinicMetrics />
11
+ <DefaultQueueTable />
12
+ </>
13
+ );
14
+ };
15
+
16
+ export default Home;
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import Home from './home.component';
4
+ import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
5
+ import { configSchema } from './config-schema';
6
+
7
+ const mockedUseConfig = useConfig as jest.Mock;
8
+
9
+ mockedUseConfig.mockReturnValue({
10
+ ...getDefaultsFromConfigSchema(configSchema),
11
+ concepts: {
12
+ visitQueueNumberAttributeUuid: 'c61ce16f-272a-41e7-9924-4c555d0932c5',
13
+ },
14
+ });
15
+
16
+ jest.mock('./helpers/helpers', () => ({
17
+ ...jest.requireActual('./helpers/helpers'),
18
+ useSelectedQueueLocationName: jest.fn(() => 'Test Location'),
19
+ }));
20
+
21
+ describe('Home Component', () => {
22
+ it('renders PatientQueueHeader, ClinicMetrics when activeTicketScreen is not "screen"', () => {
23
+ // Mock window.location.pathname
24
+ const originalLocation = window.location;
25
+ delete window.location;
26
+ window.location = { pathname: '/some-path' };
27
+
28
+ render(<Home />);
29
+
30
+ // Assert that the expected components are rendered
31
+ expect(screen.getByTestId('patient-queue-header')).toBeInTheDocument();
32
+ expect(screen.getByTestId('clinic-metrics')).toBeInTheDocument();
33
+
34
+ // Clean up the mock
35
+ window.location = originalLocation;
36
+ });
37
+
38
+ it('renders QueueScreen when activeTicketScreen is "screen"', () => {
39
+ const originalLocation = window.location;
40
+ delete window.location;
41
+ window.location = { pathname: '/some-path/screen' };
42
+
43
+ render(<Home />);
44
+ expect(screen.getByText(/patients currently in queue/i)).toBeInTheDocument();
45
+
46
+ window.location = originalLocation;
47
+ });
48
+ });
@@ -0,0 +1,13 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import useSWRImmutable from 'swr/immutable';
3
+ import { type Concept } from '../types';
4
+
5
+ export function useConcept(uuid: string) {
6
+ const apiUrl = uuid ? `${restBaseUrl}/concept/${uuid}` : undefined;
7
+ const { data, error, isLoading } = useSWRImmutable<{ data: Concept }, Error>(apiUrl, openmrsFetch);
8
+ return {
9
+ concept: data?.data,
10
+ error: error,
11
+ isLoading: isLoading,
12
+ };
13
+ }
@@ -0,0 +1,10 @@
1
+ import { useQueues } from './useQueues';
2
+
3
+ export function useQueue(queueUuid?: string) {
4
+ const { queues, ...rest } = useQueues();
5
+
6
+ return {
7
+ queue: queues.find((q) => q.uuid == queueUuid),
8
+ ...rest,
9
+ };
10
+ }
@@ -0,0 +1,187 @@
1
+ import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { type QueueEntry, type QueueEntrySearchCriteria } from '../types';
3
+ import useSWR from 'swr';
4
+ import { useCallback, useEffect, useMemo, useState } from 'react';
5
+ import { useSWRConfig } from 'swr/_internal';
6
+
7
+ type QueueEntryResponse = FetchResponse<{
8
+ results: Array<QueueEntry>;
9
+ links: Array<{
10
+ rel: 'prev' | 'next';
11
+ uri: string;
12
+ }>;
13
+ totalCount: number;
14
+ }>;
15
+
16
+ const queueEntryBaseUrl = `${restBaseUrl}/queue-entry`;
17
+
18
+ const repString =
19
+ 'custom:(uuid,display,queue,status,patient:(uuid,display,person,identifiers:(uuid,display,identifier,identifierType)),visit:(uuid,display,startDatetime,encounters:(uuid,display,diagnoses,encounterDatetime,encounterType,obs,encounterProviders,voided),attributes:(uuid,display,value,attributeType)),priority,priorityComment,sortWeight,startedAt,endedAt,locationWaitingFor,queueComingFrom,providerWaitingFor,previousQueueEntry)';
20
+
21
+ function getInitialUrl(rep: string, searchCriteria?: QueueEntrySearchCriteria) {
22
+ const searchParam = new URLSearchParams();
23
+ searchParam.append('v', rep);
24
+ searchParam.append('totalCount', 'true');
25
+
26
+ if (searchCriteria) {
27
+ for (let [key, value] of Object.entries(searchCriteria)) {
28
+ if (value != null) {
29
+ searchParam.append(key, value?.toString());
30
+ }
31
+ }
32
+ }
33
+
34
+ return `${queueEntryBaseUrl}?${searchParam.toString()}`;
35
+ }
36
+
37
+ function getNextUrlFromResponse(data: QueueEntryResponse) {
38
+ const next = data?.data?.links?.find((link) => link.rel === 'next');
39
+ if (next) {
40
+ const nextUrl = new URL(next.uri);
41
+ // default for production
42
+ if (nextUrl.origin === window.location.origin) {
43
+ return nextUrl.toString();
44
+ }
45
+
46
+ // in development, the request should be routed through the local proxy
47
+ return new URL(`${nextUrl.pathname}${nextUrl.search ? nextUrl.search : ''}`, window.location.origin).toString();
48
+ }
49
+ // There's no next URL
50
+ return null;
51
+ }
52
+
53
+ export function useMutateQueueEntries() {
54
+ const { mutate } = useSWRConfig();
55
+
56
+ return {
57
+ mutateQueueEntries: () => {
58
+ return mutate((key) => {
59
+ return (
60
+ typeof key === 'string' &&
61
+ (key.includes(`${restBaseUrl}/queue-entry`) || key.includes(`${restBaseUrl}/visit-queue-entry`))
62
+ );
63
+ }).then(() => {
64
+ window.dispatchEvent(new CustomEvent('queue-entry-updated'));
65
+ });
66
+ },
67
+ };
68
+ }
69
+
70
+ export function useQueueEntries(searchCriteria?: QueueEntrySearchCriteria, rep: string = repString) {
71
+ // This manually implements a kind of pagination using the useSWR hook. It does not use useSWRInfinite
72
+ // because useSWRInfinite does not support with `mutate`. The hook starts by fetching the first page,
73
+ // page zero, waits until data is fetched, then fetches the next page, and so on.
74
+ //
75
+ // Fine so far. Where things get complicated is in supporting mutation. When a mutation is made, the
76
+ // SWR hook first returns stale data with `isValidating` set to false. At this point we say we are
77
+ // "waiting for mutate," because we have called mutate, but the useSWR hook hasn't updated properly
78
+ // for it yet. Next it returns stale data again, this time with `isValidating` set to true. At this
79
+ // point we say we are no longer waiting for mutate. Finally, it returns fresh data with `isValidating`
80
+ // again set to false. We may then update the data array and move on to the next page.
81
+ const [data, setData] = useState<Array<Array<QueueEntry>>>([]);
82
+ const [totalCount, setTotalCount] = useState<number>();
83
+ const [currentPage, setCurrentPage] = useState<number>(0);
84
+ const [pageUrl, setPageUrl] = useState<string>(getInitialUrl(rep, searchCriteria));
85
+ const [error, setError] = useState<Error>();
86
+ const { mutateQueueEntries } = useMutateQueueEntries();
87
+ const [waitingForMutate, setWaitingForMutate] = useState(false);
88
+
89
+ const { data: pageData, isValidating, error: pageError } = useSWR<QueueEntryResponse, Error>(pageUrl, openmrsFetch);
90
+
91
+ useEffect(() => {
92
+ const nextUrl = getNextUrlFromResponse(pageData);
93
+ const stillWaitingForMutate = waitingForMutate && !isValidating;
94
+ if (waitingForMutate && isValidating) {
95
+ setWaitingForMutate(false);
96
+ }
97
+ if (pageData && !isValidating && !stillWaitingForMutate) {
98
+ // We've got results! Time to update the data array and move on to the next page.
99
+ if (pageData?.data?.totalCount && pageData?.data?.totalCount !== totalCount) {
100
+ setTotalCount(pageData?.data?.totalCount);
101
+ }
102
+ if (pageData?.data?.results?.length) {
103
+ const newData = [...data];
104
+ newData[currentPage] = pageData?.data?.results;
105
+ setData(newData);
106
+ }
107
+ setCurrentPage(currentPage + 1);
108
+ setPageUrl(nextUrl);
109
+ // If we're mutating existing data, then we again need to wait for the mutate to work,
110
+ // since useSWR will (again) first return stale data with isValidating set to false.
111
+ const inMutateMode = data.length > currentPage;
112
+ if (inMutateMode && nextUrl) {
113
+ setWaitingForMutate(true);
114
+ }
115
+ }
116
+ // It may happen that there are fewer pages in the new data than in the old data. In this
117
+ // case, we need to remove the extra pages, which are stored on the `data` array.
118
+ // Note that since we mutated the `data` state earlier in this function, it is important to
119
+ // use the functional form of `setData` so as not to use the stale `data` state.
120
+ if (!nextUrl) {
121
+ // I will not be very suprised if there is an off-by-one error here.
122
+ if (data.length > currentPage + 1) {
123
+ setData((prevData) => {
124
+ const newData = [...prevData];
125
+ newData.splice(currentPage + 1);
126
+ return newData;
127
+ });
128
+ }
129
+ }
130
+ }, [pageData, data, currentPage, totalCount, waitingForMutate, isValidating]);
131
+
132
+ useEffect(() => {
133
+ // An error to one is an error to all
134
+ if (pageError) {
135
+ setError(pageError);
136
+ }
137
+ }, [pageError]);
138
+
139
+ const queueUpdateListener = useCallback(() => {
140
+ setWaitingForMutate(true);
141
+ setCurrentPage(0);
142
+ setPageUrl(getInitialUrl(rep, searchCriteria));
143
+ }, [rep, searchCriteria]);
144
+
145
+ useEffect(() => {
146
+ window.addEventListener('queue-entry-updated', queueUpdateListener);
147
+ return () => {
148
+ window.removeEventListener('queue-entry-updated', queueUpdateListener);
149
+ };
150
+ }, [queueUpdateListener]);
151
+
152
+ const queueEntries = useMemo(() => data.flat(), [data]);
153
+
154
+ return {
155
+ queueEntries,
156
+ totalCount,
157
+ isLoading: totalCount && queueEntries.length < totalCount,
158
+ isValidating: isValidating || currentPage < data.length,
159
+ error,
160
+ mutate: mutateQueueEntries,
161
+ };
162
+ }
163
+
164
+ export function useQueueEntriesMetrics(searchCriteria?: QueueEntrySearchCriteria) {
165
+ const searchParam = new URLSearchParams();
166
+ for (let [key, value] of Object.entries(searchCriteria)) {
167
+ if (value != null) {
168
+ searchParam.append(key, value?.toString());
169
+ }
170
+ }
171
+ const apiUrl = `${restBaseUrl}/queue-entry-metrics?` + searchParam.toString();
172
+
173
+ const { data } = useSWR<
174
+ {
175
+ data: {
176
+ count: number;
177
+ averageWaitTime: number;
178
+ };
179
+ },
180
+ Error
181
+ >(apiUrl, openmrsFetch);
182
+
183
+ return {
184
+ count: data ? data?.data?.count : 0,
185
+ averageWaitTime: data?.data?.averageWaitTime,
186
+ };
187
+ }
@@ -0,0 +1,22 @@
1
+ import { getLocale, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import useSWRImmutable from 'swr/immutable';
3
+ import { type Queue } from '../types';
4
+ import { useMemo } from 'react';
5
+
6
+ export function useQueues(locationUuid?: string) {
7
+ const customRepresentation =
8
+ 'custom:(uuid,display,name,description,service:(uuid,display),allowedPriorities:(uuid,display),allowedStatuses:(uuid,display),location:(uuid,display))';
9
+ const apiUrl = `${restBaseUrl}/queue?v=${customRepresentation}` + (locationUuid ? `&location=${locationUuid}` : '');
10
+
11
+ const { data, ...rest } = useSWRImmutable<{ data: { results: Array<Queue> } }, Error>(apiUrl, openmrsFetch);
12
+
13
+ const queues = useMemo(
14
+ () => data?.data?.results.sort((a, b) => a.display.localeCompare(b.display, getLocale())) ?? [],
15
+ [data?.data?.results],
16
+ );
17
+
18
+ return {
19
+ queues,
20
+ ...rest,
21
+ };
22
+ }
@@ -0,0 +1,18 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import useSWRImmutable from 'swr/immutable';
3
+
4
+ export interface SystemSetting {
5
+ uuid: string;
6
+ property: string;
7
+ value: string;
8
+ }
9
+
10
+ export function useSystemSetting(setting: string) {
11
+ const apiUrl = `${restBaseUrl}/systemsetting/${setting}?v=custom:(value)`;
12
+ const { data, error, isLoading } = useSWRImmutable<{ data: SystemSetting }, Error>(apiUrl, openmrsFetch);
13
+ return {
14
+ systemSetting: data?.data,
15
+ error: error,
16
+ isLoading: isLoading,
17
+ };
18
+ }
package/src/index.ts ADDED
@@ -0,0 +1,172 @@
1
+ import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle, registerBreadcrumbs } from '@openmrs/esm-framework';
2
+ import { configSchema } from './config-schema';
3
+ import { createDashboardLink } from './createDashboardLink.component';
4
+ import { dashboardMeta } from './dashboard.meta';
5
+ import rootComponent from './root.component';
6
+ import queueTableByStatusMenuComponent from './queue-table/queue-table-by-status-menu.component';
7
+ import appointmentListComponent from './queue-patient-linelists/scheduled-appointments-table.component';
8
+ import queueListComponent from './queue-patient-linelists/queue-services-table.component';
9
+ import outpatientSideNavComponent from './side-menu/side-menu.component';
10
+ import homeDashboardComponent from './home.component';
11
+ import patientInfoBannerSlotComponent from './patient-info/patient-info.component';
12
+ import pastVisitSummaryComponent from './past-visit/past-visit.component';
13
+ import VisitFormQueueFields from './patient-search/visit-form-queue-fields/visit-form-queue-fields.component';
14
+
15
+ export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
16
+
17
+ const moduleName = '@kenyaemr/esm-service-queues-app';
18
+
19
+ const options = {
20
+ featureName: 'outpatient',
21
+ moduleName,
22
+ };
23
+
24
+ export const root = getSyncLifecycle(rootComponent, options);
25
+
26
+ export const queueTableByStatusMenu = getSyncLifecycle(queueTableByStatusMenuComponent, options);
27
+
28
+ export const appointmentsList = getSyncLifecycle(appointmentListComponent, options);
29
+
30
+ export const queueList = getSyncLifecycle(queueListComponent, options);
31
+
32
+ export const outpatientSideNav = getSyncLifecycle(outpatientSideNavComponent, options);
33
+
34
+ export const serviceQueuesDashboardLink = getSyncLifecycle(createDashboardLink(dashboardMeta), options);
35
+
36
+ export const homeDashboard = getSyncLifecycle(homeDashboardComponent, options);
37
+
38
+ export const editQueueEntryStatusModal = getAsyncLifecycle(
39
+ () => import('./active-visits/change-status-dialog.component'),
40
+ {
41
+ featureName: 'edit queue status',
42
+ moduleName,
43
+ },
44
+ );
45
+
46
+ export const patientInfoBannerSlot = getSyncLifecycle(patientInfoBannerSlotComponent, {
47
+ featureName: 'patient info slot',
48
+ moduleName,
49
+ });
50
+
51
+ export const removeQueueEntry = getAsyncLifecycle(
52
+ () => import('./remove-queue-entry-dialog/remove-queue-entry.component'),
53
+ {
54
+ featureName: 'remove queue entry and end visit',
55
+ moduleName,
56
+ },
57
+ );
58
+
59
+ export const clearAllQueueEntries = getAsyncLifecycle(
60
+ () => import('./clear-queue-entries-dialog/clear-queue-entries-dialog.component'),
61
+ {
62
+ featureName: 'clear all queue entries and end visits',
63
+ moduleName,
64
+ },
65
+ );
66
+
67
+ export const addVisitToQueueModal = getAsyncLifecycle(
68
+ () => import('./add-patient-toqueue/add-patient-toqueue-dialog.component'),
69
+ {
70
+ featureName: 'add visit to queue',
71
+ moduleName,
72
+ },
73
+ );
74
+
75
+ export const transitionQueueEntryStatusModal = getAsyncLifecycle(
76
+ () => import('./transition-queue-entry/transition-queue-entry-dialog.component'),
77
+ {
78
+ featureName: 'transition queue status',
79
+ moduleName,
80
+ },
81
+ );
82
+
83
+ export const pastVisitSummary = getSyncLifecycle(pastVisitSummaryComponent, options);
84
+
85
+ export const addProviderToRoomModal = getAsyncLifecycle(
86
+ () => import('./add-provider-queue-room/add-provider-queue-room.component'),
87
+ {
88
+ featureName: 'add provider queue room',
89
+ moduleName,
90
+ },
91
+ );
92
+
93
+ export const transitionQueueEntryModal = getAsyncLifecycle(
94
+ () => import('./queue-table/queue-entry-actions/transition-queue-entry-modal.component'),
95
+ {
96
+ featureName: 'transfer patient to a different queue',
97
+ moduleName,
98
+ },
99
+ );
100
+
101
+ export const editQueueEntryModal = getAsyncLifecycle(
102
+ () => import('./queue-table/queue-entry-actions/edit-queue-entry-modal.component'),
103
+ {
104
+ featureName: 'edit queue entry of a patient',
105
+ moduleName,
106
+ },
107
+ );
108
+
109
+ export const undoTransitionQueueEntryModal = getAsyncLifecycle(
110
+ () => import('./queue-table/queue-entry-actions/undo-transition-queue-entry-modal.component'),
111
+ {
112
+ featureName: 'undo queue entry transiion of a patient',
113
+ moduleName,
114
+ },
115
+ );
116
+
117
+ export const voidQueueEntryModal = getAsyncLifecycle(
118
+ () => import('./queue-table/queue-entry-actions/void-queue-entry-modal.component'),
119
+ {
120
+ featureName: 'void queue entry of a patient',
121
+ moduleName,
122
+ },
123
+ );
124
+
125
+ export const endQueueEntryModal = getAsyncLifecycle(
126
+ () => import('./queue-table/queue-entry-actions/end-queue-entry-modal.component'),
127
+ {
128
+ featureName: 'end queue entry of a patient',
129
+ moduleName,
130
+ },
131
+ );
132
+
133
+ // t('addNewQueueService', 'Add New Queue Service')
134
+ export const addNewQueueServiceWorkspace = getAsyncLifecycle(
135
+ () => import('./queue-services/queue-service-form.workspace'),
136
+ {
137
+ featureName: 'service-queues-service-form',
138
+ moduleName,
139
+ },
140
+ );
141
+
142
+ // t('addNewQueueServiceRoom', 'Add new queue service room')
143
+ export const addNewQueueServiceRoomWorkspace = getAsyncLifecycle(
144
+ () => import('./queue-rooms/queue-room-form.workspace'),
145
+ {
146
+ featureName: 'service-queues-queue-room-form',
147
+ moduleName,
148
+ },
149
+ );
150
+
151
+ export const visitFormQueueFields = getSyncLifecycle(VisitFormQueueFields, options);
152
+
153
+ // t('searchPatient', 'Search Patient')
154
+ export const patientSearchWorkspace = getAsyncLifecycle(() => import('./patient-search/patient-search.workspace'), {
155
+ featureName: 'service-queues-patient-search',
156
+ moduleName,
157
+ });
158
+
159
+ export const activeVisitsRowActions = getAsyncLifecycle(
160
+ () => import('./active-visits/active-visits-row-actions.component'),
161
+ {
162
+ featureName:
163
+ 'quick actions to queue, requeue and transfer patients. With overflow menu actions to edit patient and end visit',
164
+ moduleName,
165
+ },
166
+ );
167
+
168
+ export function startupApp() {
169
+ registerBreadcrumbs([]);
170
+
171
+ defineConfigSchema(moduleName, configSchema);
172
+ }