@kenyaemr/esm-express-workflow-app 5.4.3 → 5.4.4-pre.100

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 (388) hide show
  1. package/.turbo/turbo-build.log +7 -12
  2. package/dist/1074.js +1 -0
  3. package/dist/1074.js.map +1 -0
  4. package/dist/12.js +17 -0
  5. package/dist/12.js.map +1 -0
  6. package/dist/1311.js +1 -0
  7. package/dist/1311.js.map +1 -0
  8. package/dist/1323.js +1 -0
  9. package/dist/1323.js.map +1 -0
  10. package/dist/1469.js +1 -0
  11. package/dist/1469.js.map +1 -0
  12. package/dist/1506.js +13 -0
  13. package/dist/1506.js.map +1 -0
  14. package/dist/1562.js +1 -0
  15. package/dist/1562.js.map +1 -0
  16. package/dist/1760.js +1 -0
  17. package/dist/1760.js.map +1 -0
  18. package/dist/1780.js +1 -0
  19. package/dist/1780.js.map +1 -0
  20. package/dist/1804.js +1 -0
  21. package/dist/1804.js.map +1 -0
  22. package/dist/1884.js +1 -0
  23. package/dist/1884.js.map +1 -0
  24. package/dist/1972.js +1 -0
  25. package/dist/1972.js.map +1 -0
  26. package/dist/1990.js +1 -0
  27. package/dist/1990.js.map +1 -0
  28. package/dist/2016.js +1 -0
  29. package/dist/2016.js.map +1 -0
  30. package/dist/2024.js +1 -0
  31. package/dist/2024.js.map +1 -0
  32. package/dist/2153.js +1 -0
  33. package/dist/2153.js.map +1 -0
  34. package/dist/216.js +1 -0
  35. package/dist/216.js.map +1 -0
  36. package/dist/2225.js +1 -0
  37. package/dist/2225.js.map +1 -0
  38. package/dist/2294.js +1 -0
  39. package/dist/2294.js.map +1 -0
  40. package/dist/2345.js +1 -0
  41. package/dist/2345.js.map +1 -0
  42. package/dist/2499.js +1 -0
  43. package/dist/2499.js.map +1 -0
  44. package/dist/2500.js +1 -0
  45. package/dist/2500.js.map +1 -0
  46. package/dist/2586.js +1 -0
  47. package/dist/2586.js.map +1 -0
  48. package/dist/2625.js +1 -0
  49. package/dist/2625.js.map +1 -0
  50. package/dist/2685.js +1 -0
  51. package/dist/2685.js.map +1 -0
  52. package/dist/2809.js +1 -0
  53. package/dist/2809.js.map +1 -0
  54. package/dist/2851.js +1 -0
  55. package/dist/2851.js.map +1 -0
  56. package/dist/2881.js +1 -0
  57. package/dist/2881.js.map +1 -0
  58. package/dist/2948.js +1 -0
  59. package/dist/2948.js.map +1 -0
  60. package/dist/2968.js +1 -0
  61. package/dist/2968.js.map +1 -0
  62. package/dist/2978.js +1 -0
  63. package/dist/2978.js.map +1 -0
  64. package/dist/2998.js +1 -0
  65. package/dist/2998.js.map +1 -0
  66. package/dist/3089.js +1 -0
  67. package/dist/3089.js.map +1 -0
  68. package/dist/3548.js +1 -0
  69. package/dist/3548.js.map +1 -0
  70. package/dist/3567.js +1 -0
  71. package/dist/3567.js.map +1 -0
  72. package/dist/3569.js +1 -0
  73. package/dist/3569.js.map +1 -0
  74. package/dist/3571.js +1 -0
  75. package/dist/3571.js.map +1 -0
  76. package/dist/3691.js +1 -0
  77. package/dist/3691.js.map +1 -0
  78. package/dist/3730.js +1 -0
  79. package/dist/3730.js.map +1 -0
  80. package/dist/3923.js +1 -0
  81. package/dist/3923.js.map +1 -0
  82. package/dist/3963.js +1 -0
  83. package/dist/3963.js.map +1 -0
  84. package/dist/4024.js +1 -0
  85. package/dist/4024.js.map +1 -0
  86. package/dist/405.js +1 -0
  87. package/dist/405.js.map +1 -0
  88. package/dist/4071.js +1 -0
  89. package/dist/4071.js.map +1 -0
  90. package/dist/4271.js +1 -0
  91. package/dist/4271.js.map +1 -0
  92. package/dist/4296.js +1 -0
  93. package/dist/4296.js.map +1 -0
  94. package/dist/4337.js +1 -0
  95. package/dist/4337.js.map +1 -0
  96. package/dist/4432.js +1 -0
  97. package/dist/4432.js.map +1 -0
  98. package/dist/4581.js +1 -0
  99. package/dist/4581.js.map +1 -0
  100. package/dist/4637.js +11 -0
  101. package/dist/4637.js.map +1 -0
  102. package/dist/4666.js +1 -0
  103. package/dist/4666.js.map +1 -0
  104. package/dist/4680.js +1 -0
  105. package/dist/4680.js.map +1 -0
  106. package/dist/4735.js +1 -0
  107. package/dist/4735.js.map +1 -0
  108. package/dist/4737.js +1 -0
  109. package/dist/4737.js.map +1 -0
  110. package/dist/4744.js +1 -0
  111. package/dist/4744.js.map +1 -0
  112. package/dist/4795.js +1 -0
  113. package/dist/4795.js.map +1 -0
  114. package/dist/4813.js +2 -0
  115. package/dist/4813.js.map +1 -0
  116. package/dist/4818.js +1 -0
  117. package/dist/4818.js.map +1 -0
  118. package/dist/4858.js +1 -0
  119. package/dist/4858.js.map +1 -0
  120. package/dist/487.js +1 -0
  121. package/dist/487.js.map +1 -0
  122. package/dist/4970.js +1 -0
  123. package/dist/4970.js.map +1 -0
  124. package/dist/5038.js +1 -0
  125. package/dist/5038.js.map +1 -0
  126. package/dist/5202.js +1 -0
  127. package/dist/5202.js.map +1 -0
  128. package/dist/5491.js +1 -0
  129. package/dist/5491.js.map +1 -0
  130. package/dist/5592.js +1 -0
  131. package/dist/5592.js.map +1 -0
  132. package/dist/5669.js +1 -0
  133. package/dist/5669.js.map +1 -0
  134. package/dist/586.js +1 -0
  135. package/dist/586.js.map +1 -0
  136. package/dist/5932.js +1 -0
  137. package/dist/5932.js.map +1 -0
  138. package/dist/5995.js +1 -0
  139. package/dist/5995.js.map +1 -0
  140. package/dist/6258.js +1 -0
  141. package/dist/6258.js.map +1 -0
  142. package/dist/629.js +1 -0
  143. package/dist/629.js.map +1 -0
  144. package/dist/6328.js +1 -0
  145. package/dist/6328.js.map +1 -0
  146. package/dist/6355.js +1 -0
  147. package/dist/6355.js.map +1 -0
  148. package/dist/6419.js +1 -0
  149. package/dist/6419.js.map +1 -0
  150. package/dist/644.js +1 -0
  151. package/dist/644.js.map +1 -0
  152. package/dist/6456.js +1 -0
  153. package/dist/6466.js +3 -0
  154. package/dist/6466.js.map +1 -0
  155. package/dist/655.js +1 -0
  156. package/dist/655.js.map +1 -0
  157. package/dist/6798.js +66 -0
  158. package/dist/6798.js.map +1 -0
  159. package/dist/6910.js +1 -0
  160. package/dist/6910.js.map +1 -0
  161. package/dist/6925.js +1 -0
  162. package/dist/6925.js.map +1 -0
  163. package/dist/70.js +1 -0
  164. package/dist/70.js.map +1 -0
  165. package/dist/7201.js +1 -0
  166. package/dist/7201.js.map +1 -0
  167. package/dist/7234.js +1 -0
  168. package/dist/7234.js.map +1 -0
  169. package/dist/7261.js +1 -0
  170. package/dist/7261.js.map +1 -0
  171. package/dist/7326.js +1 -0
  172. package/dist/7359.js +1 -0
  173. package/dist/7487.js +1 -0
  174. package/dist/7487.js.map +1 -0
  175. package/dist/7591.js +1 -0
  176. package/dist/7591.js.map +1 -0
  177. package/dist/7607.js +1 -0
  178. package/dist/7701.js +1 -0
  179. package/dist/7701.js.map +1 -0
  180. package/dist/7717.js +1 -0
  181. package/dist/7717.js.map +1 -0
  182. package/dist/7739.js +1 -0
  183. package/dist/7739.js.map +1 -0
  184. package/dist/7788.js +1 -0
  185. package/dist/7788.js.map +1 -0
  186. package/dist/7819.js +1 -0
  187. package/dist/7819.js.map +1 -0
  188. package/dist/7971.js +1 -0
  189. package/dist/7971.js.map +1 -0
  190. package/dist/7983.js +1 -0
  191. package/dist/7983.js.map +1 -0
  192. package/dist/807.js +1 -0
  193. package/dist/807.js.map +1 -0
  194. package/dist/8159.js +7 -0
  195. package/dist/8159.js.map +1 -0
  196. package/dist/8338.js +1 -0
  197. package/dist/8338.js.map +1 -0
  198. package/dist/845.js +1 -0
  199. package/dist/845.js.map +1 -0
  200. package/dist/8570.js +1 -0
  201. package/dist/8570.js.map +1 -0
  202. package/dist/8661.js +1 -0
  203. package/dist/8661.js.map +1 -0
  204. package/dist/87.js +1 -0
  205. package/dist/87.js.map +1 -0
  206. package/dist/8727.js +1 -0
  207. package/dist/8766.js +1 -0
  208. package/dist/8766.js.map +1 -0
  209. package/dist/8828.js +1 -0
  210. package/dist/8828.js.map +1 -0
  211. package/dist/8860.js +1 -0
  212. package/dist/8860.js.map +1 -0
  213. package/dist/8911.js +1 -0
  214. package/dist/8911.js.map +1 -0
  215. package/dist/8930.js +1 -0
  216. package/dist/8930.js.map +1 -0
  217. package/dist/8971.js +1 -0
  218. package/dist/8971.js.map +1 -0
  219. package/dist/9124.js +1 -0
  220. package/dist/9124.js.map +1 -0
  221. package/dist/9157.js +1 -0
  222. package/dist/9157.js.map +1 -0
  223. package/dist/9182.js +1 -0
  224. package/dist/921.js +1 -0
  225. package/dist/921.js.map +1 -0
  226. package/dist/9212.js +1 -0
  227. package/dist/9212.js.map +1 -0
  228. package/dist/9255.js +1 -0
  229. package/dist/9255.js.map +1 -0
  230. package/dist/9257.js +1 -0
  231. package/dist/9257.js.map +1 -0
  232. package/dist/9316.js +1 -0
  233. package/dist/9316.js.map +1 -0
  234. package/dist/9333.js +1 -0
  235. package/dist/9333.js.map +1 -0
  236. package/dist/9404.js +1 -0
  237. package/dist/9404.js.map +1 -0
  238. package/dist/9446.js +1 -0
  239. package/dist/9446.js.map +1 -0
  240. package/dist/9447.js +1 -0
  241. package/dist/9447.js.map +1 -0
  242. package/dist/9449.js +1 -0
  243. package/dist/9449.js.map +1 -0
  244. package/dist/9535.js +1 -0
  245. package/dist/9535.js.map +1 -0
  246. package/dist/9606.js +1 -0
  247. package/dist/9606.js.map +1 -0
  248. package/dist/973.js +1 -0
  249. package/dist/973.js.map +1 -0
  250. package/dist/9845.js +1 -0
  251. package/dist/9845.js.map +1 -0
  252. package/dist/kenyaemr-esm-express-workflow-app.js +5 -5
  253. package/dist/kenyaemr-esm-express-workflow-app.js.buildmanifest.json +3004 -175
  254. package/dist/kenyaemr-esm-express-workflow-app.js.map +1 -1
  255. package/dist/main.js +5 -114
  256. package/dist/main.js.map +1 -1
  257. package/dist/routes.json +1 -1
  258. package/package.json +6 -7
  259. package/rspack.config.js +1 -1
  260. package/src/components/accounting/index.tsx +11 -10
  261. package/src/components/admissions/index.tsx +11 -10
  262. package/src/components/appointments/index.ts +10 -8
  263. package/src/components/consultation/clinical-encounter/encounter-details.component.tsx +9 -9
  264. package/src/components/consultation/clinical-encounter/encounter-details.test.tsx +19 -18
  265. package/src/components/consultation/consultation-context.tsx +19 -0
  266. package/src/components/consultation/consultation-summary-cards.component.tsx +124 -0
  267. package/src/components/consultation/consultation.component.tsx +41 -268
  268. package/src/components/consultation/consultation.resource.ts +67 -24
  269. package/src/components/consultation/consultation.scss +5 -0
  270. package/src/components/consultation/consultation.utils.tsx +222 -0
  271. package/src/components/consultation/dashboard.component.tsx +0 -2
  272. package/src/components/consultation/index.ts +27 -20
  273. package/src/components/facility-dashboard/index.tsx +10 -9
  274. package/src/components/laboratory/index.ts +11 -10
  275. package/src/components/laboratory/lab-table.component.tsx +22 -8
  276. package/src/components/laboratory/laboratory-tabs.component.tsx +2 -2
  277. package/src/components/mch/dashboard.component.tsx +0 -2
  278. package/src/components/mch/index.tsx +10 -9
  279. package/src/components/mch/mch.consultation.component.tsx +27 -15
  280. package/src/components/mch/mch.triage.component.tsx +42 -33
  281. package/src/components/pharmacy/index.ts +20 -18
  282. package/src/components/pharmacy/orders/pharmacy-orders.component.tsx +35 -13
  283. package/src/components/pharmacy/orders/pharmacy-orders.test.tsx +8 -7
  284. package/src/components/procedures/index.ts +11 -10
  285. package/src/components/procedures/procedures-table.component.tsx +44 -13
  286. package/src/components/procedures/procedures-tabs.component.tsx +2 -2
  287. package/src/components/radiology-and-imaging/index.ts +14 -10
  288. package/src/components/radiology-and-imaging/radiology-and-imaging-table.component.tsx +35 -15
  289. package/src/components/radiology-and-imaging/radiology-and-imaging.component.tsx +2 -2
  290. package/src/components/registration/card/HIE-card/hie-card.component.tsx +32 -44
  291. package/src/components/registration/card/Local-card/local-card.component.tsx +22 -24
  292. package/src/components/registration/dependants/dependants.component.tsx +32 -60
  293. package/src/components/registration/dependants/dependants.resource.ts +79 -50
  294. package/src/components/registration/helper/index.ts +4 -0
  295. package/src/components/registration/index.ts +10 -9
  296. package/src/components/registration/search-bar/search-bar.resource.ts +32 -93
  297. package/src/components/registration/start-visit-form/hooks/useDefaultFacilityLocation.tsx +15 -0
  298. package/src/components/registration/start-visit-form/hooks/useDefaultVisitLocation.tsx +24 -0
  299. package/src/components/registration/start-visit-form/hooks/useOfflineVisitType.tsx +18 -0
  300. package/src/components/registration/start-visit-form/hooks/useRecommendedVisitTypes.tsx +36 -0
  301. package/src/components/registration/start-visit-form/hooks/useVisitAttributeType.tsx +102 -0
  302. package/src/components/registration/start-visit-form/overflow-menu-extension/overflow-menu-item.extension.tsx +55 -0
  303. package/src/components/registration/start-visit-form/overflow-menu-extension/overflow-menu-item.scss +3 -0
  304. package/src/components/registration/start-visit-form/start-visit-workspace/base-visit-type.component.tsx +126 -0
  305. package/src/components/registration/start-visit-form/start-visit-workspace/base-visit-type.scss +75 -0
  306. package/src/components/registration/start-visit-form/start-visit-workspace/exported-visit-form.workspace.tsx +743 -0
  307. package/src/components/registration/start-visit-form/start-visit-workspace/location-selector.component.tsx +86 -0
  308. package/src/components/registration/start-visit-form/start-visit-workspace/recommended-visit-type.component.tsx +32 -0
  309. package/src/components/registration/start-visit-form/start-visit-workspace/visit-attribute-type.component.tsx +257 -0
  310. package/src/components/registration/start-visit-form/start-visit-workspace/visit-attribute-type.scss +5 -0
  311. package/src/components/registration/start-visit-form/start-visit-workspace/visit-date-time.component.tsx +193 -0
  312. package/src/components/registration/start-visit-form/start-visit-workspace/visit-form.resource.ts +383 -0
  313. package/src/components/registration/start-visit-form/start-visit-workspace/visit-form.scss +166 -0
  314. package/src/components/registration/start-visit-form/visit-form-workspace/visit-form.workspace.tsx +55 -0
  315. package/src/components/reports/index.ts +10 -9
  316. package/src/components/triage/dashboard.component.tsx +0 -2
  317. package/src/components/triage/index.ts +10 -9
  318. package/src/components/triage/triage.component.tsx +92 -42
  319. package/src/components/triage/triage.resource.ts +56 -50
  320. package/src/components/triage/triage.scss +6 -0
  321. package/src/config-schema.ts +91 -0
  322. package/src/hooks/useServiceQueues.tsx +95 -25
  323. package/src/index.ts +32 -13
  324. package/src/routes.json +53 -254
  325. package/src/shared/orders/OrdersTabs.tsx +8 -3
  326. package/src/shared/patient-chart/patient-chart.resources.ts +8 -12
  327. package/src/shared/patient-chart/patient-summary-dashboard/patient-summary-dashboard.component.tsx +1 -2
  328. package/src/shared/pin-put/pinput.component.test.tsx +7 -6
  329. package/src/shared/queue/queue-entry/queue-entry-table.component.tsx +99 -88
  330. package/src/shared/queue/queue-entry/queue-entry-table.scss +4 -0
  331. package/src/shared/queue/queue-summary-cards.component.tsx +32 -0
  332. package/src/shared/queue/queue-tab.component.tsx +182 -70
  333. package/src/shared/queue/queue-tab.scss +1 -0
  334. package/src/shared/queue/queue-workflow-context.tsx +90 -0
  335. package/src/shared/tabs/extension-tabs.component.tsx +9 -6
  336. package/src/shared/utils/index.ts +1 -2
  337. package/src/types/index.ts +17 -2
  338. package/translations/am.json +64 -13
  339. package/translations/en.json +59 -8
  340. package/translations/sw.json +58 -7
  341. package/dist/127.js +0 -1
  342. package/dist/200.js +0 -1
  343. package/dist/200.js.map +0 -1
  344. package/dist/24.js +0 -1
  345. package/dist/24.js.map +0 -1
  346. package/dist/267.js +0 -1
  347. package/dist/267.js.map +0 -1
  348. package/dist/285.js +0 -1
  349. package/dist/285.js.map +0 -1
  350. package/dist/329.js +0 -1
  351. package/dist/329.js.map +0 -1
  352. package/dist/40.js +0 -1
  353. package/dist/466.js +0 -1
  354. package/dist/466.js.map +0 -1
  355. package/dist/472.js +0 -66
  356. package/dist/472.js.map +0 -1
  357. package/dist/490.js +0 -1
  358. package/dist/490.js.map +0 -1
  359. package/dist/54.js +0 -1
  360. package/dist/54.js.map +0 -1
  361. package/dist/689.js +0 -1
  362. package/dist/689.js.map +0 -1
  363. package/dist/697.js +0 -1
  364. package/dist/697.js.map +0 -1
  365. package/dist/704.js +0 -1
  366. package/dist/704.js.map +0 -1
  367. package/dist/710.js +0 -1
  368. package/dist/710.js.map +0 -1
  369. package/dist/729.js +0 -17
  370. package/dist/729.js.map +0 -1
  371. package/dist/805.js +0 -37
  372. package/dist/805.js.map +0 -1
  373. package/dist/847.js +0 -1
  374. package/dist/847.js.map +0 -1
  375. package/dist/85.js +0 -1
  376. package/dist/85.js.map +0 -1
  377. package/dist/882.js +0 -1
  378. package/dist/91.js +0 -1
  379. package/dist/91.js.map +0 -1
  380. package/dist/916.js +0 -1
  381. package/dist/994.js +0 -1
  382. package/dist/994.js.map +0 -1
  383. package/dist/998.js +0 -1
  384. package/dist/998.js.map +0 -1
  385. package/jest.config.js +0 -3
  386. package/src/shared/patient-chart/patient-chart.component.tsx +0 -61
  387. package/src/shared/patient-chart/patient-chart.scss +0 -15
  388. package/src/shared/patient-chart/useInitialize.ts +0 -24
@@ -1,5 +1,13 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import dayjs from 'dayjs';
3
+ import relativeTime from 'dayjs/plugin/relativeTime';
4
+ import capitalize from 'lodash-es/capitalize';
5
+ import lowerCase from 'lodash-es/lowerCase';
6
+ import startCase from 'lodash-es/startCase';
7
+ import { useTranslation } from 'react-i18next';
1
8
  import {
2
9
  DataTable,
10
+ InlineLoading,
3
11
  OverflowMenu,
4
12
  OverflowMenuItem,
5
13
  Pagination,
@@ -11,20 +19,13 @@ import {
11
19
  TableHeader,
12
20
  TableRow,
13
21
  } from '@carbon/react';
14
- import { ConfigurableLink, showModal, useConfig, useDebounce, usePagination } from '@openmrs/esm-framework';
15
- import { usePaginationInfo } from '@openmrs/esm-patient-common-lib';
16
- import dayjs from 'dayjs';
17
- import relativeTime from 'dayjs/plugin/relativeTime';
18
- import startCase from 'lodash-es/startCase';
19
- import React, { useMemo, useState } from 'react';
20
- import { useTranslation } from 'react-i18next';
22
+ import { ConfigurableLink, showModal, useConfig, useDebounce } from '@openmrs/esm-framework';
23
+ import { CardHeader, usePaginationInfo } from '@openmrs/esm-patient-common-lib';
21
24
 
22
- import capitalize from 'lodash-es/capitalize';
23
- import lowerCase from 'lodash-es/lowerCase';
24
25
  import { type ExpressWorkflowConfig } from '../../../config-schema';
25
26
  import { spaBasePath } from '../../../constants';
26
27
  import { serveQueueEntry } from '../../../hooks/useServiceQueues';
27
- import { type QueueEntry } from '../../../types/index';
28
+ import { type QueueEntriesPagination, type QueueEntry } from '../../../types/index';
28
29
  import styles from './queue-entry-table.scss';
29
30
 
30
31
  // Extend dayjs with the relativeTime plugin
@@ -34,16 +35,23 @@ type QueueEntryTableProps = {
34
35
  navigatePath?: string;
35
36
  queueEntries: Array<QueueEntry>;
36
37
  usePatientChart?: boolean;
38
+ pagination?: QueueEntriesPagination;
39
+ onPageSizeChange?: (pageSize: number) => void;
40
+ isLoading?: boolean;
41
+ isValidating?: boolean;
37
42
  };
38
43
 
39
44
  const QueueEntryTable: React.FC<QueueEntryTableProps> = ({
40
45
  navigatePath = 'triage',
41
46
  queueEntries,
42
47
  usePatientChart,
48
+ pagination,
49
+ onPageSizeChange,
50
+ isValidating,
51
+ isLoading,
43
52
  }) => {
44
53
  const { visitQueueNumberAttributeUuid } = useConfig<ExpressWorkflowConfig>();
45
54
  const [searchString, setSearchString] = useState('');
46
- const pageSize = 10;
47
55
  const { t } = useTranslation();
48
56
  const debouncedSearchString = useDebounce(searchString, 500);
49
57
  const filteredQueueEntries = useMemo(() => {
@@ -51,48 +59,32 @@ const QueueEntryTable: React.FC<QueueEntryTableProps> = ({
51
59
  return queueEntry.patient.person.display.toLowerCase().includes(debouncedSearchString.toLowerCase());
52
60
  });
53
61
  }, [queueEntries, debouncedSearchString]);
54
- const { currentPage, goTo, results } = usePagination(filteredQueueEntries, pageSize);
55
- const { pageSizes } = usePaginationInfo(pageSize, queueEntries.length, currentPage, results.length);
56
62
 
57
- const headers = [
58
- {
59
- header: t('name', 'Name'),
60
- key: 'patientName',
61
- },
62
- {
63
- header: t('queueNumber', 'Queue Number'),
64
- key: 'queueNumber',
65
- },
66
- {
67
- header: t('comingFrom', 'Coming from'),
68
- key: 'previousQueue',
69
- },
70
- {
71
- header: t('priority', 'Priority'),
72
- key: 'priority',
73
- },
74
- {
75
- header: t('priorityComment', 'Priority Comment'),
76
- key: 'priorityComment',
77
- },
78
- {
79
- header: t('status', 'status'),
80
- key: 'status',
81
- },
82
- {
83
- header: t('queue', 'Queue'),
84
- key: 'queue',
85
- },
86
- {
87
- header: t('waitTime', 'Wait time'),
88
- key: 'waitTime',
89
- },
90
- ];
63
+ const { pageSizes } = usePaginationInfo(
64
+ pagination?.defaultPageSize,
65
+ pagination?.totalCount,
66
+ pagination?.currentPage,
67
+ pagination?.currentPageSize.current,
68
+ );
69
+
70
+ const headers = useMemo(
71
+ () => [
72
+ { header: t('name', 'Name'), key: 'patientName' },
73
+ { header: t('queueNumber', 'Queue Number'), key: 'queueNumber' },
74
+ { header: t('comingFrom', 'Coming from'), key: 'previousQueue' },
75
+ { header: t('priority', 'Priority'), key: 'priority' },
76
+ { header: t('priorityComment', 'Priority Comment'), key: 'priorityComment' },
77
+ { header: t('status', 'status'), key: 'status' },
78
+ { header: t('queue', 'Queue'), key: 'queue' },
79
+ { header: t('waitTime', 'Wait time'), key: 'waitTime' },
80
+ ],
81
+ [t],
82
+ );
91
83
 
92
84
  const handleCallQueueEntry = async (queueEntry: QueueEntry) => {
93
- const queueNumber = queueEntry.visit.attributes?.filter(
85
+ const queueNumber = queueEntry.visit.attributes?.find(
94
86
  (attr) => attr['attributeType']?.uuid === visitQueueNumberAttributeUuid,
95
- )?.[0];
87
+ );
96
88
  const response = await serveQueueEntry(
97
89
  queueEntry.queue.name,
98
90
  queueNumber.value,
@@ -108,42 +100,58 @@ const QueueEntryTable: React.FC<QueueEntryTableProps> = ({
108
100
  }
109
101
  };
110
102
 
111
- const rows = results?.map((queueEntry) => {
112
- const visitNumber = queueEntry?.visit?.attributes?.find(
113
- (attr) => attr?.attributeType?.uuid === visitQueueNumberAttributeUuid,
114
- );
103
+ const rows = useMemo(() => {
104
+ return filteredQueueEntries?.map((queueEntry) => {
105
+ const visitNumber = queueEntry?.visit?.attributes?.find(
106
+ (attr) => attr?.attributeType?.uuid === visitQueueNumberAttributeUuid,
107
+ );
115
108
 
116
- const patientChartUrl = usePatientChart
117
- ? `${window.spaBase}/patient/${queueEntry.patient.uuid}/chart/Patient Summary?path=${navigatePath}`
118
- : `${spaBasePath}/${navigatePath}/${queueEntry.patient.uuid}`;
109
+ const patientChartUrl = usePatientChart
110
+ ? `${globalThis.spaBase}/patient/${queueEntry.patient.uuid}/chart/Patient Summary?path=${navigatePath}`
111
+ : `${spaBasePath}/${navigatePath}/${queueEntry.patient.uuid}`;
119
112
 
120
- return {
121
- id: queueEntry.uuid,
122
- queueNumber: visitNumber?.value ?? '--',
123
- previousQueue: startCase(queueEntry.previousQueueEntry?.queue?.display?.toLowerCase() ?? '--'),
124
- patientName: (
125
- <ConfigurableLink className={styles.link} to={patientChartUrl}>
126
- {startCase(queueEntry.patient.person.display.toLowerCase())}
127
- </ConfigurableLink>
128
- ),
129
- priority: (
130
- <div className={styles.priorityPill} data-priority={lowerCase(queueEntry?.priority?.display)}>
131
- {t(queueEntry?.priority?.display, capitalize(queueEntry?.priority?.display.replace('_', ' ')))}
132
- </div>
133
- ),
134
- priorityComment: startCase(queueEntry.priorityComment?.toLowerCase() ?? '--'),
135
- status: queueEntry?.status?.display ?? '--',
136
- queue: startCase(queueEntry?.queue?.display?.toLowerCase() ?? '--'),
137
- waitTime: dayjs(queueEntry.startedAt).fromNow(),
138
- };
139
- });
113
+ return {
114
+ id: queueEntry.uuid,
115
+ queueNumber: visitNumber?.value ?? '--',
116
+ previousQueue: startCase(queueEntry.previousQueueEntry?.queue?.display?.toLowerCase() ?? '--'),
117
+ patientName: (
118
+ <ConfigurableLink className={styles.link} to={patientChartUrl}>
119
+ {startCase(queueEntry.patient.person.display.toLowerCase())}
120
+ </ConfigurableLink>
121
+ ),
122
+ priority: (
123
+ <div className={styles.priorityPill} data-priority={lowerCase(queueEntry?.priority?.display)}>
124
+ {t(queueEntry?.priority?.display, capitalize(queueEntry?.priority?.display.replace('_', ' ')))}
125
+ </div>
126
+ ),
127
+ priorityComment: startCase(queueEntry.priorityComment?.toLowerCase() ?? '--'),
128
+ status: queueEntry?.status?.display ?? '--',
129
+ queue: startCase(queueEntry?.queue?.display?.toLowerCase() ?? '--'),
130
+ waitTime: dayjs(queueEntry.startedAt).fromNow(),
131
+ };
132
+ });
133
+ }, [filteredQueueEntries, visitQueueNumberAttributeUuid, navigatePath, usePatientChart, t]);
140
134
 
135
+ if (isLoading && queueEntries.length === 0) {
136
+ return <InlineLoading status="active" description={t('loading', 'Loading...')} />;
137
+ }
141
138
  if (queueEntries.length === 0) {
142
139
  return <div>{t('noPatientsAwaiting', 'No patients awaiting service')}</div>;
143
140
  }
144
141
 
145
142
  return (
146
143
  <div className={styles.table}>
144
+ <CardHeader title={t('queueEntries', 'Queue Entries')}>
145
+ <div className={styles.loadingContainer}>
146
+ {isValidating && (
147
+ <InlineLoading
148
+ className={styles.loading}
149
+ status="active"
150
+ description={t('refreshingData', 'Refreshing data...')}
151
+ />
152
+ )}
153
+ </div>
154
+ </CardHeader>
147
155
  <Search
148
156
  labelText={t('search', 'Search')}
149
157
  placeholder={t('search', 'Search')}
@@ -172,7 +180,7 @@ const QueueEntryTable: React.FC<QueueEntryTableProps> = ({
172
180
  <TableCell className="cds--table-column-menu">
173
181
  <OverflowMenu size="sm" aria-label="overflow-menu" flipped align="right">
174
182
  <OverflowMenuItem
175
- onClick={() => handleCallQueueEntry(results[index])}
183
+ onClick={() => handleCallQueueEntry(filteredQueueEntries[index])}
176
184
  itemText={t('call', 'Call')}
177
185
  />
178
186
  </OverflowMenu>
@@ -183,17 +191,20 @@ const QueueEntryTable: React.FC<QueueEntryTableProps> = ({
183
191
  </Table>
184
192
  )}
185
193
  </DataTable>
186
- <Pagination
187
- pageSizes={pageSizes}
188
- forwardText={t('nextPage', 'Next page')}
189
- backwardText={t('previousPage', 'Previous page')}
190
- page={currentPage}
191
- pageSize={pageSize}
192
- totalItems={filteredQueueEntries.length}
193
- onChange={({ page }) => {
194
- goTo(page);
195
- }}
196
- />
194
+ {pagination && (
195
+ <Pagination
196
+ pageSizes={pageSizes}
197
+ forwardText={t('nextPage', 'Next page')}
198
+ backwardText={t('previousPage', 'Previous page')}
199
+ page={pagination.currentPage}
200
+ pageSize={pagination.currentPageSize.current}
201
+ totalItems={pagination.totalCount}
202
+ onChange={({ page, pageSize }) => {
203
+ pagination.goTo(page);
204
+ onPageSizeChange?.(pageSize as number);
205
+ }}
206
+ />
207
+ )}
197
208
  </div>
198
209
  );
199
210
  };
@@ -29,3 +29,7 @@
29
29
  background-color: colors.$gray-20;
30
30
  }
31
31
  }
32
+
33
+ .loadingContainer {
34
+ margin-right: layout.$spacing-05;
35
+ }
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import Card from '../cards/card.component';
3
+ import styles from './queue-tab.scss';
4
+
5
+ export type QueueSummaryCard = {
6
+ title: string;
7
+ value: string;
8
+ categories?: Array<{ label: string; value: number; onClick?: () => void }>;
9
+ onClick?: () => void;
10
+ refreshButton?: React.ReactNode;
11
+ };
12
+
13
+ interface QueueSummaryCardsProps {
14
+ cards?: Array<QueueSummaryCard>;
15
+ }
16
+
17
+ const QueueSummaryCards: React.FC<QueueSummaryCardsProps> = ({ cards }) => (
18
+ <div className={styles.cards}>
19
+ {cards?.map((card) => (
20
+ <Card
21
+ key={card.title}
22
+ title={card.title}
23
+ total={card.value}
24
+ categories={card.categories}
25
+ onClick={card.onClick}
26
+ refreshButton={card.refreshButton}
27
+ />
28
+ ))}
29
+ </div>
30
+ );
31
+
32
+ export default QueueSummaryCards;
@@ -1,23 +1,18 @@
1
- import { Tabs, TabList, Tab, TabPanels, TabPanel, InlineLoading, TabsSkeleton } from '@carbon/react';
2
- import React, { useState, useEffect, useMemo, useCallback } from 'react';
1
+ import React, { useState, useMemo, useCallback, useEffect } from 'react';
2
+ import dayjs from 'dayjs';
3
3
  import { useTranslation } from 'react-i18next';
4
+ import { Tabs, TabList, Tab, TabPanels, TabPanel } from '@carbon/react';
4
5
  import startCase from 'lodash-es/startCase';
5
- import Card from '../cards/card.component';
6
- import { Queue, QueueFilter } from '../../types/index';
7
- import QueueEntryTable from './queue-entry/queue-entry-table.component';
6
+
7
+ import FiltersHeader from './filters-header.component';
8
+ import { type Queue, type QueueFilter } from '../../types/index';
8
9
  import { useQueueEntries } from '../../hooks/useServiceQueues';
10
+ import QueueEntryTable from './queue-entry/queue-entry-table.component';
9
11
  import styles from './queue-tab.scss';
10
- import FiltersHeader from './filters-header.component';
12
+ import { useQueueWorkflowContextOptional } from './queue-workflow-context';
11
13
 
12
14
  type QueueTabProps = {
13
15
  queues: Array<Queue>;
14
- cards?: Array<{
15
- title: string;
16
- value: string;
17
- categories?: Array<{ label: string; value: number; onClick?: () => void }>;
18
- onClick?: () => void;
19
- refreshButton?: React.ReactNode; // Add this property
20
- }>;
21
16
  navigatePath: string;
22
17
  onTabChanged?: (queue: Queue) => void;
23
18
  usePatientChart?: boolean;
@@ -25,54 +20,69 @@ type QueueTabProps = {
25
20
  onFiltersChanged?: (filters: Array<QueueFilter>) => void;
26
21
  };
27
22
 
28
- const QueueTab: React.FC<QueueTabProps> = ({
23
+ const startedOnOrAfter = dayjs().subtract(24, 'hour').format('YYYY-MM-DD HH:mm:ss');
24
+
25
+ const QueueTabWithContext: React.FC<
26
+ QueueTabProps & {
27
+ validQueues: Queue[];
28
+ workflowContext: NonNullable<ReturnType<typeof useQueueWorkflowContextOptional>>;
29
+ }
30
+ > = ({
29
31
  queues,
30
- cards,
31
32
  navigatePath,
32
- onTabChanged,
33
33
  usePatientChart,
34
- filters,
35
- onFiltersChanged,
34
+ filters: filtersProp,
35
+ onFiltersChanged: onFiltersChangedProp,
36
+ validQueues,
37
+ workflowContext,
36
38
  }) => {
39
+ const filters = workflowContext.filters ?? filtersProp ?? [];
40
+ const onFiltersChanged = workflowContext.setFilters ?? onFiltersChangedProp;
41
+ const onTabChanged = workflowContext.setCurrQueue;
37
42
  const { t } = useTranslation();
38
-
39
- // Filter queues with rooms first
40
- const validQueues = useMemo(() => queues.filter((queue) => queue?.queueRooms?.length > 0), [queues]);
41
-
42
- // Set initial selected queue to first valid queue
43
43
  const [selectedTabIndex, setSelectedTabIndex] = useState(0);
44
- const [isInitialLoad, setIsInitialLoad] = useState(true);
45
-
46
44
  const selectedQueue = validQueues[selectedTabIndex];
47
-
48
- const { queueEntries, isLoading, error } = useQueueEntries({
49
- location: selectedQueue?.location?.uuid ? [selectedQueue.location.uuid] : undefined,
50
- statuses: filters?.filter((filter) => filter.key === 'status')?.flatMap((filter) => filter.value.split(',')),
51
- });
45
+ const activeQueue = workflowContext.activeQueue;
52
46
 
53
47
  useEffect(() => {
54
- if (!isLoading && isInitialLoad) {
55
- setIsInitialLoad(false);
48
+ const index = validQueues.findIndex((q) => q?.uuid === activeQueue?.uuid);
49
+ if (index >= 0 && index !== selectedTabIndex) {
50
+ setSelectedTabIndex(index);
56
51
  }
57
- }, [isLoading, isInitialLoad]);
52
+ }, [activeQueue?.uuid, validQueues, selectedTabIndex]);
53
+
54
+ const {
55
+ queueEntries,
56
+ isLoadingQueueEntries,
57
+ isValidatingQueueEntries,
58
+ queueEntriesError: error,
59
+ queueEntriesPagination: pagination,
60
+ pageSize,
61
+ setPageSize,
62
+ } = workflowContext;
63
+
64
+ useEffect(() => {
65
+ pagination?.goTo(1);
66
+ }, [selectedQueue?.uuid]);
58
67
 
59
68
  const queueEntriesByService = useMemo(() => {
60
69
  if (!queueEntries?.length || !selectedQueue?.uuid) {
61
70
  return [];
62
71
  }
63
72
  const priorityFilter = filters?.find((filter) => filter.key === 'priority')?.value;
64
- const serviceAwaitingFilter = filters?.find((filter) => filter.key === 'service_awaiting')?.value?.split(',') ?? []; // Patient UUIDs
73
+ const statusFilter =
74
+ filters?.filter((filter) => filter.key === 'status')?.flatMap((filter) => filter.value.split(',')) ?? [];
75
+ const serviceAwaitingFilter = filters?.find((filter) => filter.key === 'service_awaiting')?.value?.split(',') ?? [];
65
76
  const serviceCompletedFilter =
66
- filters?.find((filter) => filter.key === 'service_completed')?.value?.split(',') ?? []; // Patient UUIDs
67
- const filtered = queueEntries.filter((entry) => {
68
- return (
77
+ filters?.find((filter) => filter.key === 'service_completed')?.value?.split(',') ?? [];
78
+ return queueEntries.filter(
79
+ (entry) =>
69
80
  entry?.queue?.uuid === selectedQueue?.uuid &&
81
+ (statusFilter.length > 0 ? statusFilter.includes(entry?.status?.uuid) : true) &&
70
82
  (priorityFilter ? entry?.priority?.uuid === priorityFilter : true) &&
71
83
  (serviceAwaitingFilter.length > 0 ? serviceAwaitingFilter.includes(entry?.patient?.uuid) : true) &&
72
- (serviceCompletedFilter.length > 0 ? serviceCompletedFilter.includes(entry?.patient?.uuid) : true)
73
- );
74
- });
75
- return filtered;
84
+ (serviceCompletedFilter.length > 0 ? serviceCompletedFilter.includes(entry?.patient?.uuid) : true),
85
+ );
76
86
  }, [filters, queueEntries, selectedQueue?.uuid]);
77
87
 
78
88
  const handleTabChange = useCallback(
@@ -86,21 +96,112 @@ const QueueTab: React.FC<QueueTabProps> = ({
86
96
  [validQueues, onTabChanged],
87
97
  );
88
98
 
89
- if (isInitialLoad && isLoading) {
90
- return <TabsSkeleton />;
99
+ if (error) {
100
+ return (
101
+ <div>
102
+ {t('errorLoadingQueueEntries', 'Error loading queue entries')}: {error.message}
103
+ </div>
104
+ );
91
105
  }
92
106
 
93
- if (!queues || queues.length === 0) {
94
- return <div>{t('noQueuesAvailable', 'No queues available')}</div>;
95
- }
107
+ return (
108
+ <div className={styles.queueTab}>
109
+ <FiltersHeader filters={filters} onFiltersChanged={onFiltersChanged} />
110
+ <div className={styles.tabsContainer}>
111
+ <Tabs selectedIndex={selectedTabIndex} onChange={handleTabChange}>
112
+ <TabList contained>
113
+ {validQueues.map((queue) => (
114
+ <Tab key={queue?.uuid}>{startCase(queue?.queueRooms[0]?.display)}</Tab>
115
+ ))}
116
+ </TabList>
117
+ <TabPanels>
118
+ {validQueues.map((queue) => (
119
+ <TabPanel key={queue?.uuid}>
120
+ <QueueEntryTable
121
+ queueEntries={queueEntriesByService}
122
+ navigatePath={navigatePath}
123
+ usePatientChart={usePatientChart}
124
+ pagination={pagination}
125
+ onPageSizeChange={setPageSize}
126
+ isLoading={isLoadingQueueEntries}
127
+ isValidating={isValidatingQueueEntries}
128
+ />
129
+ </TabPanel>
130
+ ))}
131
+ </TabPanels>
132
+ </Tabs>
133
+ </div>
134
+ </div>
135
+ );
136
+ };
96
137
 
97
- if (validQueues.length === 0) {
98
- return <div>{t('noQueueRooms', 'No queue rooms configured')}</div>;
99
- }
138
+ const QueueTabWithoutContext: React.FC<QueueTabProps> = ({
139
+ queues,
140
+ navigatePath,
141
+ onTabChanged: onTabChangedProp,
142
+ usePatientChart,
143
+ filters: filtersProp,
144
+ onFiltersChanged: onFiltersChangedProp,
145
+ }) => {
146
+ const { t } = useTranslation();
147
+ const [pageSize, setPageSize] = useState(10);
148
+ const validQueues = useMemo(() => queues.filter((queue) => queue?.queueRooms?.length > 0), [queues]);
149
+ const [selectedTabIndex, setSelectedTabIndex] = useState(0);
150
+ const selectedQueue = validQueues[selectedTabIndex];
100
151
 
101
- if (!selectedQueue) {
102
- return <div>{t('noQueueSelected', 'Please select a queue')}</div>;
103
- }
152
+ const {
153
+ queueEntries,
154
+ isLoading: isLoadingQueueEntries,
155
+ isValidating: isValidatingQueueEntries,
156
+ error,
157
+ pagination,
158
+ } = useQueueEntries(
159
+ {
160
+ location: selectedQueue?.location?.uuid ? [selectedQueue.location.uuid] : undefined,
161
+ startedOnOrAfter,
162
+ queues: [selectedQueue?.uuid],
163
+ },
164
+ pageSize,
165
+ );
166
+
167
+ useEffect(() => {
168
+ pagination?.goTo(1);
169
+ }, [selectedQueue?.uuid]);
170
+
171
+ const filters = filtersProp ?? [];
172
+ const onFiltersChanged = onFiltersChangedProp;
173
+ const onTabChanged = onTabChangedProp;
174
+
175
+ const queueEntriesByService = useMemo(() => {
176
+ if (!queueEntries?.length || !selectedQueue?.uuid) {
177
+ return [];
178
+ }
179
+ const priorityFilter = filters?.find((filter) => filter.key === 'priority')?.value;
180
+ const statusFilter =
181
+ filters?.filter((filter) => filter.key === 'status')?.flatMap((filter) => filter.value.split(',')) ?? [];
182
+ const serviceAwaitingFilter = filters?.find((filter) => filter.key === 'service_awaiting')?.value?.split(',') ?? [];
183
+ const serviceCompletedFilter =
184
+ filters?.find((filter) => filter.key === 'service_completed')?.value?.split(',') ?? [];
185
+ return queueEntries.filter(
186
+ (entry) =>
187
+ entry?.queue?.uuid === selectedQueue?.uuid &&
188
+ (statusFilter.length > 0 ? statusFilter.includes(entry?.status?.uuid) : true) &&
189
+ (priorityFilter ? entry?.priority?.uuid === priorityFilter : true) &&
190
+ (serviceAwaitingFilter.length > 0 ? serviceAwaitingFilter.includes(entry?.patient?.uuid) : true) &&
191
+ (serviceCompletedFilter.length > 0 ? serviceCompletedFilter.includes(entry?.patient?.uuid) : true),
192
+ );
193
+ }, [filters, queueEntries, selectedQueue?.uuid]);
194
+
195
+ const handleTabChange = useCallback(
196
+ (evt: { selectedIndex: number }) => {
197
+ setSelectedTabIndex(evt.selectedIndex);
198
+ const newQueue = validQueues[evt.selectedIndex];
199
+ if (newQueue) {
200
+ onTabChanged?.(newQueue);
201
+ }
202
+ },
203
+ [validQueues, onTabChanged],
204
+ );
104
205
 
105
206
  if (error) {
106
207
  return (
@@ -112,18 +213,6 @@ const QueueTab: React.FC<QueueTabProps> = ({
112
213
 
113
214
  return (
114
215
  <div className={styles.queueTab}>
115
- <div className={styles.cards}>
116
- {cards?.map((card) => (
117
- <Card
118
- key={card.title}
119
- title={card.title}
120
- total={card.value}
121
- categories={card.categories}
122
- onClick={card.onClick}
123
- refreshButton={card.refreshButton}
124
- />
125
- ))}
126
- </div>
127
216
  <FiltersHeader filters={filters} onFiltersChanged={onFiltersChanged} />
128
217
  <div className={styles.tabsContainer}>
129
218
  <Tabs selectedIndex={selectedTabIndex} onChange={handleTabChange}>
@@ -133,17 +222,16 @@ const QueueTab: React.FC<QueueTabProps> = ({
133
222
  ))}
134
223
  </TabList>
135
224
  <TabPanels>
136
- {validQueues.map((queue, index) => (
225
+ {validQueues.map((queue) => (
137
226
  <TabPanel key={queue?.uuid}>
138
- {isLoading && !isInitialLoad && (
139
- <div className={styles.loadingOverlay}>
140
- <InlineLoading description={t('loadingQueueEntries', 'Loading queue entries...')} />
141
- </div>
142
- )}
143
227
  <QueueEntryTable
144
228
  queueEntries={queueEntriesByService}
145
229
  navigatePath={navigatePath}
146
230
  usePatientChart={usePatientChart}
231
+ pagination={pagination}
232
+ onPageSizeChange={setPageSize}
233
+ isLoading={isLoadingQueueEntries}
234
+ isValidating={isValidatingQueueEntries}
147
235
  />
148
236
  </TabPanel>
149
237
  ))}
@@ -154,4 +242,28 @@ const QueueTab: React.FC<QueueTabProps> = ({
154
242
  );
155
243
  };
156
244
 
245
+ const QueueTab: React.FC<QueueTabProps> = (props) => {
246
+ const workflowContext = useQueueWorkflowContextOptional();
247
+ const { t } = useTranslation();
248
+ const validQueues = useMemo(() => props.queues.filter((queue) => queue?.queueRooms?.length > 0), [props.queues]);
249
+
250
+ if (!props.queues || props.queues.length === 0) {
251
+ return <div>{t('noQueuesAvailable', 'No queues available')}</div>;
252
+ }
253
+
254
+ if (validQueues.length === 0) {
255
+ return <div>{t('noQueueRooms', 'No queue rooms configured')}</div>;
256
+ }
257
+
258
+ if (!validQueues[0]) {
259
+ return <div>{t('noQueueSelected', 'Please select a queue')}</div>;
260
+ }
261
+
262
+ if (workflowContext) {
263
+ return <QueueTabWithContext {...props} validQueues={validQueues} workflowContext={workflowContext} />;
264
+ }
265
+
266
+ return <QueueTabWithoutContext {...props} />;
267
+ };
268
+
157
269
  export default QueueTab;
@@ -24,4 +24,5 @@
24
24
  display: flex;
25
25
  flex-direction: row;
26
26
  column-gap: layout.$spacing-05;
27
+ margin: layout.$spacing-05;
27
28
  }