@ampath/esm-dha-workflow-app 4.0.0-next.35 → 4.0.0-next.355

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 (793) hide show
  1. package/README.md +19 -0
  2. package/dist/1149.js +1 -0
  3. package/dist/1149.js.map +1 -0
  4. package/dist/1171.js +1 -0
  5. package/dist/1171.js.map +1 -0
  6. package/dist/1197.js +1 -0
  7. package/dist/1239.js +1 -0
  8. package/dist/1239.js.map +1 -0
  9. package/dist/1277.js +1 -0
  10. package/dist/1277.js.map +1 -0
  11. package/dist/1363.js +1 -0
  12. package/dist/1363.js.map +1 -0
  13. package/dist/1551.js +1 -0
  14. package/dist/1551.js.map +1 -0
  15. package/dist/1556.js +1 -0
  16. package/dist/1556.js.map +1 -0
  17. package/dist/1560.js +1 -0
  18. package/dist/1560.js.map +1 -0
  19. package/dist/1925.js +1 -0
  20. package/dist/1925.js.map +1 -0
  21. package/dist/1927.js +1 -0
  22. package/dist/1927.js.map +1 -0
  23. package/dist/2054.js +1 -0
  24. package/dist/2054.js.map +1 -0
  25. package/dist/2093.js +1 -0
  26. package/dist/2093.js.map +1 -0
  27. package/dist/2177.js +2 -0
  28. package/dist/2177.js.map +1 -0
  29. package/dist/2230.js +1 -0
  30. package/dist/2230.js.map +1 -0
  31. package/dist/2493.js +1 -0
  32. package/dist/2493.js.map +1 -0
  33. package/dist/3041.js +1 -0
  34. package/dist/3041.js.map +1 -0
  35. package/dist/3099.js +1 -0
  36. package/dist/3101.js +1 -0
  37. package/dist/3101.js.map +1 -0
  38. package/dist/313.js +1 -0
  39. package/dist/313.js.map +1 -0
  40. package/dist/3184.js +2 -0
  41. package/dist/3184.js.map +1 -0
  42. package/dist/3202.js +1 -0
  43. package/dist/3202.js.map +1 -0
  44. package/dist/3222.js +1 -0
  45. package/dist/3222.js.map +1 -0
  46. package/dist/327.js +1 -0
  47. package/dist/327.js.map +1 -0
  48. package/dist/347.js +1 -0
  49. package/dist/347.js.map +1 -0
  50. package/dist/3595.js +1 -0
  51. package/dist/3595.js.map +1 -0
  52. package/dist/3928.js +1 -0
  53. package/dist/3928.js.map +1 -0
  54. package/dist/3939.js +1 -0
  55. package/dist/3939.js.map +1 -0
  56. package/dist/4003.js +1 -0
  57. package/dist/4003.js.map +1 -0
  58. package/dist/4055.js +1 -0
  59. package/dist/4205.js +1 -0
  60. package/dist/4205.js.map +1 -0
  61. package/dist/4225.js +1 -0
  62. package/dist/4225.js.map +1 -0
  63. package/dist/4231.js +1 -0
  64. package/dist/4231.js.map +1 -0
  65. package/dist/4300.js +1 -0
  66. package/dist/4335.js +1 -0
  67. package/dist/4353.js +1 -0
  68. package/dist/4353.js.map +1 -0
  69. package/dist/4431.js +1 -0
  70. package/dist/4431.js.map +1 -0
  71. package/dist/4454.js +1 -0
  72. package/dist/4454.js.map +1 -0
  73. package/dist/4457.js +2 -0
  74. package/dist/4457.js.LICENSE.txt +282 -0
  75. package/dist/4457.js.map +1 -0
  76. package/dist/4605.js +1 -0
  77. package/dist/4605.js.map +1 -0
  78. package/dist/4611.js +1 -0
  79. package/dist/4611.js.map +1 -0
  80. package/dist/4652.js +1 -0
  81. package/dist/4674.js +1 -0
  82. package/dist/4674.js.map +1 -0
  83. package/dist/4755.js +1 -0
  84. package/dist/4755.js.map +1 -0
  85. package/dist/4856.js +1 -0
  86. package/dist/4856.js.map +1 -0
  87. package/dist/4986.js +1 -0
  88. package/dist/4986.js.map +1 -0
  89. package/dist/5119.js +1 -0
  90. package/dist/5119.js.map +1 -0
  91. package/dist/5167.js +1 -0
  92. package/dist/5167.js.map +1 -0
  93. package/dist/5317.js +1 -0
  94. package/dist/5317.js.map +1 -0
  95. package/dist/5344.js +1 -0
  96. package/dist/5344.js.map +1 -0
  97. package/dist/5380.js +1 -0
  98. package/dist/5380.js.map +1 -0
  99. package/dist/5422.js +1 -0
  100. package/dist/5422.js.map +1 -0
  101. package/dist/5576.js +1 -0
  102. package/dist/5576.js.map +1 -0
  103. package/dist/5724.js +1 -0
  104. package/dist/5724.js.map +1 -0
  105. package/dist/5851.js +1 -0
  106. package/dist/5851.js.map +1 -0
  107. package/dist/5961.js +1 -0
  108. package/dist/5961.js.map +1 -0
  109. package/dist/6177.js +1 -0
  110. package/dist/6177.js.map +1 -0
  111. package/dist/6264.js +1 -0
  112. package/dist/6264.js.map +1 -0
  113. package/dist/6540.js +2 -0
  114. package/dist/6540.js.map +1 -0
  115. package/dist/6606.js +1 -0
  116. package/dist/6606.js.map +1 -0
  117. package/dist/6720.js +1 -0
  118. package/dist/6720.js.map +1 -0
  119. package/dist/6824.js +1 -0
  120. package/dist/6824.js.map +1 -0
  121. package/dist/6942.js +1 -0
  122. package/dist/6942.js.map +1 -0
  123. package/dist/71.js +1 -0
  124. package/dist/71.js.map +1 -0
  125. package/dist/7207.js +1 -0
  126. package/dist/7207.js.map +1 -0
  127. package/dist/7255.js +1 -0
  128. package/dist/7255.js.map +1 -0
  129. package/dist/7420.js +1 -0
  130. package/dist/7420.js.map +1 -0
  131. package/dist/7521.js +1 -0
  132. package/dist/7521.js.map +1 -0
  133. package/dist/7549.js +1 -0
  134. package/dist/7549.js.map +1 -0
  135. package/dist/7557.js +1 -0
  136. package/dist/7557.js.map +1 -0
  137. package/dist/7717.js +1 -0
  138. package/dist/7717.js.map +1 -0
  139. package/dist/7830.js +2 -0
  140. package/dist/7830.js.map +1 -0
  141. package/dist/7857.js +1 -0
  142. package/dist/7857.js.map +1 -0
  143. package/dist/7941.js +1 -0
  144. package/dist/7941.js.map +1 -0
  145. package/dist/8091.js +1 -0
  146. package/dist/8091.js.map +1 -0
  147. package/dist/810.js +1 -0
  148. package/dist/810.js.map +1 -0
  149. package/dist/8146.js +1 -0
  150. package/dist/8146.js.map +1 -0
  151. package/dist/850.js +1 -0
  152. package/dist/850.js.map +1 -0
  153. package/dist/8558.js +1 -0
  154. package/dist/8558.js.map +1 -0
  155. package/dist/8684.js +1 -0
  156. package/dist/8684.js.map +1 -0
  157. package/dist/8895.js +1 -0
  158. package/dist/8895.js.map +1 -0
  159. package/dist/9070.js +1 -0
  160. package/dist/9070.js.map +1 -0
  161. package/dist/9091.js +1 -0
  162. package/dist/9091.js.map +1 -0
  163. package/dist/9093.js +1 -0
  164. package/dist/9093.js.map +1 -0
  165. package/dist/9338.js +1 -0
  166. package/dist/9338.js.map +1 -0
  167. package/dist/9349.js +1 -0
  168. package/dist/9349.js.map +1 -0
  169. package/dist/9418.js +2 -0
  170. package/dist/9418.js.LICENSE.txt +1 -0
  171. package/dist/9418.js.map +1 -0
  172. package/dist/9428.js +1 -0
  173. package/dist/9428.js.map +1 -0
  174. package/dist/9583.js +2 -0
  175. package/dist/9583.js.map +1 -0
  176. package/dist/9871.js +1 -0
  177. package/dist/9871.js.map +1 -0
  178. package/dist/esm-dha-workflow-app.js +1 -1
  179. package/dist/esm-dha-workflow-app.js.buildmanifest.json +1830 -221
  180. package/dist/esm-dha-workflow-app.js.map +1 -1
  181. package/dist/main.js +1 -1
  182. package/dist/main.js.map +1 -1
  183. package/dist/routes.json +1 -1
  184. package/local-config.json +9 -0
  185. package/package.json +16 -6
  186. package/src/admissions/admission-request-list/admission-request-list.scss +0 -0
  187. package/src/admissions/admission-request-list/admission-request-list.tsx +263 -0
  188. package/src/admissions/admissions-dashboard.component.scss +15 -0
  189. package/src/admissions/admissions-dashboard.component.tsx +277 -0
  190. package/src/admissions/admissions.resource.ts +233 -0
  191. package/src/admissions/admitted-list/admitted-patients-list.tsx +206 -0
  192. package/src/admissions/awaiting-discharge-list/awaiting-discharge-list.tsx +197 -0
  193. package/src/admissions/bed-assigment-request/bed-assignment-request-list.tsx +134 -0
  194. package/src/admissions/constants/index.ts +33 -0
  195. package/src/admissions/discharged-list/discharged-list.scss +0 -0
  196. package/src/admissions/discharged-list/discharged-list.tsx +67 -0
  197. package/src/admissions/form-entry-workspace/form-entry-workspace.tsx +62 -0
  198. package/src/admissions/inpatient/admission-history/patient-admission-history.tsx +76 -0
  199. package/src/admissions/inpatient/admission-requests/patient-admission-requests.scss +19 -0
  200. package/src/admissions/inpatient/admission-requests/patient-admission-requests.tsx +72 -0
  201. package/src/admissions/inpatient/inpatient-admissions.component.scss +7 -0
  202. package/src/admissions/inpatient/inpatient-admissions.component.tsx +46 -0
  203. package/src/admissions/modal/add-bill-items/add-bill-items.modal.scss +17 -0
  204. package/src/admissions/modal/add-bill-items/add-bill-items.modal.tsx +233 -0
  205. package/src/admissions/modal/admit-elsewhere/admit-elsewhere.modal.scss +23 -0
  206. package/src/admissions/modal/admit-elsewhere/admit-elsewhere.modal.tsx +156 -0
  207. package/src/admissions/modal/admit-patient/admit-patient.modal.scss +0 -0
  208. package/src/admissions/modal/admit-patient/admit-patient.modal.tsx +111 -0
  209. package/src/admissions/modal/bed-swap/bed-swap.modal.scss +0 -0
  210. package/src/admissions/modal/bed-swap/bed-swap.modal.tsx +102 -0
  211. package/src/admissions/modal/cancel-admission-request/cancel-admission-request.scss +11 -0
  212. package/src/admissions/modal/cancel-admission-request/cancel-admission-request.tsx +105 -0
  213. package/src/admissions/modal/discharge/discharge-patient.modal.scss +13 -0
  214. package/src/admissions/modal/discharge/discharge-patient.modal.tsx +86 -0
  215. package/src/admissions/types/index.ts +263 -0
  216. package/src/appointments/appointments.component.scss +6 -0
  217. package/src/appointments/appointments.component.tsx +8 -1
  218. package/src/billing/api/billing.api.ts +139 -0
  219. package/src/billing/billing-claims.resource.ts +916 -0
  220. package/src/billing/billing-dashboard-link.component.tsx +31 -0
  221. package/src/billing/billing-dashboard-reset.ts +27 -0
  222. package/src/billing/billing-root.tsx +42 -0
  223. package/src/billing/dashboard/billingDashboard.component.scss +0 -0
  224. package/src/billing/dashboard/billingDashboard.component.tsx +25 -0
  225. package/src/billing/dashboard/v2/active-visits/active-visits.component.tsx +257 -0
  226. package/src/billing/dashboard/v2/active-visits/active-visits.resource.ts +85 -0
  227. package/src/billing/dashboard/v2/active-visits/active-visits.scss +15 -0
  228. package/src/billing/dashboard/v2/active-visits.component.tsx +102 -0
  229. package/src/billing/dashboard/v2/admissions/admission-requests-tab.component.tsx +79 -0
  230. package/src/billing/dashboard/v2/billing-claims-dashboard.component.scss +209 -0
  231. package/src/billing/dashboard/v2/billing-claims-dashboard.component.tsx +396 -0
  232. package/src/billing/dashboard/v2/cash-checklist/bill-document.component.scss +90 -0
  233. package/src/billing/dashboard/v2/cash-checklist/bill-document.component.tsx +101 -0
  234. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.component.scss +199 -0
  235. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.component.tsx +361 -0
  236. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.resource.ts +239 -0
  237. package/src/billing/dashboard/v2/cash-checklist/payment-drawer.component.scss +246 -0
  238. package/src/billing/dashboard/v2/cash-checklist/payment-drawer.component.tsx +182 -0
  239. package/src/billing/dashboard/v2/claim-statuses.ts +143 -0
  240. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.scss +0 -0
  241. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.tsx +35 -0
  242. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-panel.component.scss +67 -0
  243. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-panel.component.tsx +90 -0
  244. package/src/billing/dashboard/v2/claim-visits/claim-doctors/claim-doctors.scss +28 -0
  245. package/src/billing/dashboard/v2/claim-visits/claim-doctors/claim-doctors.tsx +36 -0
  246. package/src/billing/dashboard/v2/claim-visits/claim-history/claim-history.component.scss +119 -0
  247. package/src/billing/dashboard/v2/claim-visits/claim-history/claim-history.component.tsx +198 -0
  248. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-details.component.scss +5 -0
  249. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-details.component.tsx +160 -0
  250. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-panel.component.scss +105 -0
  251. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-panel.component.tsx +184 -0
  252. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/intervention-attachments.component.scss +161 -0
  253. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/intervention-attachments.component.tsx +328 -0
  254. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-details.component.tsx +96 -0
  255. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-document.component.tsx +236 -0
  256. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-panel.component.scss +98 -0
  257. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-panel.component.tsx +292 -0
  258. package/src/billing/dashboard/v2/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.scss +133 -0
  259. package/src/billing/dashboard/v2/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.tsx +217 -0
  260. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-by-token.component.tsx +150 -0
  261. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-page.component.scss +13 -0
  262. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-page.component.tsx +116 -0
  263. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-visit-details.component.scss +338 -0
  264. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-visit-details.component.tsx +616 -0
  265. package/src/billing/dashboard/v2/claim-visits/claim-visits.component.scss +5 -0
  266. package/src/billing/dashboard/v2/claim-visits/claim-visits.component.tsx +133 -0
  267. package/src/billing/dashboard/v2/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.scss +5 -0
  268. package/src/billing/dashboard/v2/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.tsx +49 -0
  269. package/src/billing/dashboard/v2/claim-visits/modal/claim-visit-details/claim-visit-details.modal.scss +17 -0
  270. package/src/billing/dashboard/v2/claim-visits/modal/claim-visit-details/claim-visit-details.modal.tsx +56 -0
  271. package/src/billing/dashboard/v2/claim-visits/modal/close-claim/close-claim.modal.scss +0 -0
  272. package/src/billing/dashboard/v2/claim-visits/modal/close-claim/close-claim.modal.tsx +129 -0
  273. package/src/billing/dashboard/v2/claim-visits/modal/submit-claim/submit-claim.modal.tsx +204 -0
  274. package/src/billing/dashboard/v2/claim-visits/shared/_empty-state.scss +28 -0
  275. package/src/billing/dashboard/v2/claim-visits/shared/record-cards.component.scss +298 -0
  276. package/src/billing/dashboard/v2/claim-visits/shared/record-cards.component.tsx +252 -0
  277. package/src/billing/dashboard/v2/claim-visits/shared/record-details.workspace.scss +42 -0
  278. package/src/billing/dashboard/v2/claim-visits/shared/record-details.workspace.tsx +54 -0
  279. package/src/billing/dashboard/v2/claim-visits/shared/record-table.component.scss +61 -0
  280. package/src/billing/dashboard/v2/claim-visits/shared/record-table.component.tsx +150 -0
  281. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.resource.ts +51 -0
  282. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.workspace.scss +191 -0
  283. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.workspace.tsx +648 -0
  284. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.component.scss +595 -0
  285. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.component.tsx +810 -0
  286. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.resource.ts +282 -0
  287. package/src/billing/dashboard/v2/claims-accounting/bill-utils.ts +134 -0
  288. package/src/billing/dashboard/v2/claims-accounting/claim-detail.component.tsx +346 -0
  289. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.component.scss +546 -0
  290. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.component.tsx +206 -0
  291. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.resource.ts +337 -0
  292. package/src/billing/dashboard/v2/claims-accounting/invoice-document.component.scss +90 -0
  293. package/src/billing/dashboard/v2/claims-accounting/invoice-document.component.tsx +90 -0
  294. package/src/billing/dashboard/v2/claims-accounting/remittances.component.tsx +169 -0
  295. package/src/billing/dashboard/v2/claims-accounting/remittances.resource.ts +46 -0
  296. package/src/billing/dashboard/v2/claims-accounting/status-meta.ts +25 -0
  297. package/src/billing/dashboard/v2/clearance/cash-patients.scss +18 -0
  298. package/src/billing/dashboard/v2/clearance/cash.component.tsx +145 -0
  299. package/src/billing/dashboard/v2/clearance/clearance.component.scss +84 -0
  300. package/src/billing/dashboard/v2/clearance/clearance.component.tsx +225 -0
  301. package/src/billing/dashboard/v2/clearance/pay-cash.component.tsx +202 -0
  302. package/src/billing/dashboard/v2/clearance/pay-cash.scss +28 -0
  303. package/src/billing/dashboard/v2/clearance/prepaid-services.component.tsx +112 -0
  304. package/src/billing/dashboard/v2/facility-bills/claim-status.ts +249 -0
  305. package/src/billing/dashboard/v2/facility-bills/facility-bills.component.scss +140 -0
  306. package/src/billing/dashboard/v2/facility-bills/facility-bills.component.tsx +688 -0
  307. package/src/billing/dashboard/v2/facility-bills/preauths-datatables/pending-preauths.component.tsx +132 -0
  308. package/src/billing/dashboard/v2/facility-bills/preauths-datatables/preauth-preview-table.component.tsx +267 -0
  309. package/src/billing/dashboard/v2/facility-bills/preauths.component.tsx +130 -0
  310. package/src/billing/dashboard/v2/inpatient-requests/inpatient-requests.component.scss +22 -0
  311. package/src/billing/dashboard/v2/inpatient-requests/inpatient-requests.component.tsx +389 -0
  312. package/src/billing/dashboard/v2/inpatient-requests/modal/start-inpatient-claim/start-inpatient-claim.component.scss +0 -0
  313. package/src/billing/dashboard/v2/inpatient-requests/modal/start-inpatient-claim/start-inpatient-claim.component.tsx +0 -0
  314. package/src/billing/dashboard/v2/new-facility-bills/bills-table.component.tsx +78 -0
  315. package/src/billing/dashboard/v2/new-facility-bills/bills-table.scss +18 -0
  316. package/src/billing/dashboard/v2/new-facility-bills/new-facility-bills.component.tsx +64 -0
  317. package/src/billing/dashboard/v2/new-facility-bills/new-facility-bills.scss +146 -0
  318. package/src/billing/dashboard/v2/patient-bill-details/attachments/add-attachments.component.tsx +223 -0
  319. package/src/billing/dashboard/v2/patient-bill-details/attachments/attachment.component.tsx +157 -0
  320. package/src/billing/dashboard/v2/patient-bill-details/attachments/attachments.scss +92 -0
  321. package/src/billing/dashboard/v2/patient-bill-details/attachments/case-summary/case-summary.scss +295 -0
  322. package/src/billing/dashboard/v2/patient-bill-details/attachments/case-summary/case-summary.tsx +326 -0
  323. package/src/billing/dashboard/v2/patient-bill-details/attachments/dialysis/dialysis-chart.scss +238 -0
  324. package/src/billing/dashboard/v2/patient-bill-details/attachments/dialysis/dialysis-chart.tsx +269 -0
  325. package/src/billing/dashboard/v2/patient-bill-details/attachments/discharge-summary/discharge-summary.scss +96 -0
  326. package/src/billing/dashboard/v2/patient-bill-details/attachments/discharge-summary/discharge-summary.tsx +124 -0
  327. package/src/billing/dashboard/v2/patient-bill-details/attachments/final-bill.component.tsx +152 -0
  328. package/src/billing/dashboard/v2/patient-bill-details/attachments/final-bill.scss +225 -0
  329. package/src/billing/dashboard/v2/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.scss +182 -0
  330. package/src/billing/dashboard/v2/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.tsx +173 -0
  331. package/src/billing/dashboard/v2/patient-bill-details/attachments/generate-attachments.component.tsx +371 -0
  332. package/src/billing/dashboard/v2/patient-bill-details/attachments/invoice.component.tsx +151 -0
  333. package/src/billing/dashboard/v2/patient-bill-details/attachments/invoice.scss +225 -0
  334. package/src/billing/dashboard/v2/patient-bill-details/attachments/type.ts +44 -0
  335. package/src/billing/dashboard/v2/patient-bill-details/bill-details/bill-details.scss +107 -0
  336. package/src/billing/dashboard/v2/patient-bill-details/bill-details/bill-details.tsx +508 -0
  337. package/src/billing/dashboard/v2/patient-bill-details/bill-details-page.component.scss +30 -0
  338. package/src/billing/dashboard/v2/patient-bill-details/bill-details-page.component.tsx +94 -0
  339. package/src/billing/dashboard/v2/patient-bill-details/claim-details/claim-details-skeleton.component.scss +89 -0
  340. package/src/billing/dashboard/v2/patient-bill-details/claim-details/claim-details-skeleton.component.tsx +53 -0
  341. package/src/billing/dashboard/v2/patient-bill-details/claim-details/patient-claim-details.component.scss +32 -0
  342. package/src/billing/dashboard/v2/patient-bill-details/claim-details/patient-claim-details.component.tsx +215 -0
  343. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.scss +0 -0
  344. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.tsx +99 -0
  345. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-line/add-claim-line.modal.tsx +187 -0
  346. package/src/billing/dashboard/v2/patient-bill-details/patient-bill-details.scss +153 -0
  347. package/src/billing/dashboard/v2/patient-bill-details/patient-bill-details.tsx +458 -0
  348. package/src/billing/dashboard/v2/patient-bill-details/payment-mode.ts +124 -0
  349. package/src/billing/dashboard/v2/patient-bill-details/workspaces/add-claim-line/add-claim-line.workspace.scss +27 -0
  350. package/src/billing/dashboard/v2/patient-bill-details/workspaces/add-claim-line/add-claim-line.workspace.tsx +223 -0
  351. package/src/billing/dashboard/v2/patient-bill-details/workspaces/bill-item-payment/bill-item-payment.workspace.scss +27 -0
  352. package/src/billing/dashboard/v2/patient-bill-details/workspaces/bill-item-payment/bill-item-payment.workspace.tsx +109 -0
  353. package/src/billing/dashboard/v2/preauth/preauth-attachments.component.tsx +389 -0
  354. package/src/billing/dashboard/v2/preauth/preauth-list.component.scss +38 -0
  355. package/src/billing/dashboard/v2/preauth/preauth-list.component.tsx +241 -0
  356. package/src/billing/dashboard/v2/preauth/preauth-status-tag.component.tsx +75 -0
  357. package/src/billing/dashboard/v2/preauth/preauth-typed-fields.md +125 -0
  358. package/src/billing/dashboard/v2/preauth/preauth.resource.ts +1067 -0
  359. package/src/billing/dashboard/v2/preauth/preauth.workspace.scss +91 -0
  360. package/src/billing/dashboard/v2/preauth/preauth.workspace.tsx +1802 -0
  361. package/src/billing/dashboard/v2/preauth/preauthorizations-tab.component.tsx +49 -0
  362. package/src/billing/dashboard/v2/sha-claims/sha-claims-table.component.tsx +36 -0
  363. package/src/billing/dashboard/v2/sha-claims/sha-claims.component.tsx +60 -0
  364. package/src/billing/dashboard/v2/sha-claims/sha-claims.scss +8 -0
  365. package/src/billing/dashboard/v2/shared/dash-board-card/dash-board-card.component.scss +17 -0
  366. package/src/billing/dashboard/v2/shared/dash-board-card/dash-board-card.component.tsx +15 -0
  367. package/src/billing/dashboard/v2/shared/empty-state.component.scss +24 -0
  368. package/src/billing/dashboard/v2/shared/empty-state.component.tsx +13 -0
  369. package/src/billing/dashboard/v2/shared/scroll-to-top.component.scss +54 -0
  370. package/src/billing/dashboard/v2/shared/scroll-to-top.component.tsx +54 -0
  371. package/src/billing/dashboard/v2/shared/table-toolbar.component.scss +77 -0
  372. package/src/billing/dashboard/v2/shared/table-toolbar.component.tsx +48 -0
  373. package/src/billing/dashboard/v2/types/index.ts +514 -0
  374. package/src/billing/dashboard/v3/active-visits/active-visits.component.tsx +256 -0
  375. package/src/billing/dashboard/v3/active-visits/active-visits.resource.ts +57 -0
  376. package/src/billing/dashboard/v3/active-visits/active-visits.scss +15 -0
  377. package/src/billing/dashboard/v3/cash-checklist/bill-document.component.scss +90 -0
  378. package/src/billing/dashboard/v3/cash-checklist/bill-document.component.tsx +101 -0
  379. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.component.scss +199 -0
  380. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.component.tsx +361 -0
  381. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.resource.ts +240 -0
  382. package/src/billing/dashboard/v3/cash-checklist/payment-drawer.component.scss +246 -0
  383. package/src/billing/dashboard/v3/cash-checklist/payment-drawer.component.tsx +182 -0
  384. package/src/billing/dashboard/v3/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.scss +0 -0
  385. package/src/billing/dashboard/v3/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.tsx +44 -0
  386. package/src/billing/dashboard/v3/claim-visits/claim-doctors/claim-doctors.scss +5 -0
  387. package/src/billing/dashboard/v3/claim-visits/claim-doctors/claim-doctors.tsx +42 -0
  388. package/src/billing/dashboard/v3/claim-visits/claim-documents/claim-documents.scss +10 -0
  389. package/src/billing/dashboard/v3/claim-visits/claim-documents/claim-documents.tsx +25 -0
  390. package/src/billing/dashboard/v3/claim-visits/claim-intervention-details/claim-intervention-details.component.tsx +220 -0
  391. package/src/billing/dashboard/v3/claim-visits/claim-invoice-details/claim-invoice-details.component.scss +6 -0
  392. package/src/billing/dashboard/v3/claim-visits/claim-invoice-details/claim-invoice-details.component.tsx +85 -0
  393. package/src/billing/dashboard/v3/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.scss +0 -0
  394. package/src/billing/dashboard/v3/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.tsx +109 -0
  395. package/src/billing/dashboard/v3/claim-visits/claim-visit-details/claim-visit-details.component.scss +97 -0
  396. package/src/billing/dashboard/v3/claim-visits/claim-visit-details/claim-visit-details.component.tsx +343 -0
  397. package/src/billing/dashboard/v3/claim-visits/claim-visits.component.scss +5 -0
  398. package/src/billing/dashboard/v3/claim-visits/claim-visits.component.tsx +139 -0
  399. package/src/billing/dashboard/v3/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.scss +5 -0
  400. package/src/billing/dashboard/v3/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.tsx +49 -0
  401. package/src/billing/dashboard/v3/claim-visits/modal/claim-invoice-lines/claim-invoice-lines.modal.scss +7 -0
  402. package/src/billing/dashboard/v3/claim-visits/modal/claim-invoice-lines/claim-invoice-lines.modal.tsx +35 -0
  403. package/src/billing/dashboard/v3/claim-visits/modal/claim-visit-details/claim-visit-details.modal.scss +6 -0
  404. package/src/billing/dashboard/v3/claim-visits/modal/claim-visit-details/claim-visit-details.modal.tsx +33 -0
  405. package/src/billing/dashboard/v3/claim-visits/modal/close-claim/close-claim.modal.scss +0 -0
  406. package/src/billing/dashboard/v3/claim-visits/modal/close-claim/close-claim.modal.tsx +129 -0
  407. package/src/billing/dashboard/v3/claim-visits/modal/submit-claim/submit-claim.modal.tsx +204 -0
  408. package/src/billing/dashboard/v3/claim-visits/payer-preview/index.scss +140 -0
  409. package/src/billing/dashboard/v3/claim-visits/payer-preview/payer-preview-tile.component.tsx +55 -0
  410. package/src/billing/dashboard/v3/claim-visits/payer-preview/payer-preview-workspace.component.tsx +157 -0
  411. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-doctors.component.tsx +54 -0
  412. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-lines.component.tsx +48 -0
  413. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-notes.component.tsx +47 -0
  414. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-diagnoses.component.tsx +44 -0
  415. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-interventions.component.tsx +44 -0
  416. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.resource.ts +51 -0
  417. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.workspace.scss +191 -0
  418. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.workspace.tsx +648 -0
  419. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.component.scss +595 -0
  420. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.component.tsx +810 -0
  421. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.resource.ts +282 -0
  422. package/src/billing/dashboard/v3/claims-accounting/bill-utils.ts +134 -0
  423. package/src/billing/dashboard/v3/claims-accounting/claim-detail.component.tsx +346 -0
  424. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.component.scss +546 -0
  425. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.component.tsx +206 -0
  426. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.resource.ts +337 -0
  427. package/src/billing/dashboard/v3/claims-accounting/invoice-document.component.scss +90 -0
  428. package/src/billing/dashboard/v3/claims-accounting/invoice-document.component.tsx +90 -0
  429. package/src/billing/dashboard/v3/claims-accounting/remittances.component.tsx +169 -0
  430. package/src/billing/dashboard/v3/claims-accounting/remittances.resource.ts +46 -0
  431. package/src/billing/dashboard/v3/claims-accounting/status-meta.ts +25 -0
  432. package/src/billing/dashboard/v3/clearance/clearance.component.scss +100 -0
  433. package/src/billing/dashboard/v3/clearance/clearance.component.tsx +0 -0
  434. package/src/billing/dashboard/v3/clearance/prepaid-services.component.tsx +112 -0
  435. package/src/billing/dashboard/v3/facility-bills/claim-status.ts +243 -0
  436. package/src/billing/dashboard/v3/facility-bills/facility-bills.component.scss +72 -0
  437. package/src/billing/dashboard/v3/facility-bills/facility-bills.component.tsx +181 -0
  438. package/src/billing/dashboard/v3/facility-bills/preauths-datatables/pending-preauths.component.tsx +132 -0
  439. package/src/billing/dashboard/v3/facility-bills/preauths-datatables/preauth-preview-table.component.tsx +232 -0
  440. package/src/billing/dashboard/v3/facility-bills/preauths.component.tsx +127 -0
  441. package/src/billing/dashboard/v3/patient-bill-details/attachments/add-attachments.component.tsx +223 -0
  442. package/src/billing/dashboard/v3/patient-bill-details/attachments/attachment.component.tsx +157 -0
  443. package/src/billing/dashboard/v3/patient-bill-details/attachments/attachments.scss +92 -0
  444. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary-helper.ts +58 -0
  445. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary.scss +295 -0
  446. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary.tsx +287 -0
  447. package/src/billing/dashboard/v3/patient-bill-details/attachments/dialysis/dialysis-chart.scss +238 -0
  448. package/src/billing/dashboard/v3/patient-bill-details/attachments/dialysis/dialysis-chart.tsx +317 -0
  449. package/src/billing/dashboard/v3/patient-bill-details/attachments/dialysis/dialysis-helper.ts +94 -0
  450. package/src/billing/dashboard/v3/patient-bill-details/attachments/discharge-summary/discharge-summary.scss +96 -0
  451. package/src/billing/dashboard/v3/patient-bill-details/attachments/discharge-summary/discharge-summary.tsx +126 -0
  452. package/src/billing/dashboard/v3/patient-bill-details/attachments/final-bill.component.tsx +75 -0
  453. package/src/billing/dashboard/v3/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.scss +182 -0
  454. package/src/billing/dashboard/v3/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.tsx +253 -0
  455. package/src/billing/dashboard/v3/patient-bill-details/attachments/generate-attachments.component.tsx +345 -0
  456. package/src/billing/dashboard/v3/patient-bill-details/attachments/invoice.component.tsx +150 -0
  457. package/src/billing/dashboard/v3/patient-bill-details/attachments/invoice.scss +225 -0
  458. package/src/billing/dashboard/v3/patient-bill-details/attachments/type.ts +259 -0
  459. package/src/billing/dashboard/v3/patient-bill-details/bill-details/bill-details.scss +17 -0
  460. package/src/billing/dashboard/v3/patient-bill-details/bill-details/bill-details.tsx +260 -0
  461. package/src/billing/dashboard/v3/patient-bill-details/claim-details/patient-claim-details.component.scss +0 -0
  462. package/src/billing/dashboard/v3/patient-bill-details/claim-details/patient-claim-details.component.tsx +68 -0
  463. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.scss +0 -0
  464. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.tsx +99 -0
  465. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-line/add-claim-line.modal.scss +14 -0
  466. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-line/add-claim-line.modal.tsx +112 -0
  467. package/src/billing/dashboard/v3/patient-bill-details/modals/bill-item-payment/bill-item-payment.modal.scss +6 -0
  468. package/src/billing/dashboard/v3/patient-bill-details/modals/bill-item-payment/bill-item-payment.modal.tsx +139 -0
  469. package/src/billing/dashboard/v3/patient-bill-details/patient-bill-details.scss +85 -0
  470. package/src/billing/dashboard/v3/patient-bill-details/patient-bill-details.tsx +343 -0
  471. package/src/billing/dashboard/v3/patient-bill-details/visit-diagnosis-details/visit-diagnosis-details.component.scss +0 -0
  472. package/src/billing/dashboard/v3/patient-bill-details/visit-diagnosis-details/visit-diagnosis-details.component.tsx +92 -0
  473. package/src/billing/dashboard/v3/preauth/elective/elective-authorize.resource.ts +284 -0
  474. package/src/billing/dashboard/v3/preauth/elective/elective-preauth-request.workspace.scss +125 -0
  475. package/src/billing/dashboard/v3/preauth/elective/elective-preauth-request.workspace.tsx +1184 -0
  476. package/src/billing/dashboard/v3/preauth/elective/elective-preauth.component.scss +15 -0
  477. package/src/billing/dashboard/v3/preauth/elective/elective-preauth.component.tsx +377 -0
  478. package/src/billing/dashboard/v3/preauth/elective/elective-preauth.resource.ts +1378 -0
  479. package/src/billing/dashboard/v3/preauth/elective/elective-requests-list.component.tsx +357 -0
  480. package/src/billing/dashboard/v3/preauth/preauth-attachments.component.tsx +389 -0
  481. package/src/billing/dashboard/v3/preauth/preauth-list.component.scss +34 -0
  482. package/src/billing/dashboard/v3/preauth/preauth-list.component.tsx +300 -0
  483. package/src/billing/dashboard/v3/preauth/preauth-status-tag.component.tsx +75 -0
  484. package/src/billing/dashboard/v3/preauth/preauth-typed-fields.md +125 -0
  485. package/src/billing/dashboard/v3/preauth/preauth.resource.ts +1197 -0
  486. package/src/billing/dashboard/v3/preauth/preauth.workspace.scss +176 -0
  487. package/src/billing/dashboard/v3/preauth/preauth.workspace.tsx +2266 -0
  488. package/src/billing/dashboard/v3/preauth/preauthorizations-tab.component.tsx +55 -0
  489. package/src/billing/dashboard/v3/shared/empty-state.component.scss +25 -0
  490. package/src/billing/dashboard/v3/shared/empty-state.component.tsx +13 -0
  491. package/src/billing/dashboard/v3/shared/table-toolbar.component.scss +64 -0
  492. package/src/billing/dashboard/v3/shared/table-toolbar.component.tsx +48 -0
  493. package/src/billing/dashboard/v3/types/index.ts +384 -0
  494. package/src/billing/extensions/generate-order-bill-button/generate-order-bill-button.extension.tsx +55 -0
  495. package/src/billing/extensions/generate-order-bill-button/generate-order-bill-button.scss +16 -0
  496. package/src/billing/extensions/visit-billing/visit-billing.extension.scss +0 -0
  497. package/src/billing/extensions/visit-billing/visit-billing.extension.tsx +509 -0
  498. package/src/billing/invoice/bill.resource.ts +47 -0
  499. package/src/billing/invoice/invoice-header/header-card/header-card.scss +17 -0
  500. package/src/billing/invoice/invoice-header/header-card/header-card.tsx +21 -0
  501. package/src/billing/invoice/invoice.scss +113 -0
  502. package/src/billing/invoice/invoice.tsx +1441 -0
  503. package/src/billing/invoice/line-items/line-items.scss +0 -0
  504. package/src/billing/invoice/line-items/line-items.tsx +120 -0
  505. package/src/billing/invoice/modal/delete-bill-item/delete-bill-item.modal.scss +23 -0
  506. package/src/billing/invoice/modal/delete-bill-item/delete-bill-item.modal.tsx +114 -0
  507. package/src/billing/invoice/modal/edit-bill-item/edit-bill-item.modal.scss +0 -0
  508. package/src/billing/invoice/modal/edit-bill-item/edit-bill-item.modal.tsx +122 -0
  509. package/src/billing/invoice/payment-details/payment-details.scss +0 -0
  510. package/src/billing/invoice/payment-details/payment-details.tsx +43 -0
  511. package/src/billing/invoice/print-invoice/print-receipt.component.tsx +44 -0
  512. package/src/billing/invoice/print-invoice/print-receipt.scss +14 -0
  513. package/src/billing/maternity-discharge.resource.ts +21 -0
  514. package/src/billing/types/index.ts +354 -0
  515. package/src/billing/utils/index.ts +17 -0
  516. package/src/billing/widgets/billingTotalsRow.component.scss +0 -0
  517. package/src/billing/widgets/billingTotalsRow.component.tsx +712 -0
  518. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.resource.ts +130 -0
  519. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.scss +58 -0
  520. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.workspace.tsx +656 -0
  521. package/src/billing/workspaces/create-order-bill-form-workspace/schema.ts +12 -0
  522. package/src/bookings/bookings.component.scss +7 -0
  523. package/src/bookings/bookings.component.tsx +35 -0
  524. package/src/bookings/daily/daily-bookings.resource.ts +2 -1
  525. package/src/case-summary/case-summary.extension.scss +13 -0
  526. package/src/case-summary/case-summary.extension.tsx +40 -0
  527. package/src/case-summary/case-summary.resource.test.ts +69 -0
  528. package/src/case-summary/case-summary.resource.ts +52 -0
  529. package/src/case-summary/components/case-summary-printable.component.scss +174 -0
  530. package/src/case-summary/components/case-summary-printable.component.tsx +288 -0
  531. package/src/case-summary/components/case-summary-printable.utils.ts +51 -0
  532. package/src/case-summary/types/case-summary.types.ts +152 -0
  533. package/src/claims/claims.component.scss +70 -0
  534. package/src/claims/claims.component.tsx +743 -0
  535. package/src/claims/claims.resource.ts +1840 -0
  536. package/src/claims/index.ts +365 -0
  537. package/src/claims/interventions.resource.ts +131 -0
  538. package/src/claims/utils.ts +64 -0
  539. package/src/config-schema.ts +149 -1
  540. package/src/context/patient-context.tsx +27 -0
  541. package/src/createDashboardLink.tsx +9 -0
  542. package/src/dashboard/charts/chart.component.scss +24 -0
  543. package/src/dashboard/charts/chart.component.tsx +56 -0
  544. package/src/dashboard/dashboard.component.scss +48 -3
  545. package/src/dashboard/dashboard.component.tsx +29 -38
  546. package/src/dashboard/overview/overview.component.scss +40 -59
  547. package/src/dashboard/overview/overview.component.tsx +55 -41
  548. package/src/dashboard-meta/accounting-dashboard.meta.ts +6 -0
  549. package/src/dashboard-meta/admissions-dashboard.meta.ts +6 -0
  550. package/src/dashboard-meta/billing-dashboard.meta.ts +6 -0
  551. package/src/dashboard-meta/bookings-dashboard.meta.ts +6 -0
  552. package/src/dashboard-meta/case-summary.meta.ts +6 -0
  553. package/src/dashboard-meta/consultation-dashboard.meta.ts +6 -0
  554. package/src/dashboard-meta/dha-workflow-dashboard.meta.ts +6 -0
  555. package/src/dashboard-meta/elective-preauth.meta.ts +6 -0
  556. package/src/dashboard-meta/emt-dashboard.meta.ts +6 -0
  557. package/src/dashboard-meta/inpatient-admissions.meta.ts +6 -0
  558. package/src/dashboard-meta/maternity-dashboard.meta.ts +6 -0
  559. package/src/dashboard-meta/mch-dashboard.meta.ts +6 -0
  560. package/src/dashboard-meta/pharmacy-dashboard.meta.ts +6 -0
  561. package/src/dashboard-meta/queue-dashboard.meta.ts +6 -0
  562. package/src/dashboard-meta/registers-dashboard.meta.ts +6 -0
  563. package/src/dashboard-meta/registry-dashboard.meta.ts +6 -0
  564. package/src/dashboard-meta/service-queue-admin.meta.ts +6 -0
  565. package/src/dashboard-meta/specialized-clinics-dashboard.meta.ts +6 -0
  566. package/src/dashboard-meta/triage-dashboard.meta.ts +6 -0
  567. package/src/emt/cr-lookup.resource.test.ts +88 -0
  568. package/src/emt/cr-lookup.resource.ts +42 -0
  569. package/src/emt/emt-queue.component.test.tsx +353 -0
  570. package/src/emt/emt-queue.component.tsx +463 -0
  571. package/src/emt/emt-queue.scss +85 -0
  572. package/src/emt/emt.resource.test.ts +247 -0
  573. package/src/emt/emt.resource.ts +150 -0
  574. package/src/emt/handover-modal/handover-modal.component.test.tsx +273 -0
  575. package/src/emt/handover-modal/handover-modal.component.tsx +541 -0
  576. package/src/emt/handover-modal/handover-modal.scss +113 -0
  577. package/src/emt/types/emt.types.ts +137 -0
  578. package/src/index.ts +204 -6
  579. package/src/mnch/maternity/maternity-queues.component.scss +7 -0
  580. package/src/mnch/maternity/maternity-queues.component.tsx +32 -0
  581. package/src/mnch/maternity/queues/triage/maternity-triage.tsx +15 -0
  582. package/src/mnch/mch/mch-queues.component.scss +10 -0
  583. package/src/mnch/mch/mch-queues.component.tsx +36 -0
  584. package/src/mnch/mch/queues/consultation/mch-consultation.tsx +18 -0
  585. package/src/mnch/mch/queues/triage/mch-triage.tsx +15 -0
  586. package/src/mnch/mnch-root.tsx +17 -0
  587. package/src/mortuary/mortuary.component.tsx +13 -0
  588. package/src/pharmacy/pharmacy.component.scss +16 -0
  589. package/src/pharmacy/pharmacy.component.tsx +11 -6
  590. package/src/registers/registers.component.tsx +8 -0
  591. package/src/registry/drawer/emr-compare.component.scss +263 -0
  592. package/src/registry/drawer/emr-compare.component.tsx +302 -0
  593. package/src/registry/drawer/emr-compare.resource.ts +181 -0
  594. package/src/registry/drawer/emr-create-preview.component.tsx +123 -0
  595. package/src/registry/drawer/otp-verification-step.component.tsx +398 -0
  596. package/src/registry/drawer/pomsf-balance.util.test.ts +177 -0
  597. package/src/registry/drawer/pomsf-balance.util.ts +79 -0
  598. package/src/registry/drawer/verification.resource.ts +60 -0
  599. package/src/registry/drawer/workflow-drawer.component.scss +1242 -0
  600. package/src/registry/drawer/workflow-drawer.component.tsx +1478 -0
  601. package/src/registry/eligibility/eligibility-details/eligibility-details.scss +38 -0
  602. package/src/registry/eligibility/eligibility-details/eligibility-details.tsx +101 -0
  603. package/src/registry/eligibility/eliigibility-tags/eligibility-tags.scss +16 -0
  604. package/src/registry/eligibility/eliigibility-tags/eligibility-tags.tsx +120 -0
  605. package/src/registry/eligibility/modal/eligibility-details.modal.scss +0 -0
  606. package/src/registry/eligibility/modal/eligibility-details.modal.tsx +45 -0
  607. package/src/registry/hie.resource.ts +466 -0
  608. package/src/registry/hie.types.ts +63 -0
  609. package/src/registry/modal/biometrics-verification-modal/biometrics-verification-modal.scss +277 -0
  610. package/src/registry/modal/biometrics-verification-modal/biometrics-verification-modal.tsx +218 -0
  611. package/src/registry/modal/biometrics-verification-modal/type.ts +39 -0
  612. package/src/registry/modal/client-details-modal/client-details-modal.tsx +65 -29
  613. package/src/registry/modal/otp-modal/otp-whitlisting-modal.component.tsx +809 -0
  614. package/src/registry/modal/otp-modal/otp-whitlisting-modal.scss +354 -0
  615. package/src/registry/modal/otp-modal/otp-whitlisting.scss +0 -0
  616. package/src/registry/modal/otp-verification-modal/claims-consent.scss +72 -0
  617. package/src/registry/modal/otp-verification-modal/claims-consent.tsx +135 -0
  618. package/src/registry/modal/otp-verification-modal/extension/claims-consent.extension.tsx +130 -0
  619. package/src/registry/modal/otp-verification-modal/otp-verification-modal.scss +30 -0
  620. package/src/registry/modal/otp-verification-modal/otp-verification-modal.tsx +154 -54
  621. package/src/registry/modal/send-to-triage/payment-details.tsx +120 -0
  622. package/src/registry/modal/send-to-triage/payment-method.component.tsx +54 -0
  623. package/src/registry/modal/send-to-triage/send-to-queue.modal.tsx +981 -0
  624. package/src/registry/modal/send-to-triage/send-to-triage.modal.scss +156 -3
  625. package/src/registry/modal/send-to-triage/send-to-triage.modal.tsx +1094 -135
  626. package/src/registry/modal/start-patient-visit/start-patient-visit.modal.scss +34 -0
  627. package/src/registry/modal/start-patient-visit/start-patient-visit.modal.tsx +231 -0
  628. package/src/registry/payment-details/payment-options/payment-options.scss +13 -0
  629. package/src/registry/payment-details/payment-options/payment-options.tsx +61 -14
  630. package/src/registry/registration-list/registration-list.component.scss +32 -0
  631. package/src/registry/registration-list/registration-list.component.tsx +103 -0
  632. package/src/registry/registry-entry.tsx +11 -0
  633. package/src/registry/registry.component.scss +402 -78
  634. package/src/registry/registry.component.tsx +602 -222
  635. package/src/registry/registry.resource.ts +22 -3
  636. package/src/registry/types/index.ts +118 -9
  637. package/src/registry/utils/error-handler.ts +54 -0
  638. package/src/registry/utils/format-dependant-display-data.ts +1 -1
  639. package/src/registry/utils/hie-client-adapter.ts +7 -4
  640. package/src/registry/utils/mask-data.ts +40 -0
  641. package/src/registry/utils/phone-number-formatter.ts +11 -0
  642. package/src/resources/dashboard.resource.ts +20 -0
  643. package/src/resources/identifier-types.ts +2 -0
  644. package/src/resources/patient-resource.ts +6 -1
  645. package/src/resources/queue.resource.ts +24 -1
  646. package/src/resources/superset.resource.ts +21 -0
  647. package/src/resources/visit.resource.ts +19 -1
  648. package/src/root.component.tsx +10 -5
  649. package/src/routes.json +477 -23
  650. package/src/service-queues/admin/queue/modal/create-queue/create-queue.modal.scss +31 -0
  651. package/src/service-queues/admin/queue/modal/create-queue/create-queue.modal.tsx +153 -0
  652. package/src/service-queues/admin/queue/modal/edit-queue/edit-queue.modal.scss +0 -0
  653. package/src/service-queues/admin/queue/modal/edit-queue/edit-queue.modal.tsx +182 -0
  654. package/src/service-queues/admin/queue/queue-list/queue-list.scss +33 -0
  655. package/src/service-queues/admin/queue/queue-list/queue-list.tsx +113 -0
  656. package/src/service-queues/admin/queue-entry/queue-entry-list.component.scss +6 -0
  657. package/src/service-queues/admin/queue-entry/queue-entry-list.component.tsx +137 -0
  658. package/src/service-queues/admin/queue-room/modal/create-queue-room/create-queue-room.modal.scss +31 -0
  659. package/src/service-queues/admin/queue-room/modal/create-queue-room/create-queue-room.modal.tsx +137 -0
  660. package/src/service-queues/admin/queue-room/modal/edit-queue-room/edit-queue-room.modal.scss +0 -0
  661. package/src/service-queues/admin/queue-room/modal/edit-queue-room/edit-queue-room.modal.tsx +146 -0
  662. package/src/service-queues/admin/queue-room/queue-room-list/queue-room-list.scss +22 -0
  663. package/src/service-queues/admin/queue-room/queue-room-list/queue-room-list.tsx +120 -0
  664. package/src/service-queues/admin/service-queue-admin-dashboard.component.scss +6 -0
  665. package/src/service-queues/admin/service-queue-admin-dashboard.component.tsx +34 -0
  666. package/src/service-queues/consultation/consultation.component.tsx +9 -0
  667. package/src/service-queues/extensions/service-queue-patient-banner/service-queue-patient-banner.scss +30 -0
  668. package/src/service-queues/extensions/service-queue-patient-banner/service-queue-patient-banner.tsx +108 -0
  669. package/src/service-queues/modals/daily-report-patient-list/daily-report-patient-list.scss +26 -0
  670. package/src/service-queues/modals/daily-report-patient-list/daily-report-patient-list.tsx +110 -0
  671. package/src/service-queues/modals/move/move-patient.component.scss +1 -1
  672. package/src/service-queues/modals/move/move-patient.component.tsx +31 -17
  673. package/src/service-queues/queue-list/check-in.service.ts +26 -0
  674. package/src/service-queues/queue-list/queue-list.component.scss +37 -0
  675. package/src/service-queues/queue-list/queue-list.component.tsx +256 -56
  676. package/src/service-queues/service-queue/service-queue.component.tsx +151 -8
  677. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.scss +5 -0
  678. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.tsx +36 -7
  679. package/src/service-queues/service-queue.tsx +22 -16
  680. package/src/service-queues/service-queues.resource.ts +197 -1
  681. package/src/service-queues/service.resource.ts +1 -1
  682. package/src/shared/constants/concepts.ts +50 -0
  683. package/src/shared/constants/patient-category.ts +6 -0
  684. package/src/shared/constants/patient-type.ts +10 -0
  685. package/src/shared/constants/visit-types.ts +7 -0
  686. package/src/shared/services/billing.resource.ts +75 -0
  687. package/src/shared/services/claims.resource.ts +47 -0
  688. package/src/shared/services/client-payment-mode.resource.ts +27 -0
  689. package/src/shared/services/client-payment.resource.ts +17 -0
  690. package/src/shared/services/consultation-clearance.resource.ts +210 -0
  691. package/src/shared/services/eligibility.resource.ts +20 -0
  692. package/src/shared/services/encounters.resource.ts +33 -0
  693. package/src/shared/services/location.resource.ts +9 -0
  694. package/src/shared/types/index.ts +156 -0
  695. package/src/shared/ui/aggregate-stat-card/aggregate-stat-card.scss +42 -0
  696. package/src/shared/ui/aggregate-stat-card/aggregate-stat-card.tsx +42 -0
  697. package/src/shared/ui/confirm-modal/confirm.modal.scss +18 -0
  698. package/src/shared/ui/confirm-modal/confirm.modal.tsx +38 -0
  699. package/src/shared/ui/facility-worker-slot/facility-worker.component-slot.component.scss +39 -0
  700. package/src/shared/ui/facility-worker-slot/facility-worker.component-slot.component.tsx +19 -0
  701. package/src/shared/ui/otp-input/otp-input.component.scss +14 -0
  702. package/src/shared/ui/otp-input/otp-input.component.tsx +97 -0
  703. package/src/{service-queues/service-queue/stats → shared/ui}/stat-card/stat-card.component.tsx +6 -3
  704. package/src/shared/ui/timer/timer.component.scss +5 -0
  705. package/src/shared/ui/timer/timer.component.tsx +40 -0
  706. package/src/shared/utils/get-base-url.ts +15 -0
  707. package/src/shared/utils/get-tag-type.ts +75 -0
  708. package/src/side-nav-menu/mnch-nav-link-config.ts +16 -0
  709. package/src/side-nav-menu/mnch-nav-links.tsx +42 -0
  710. package/src/side-nav-menu/nav-link-config.ts +5 -5
  711. package/src/side-nav-menu/specialized-clinics-nav-link-config.ts +36 -0
  712. package/src/side-nav-menu/specialized-clinics-nav-links.tsx +42 -0
  713. package/src/specialized-clinics/critital-care-unit/critical-care-unit-queues.component.scss +7 -0
  714. package/src/specialized-clinics/critital-care-unit/critical-care-unit-queues.component.tsx +36 -0
  715. package/src/specialized-clinics/critital-care-unit/queues/consultation/critical-care-unit-consultation.tsx +15 -0
  716. package/src/specialized-clinics/critital-care-unit/queues/triage/critical-care-unit-triage.tsx +15 -0
  717. package/src/specialized-clinics/dental/dental-queues.component.scss +7 -0
  718. package/src/specialized-clinics/dental/dental-queues.component.tsx +36 -0
  719. package/src/specialized-clinics/dental/queues/consultation/dental-consultation.tsx +15 -0
  720. package/src/specialized-clinics/dental/queues/triage/dental-triage.tsx +15 -0
  721. package/src/specialized-clinics/diagnostic-and-imaging/diagnostic-and-imaging.component.scss +7 -0
  722. package/src/specialized-clinics/diagnostic-and-imaging/diagnostic-and-imaging.component.tsx +36 -0
  723. package/src/specialized-clinics/diagnostic-and-imaging/queues/consultation/diagnosis-and-imaging-consultation.tsx +15 -0
  724. package/src/specialized-clinics/diagnostic-and-imaging/queues/triage/diagnosis-and-imaging-triage.tsx +15 -0
  725. package/src/specialized-clinics/oncology/oncology-queues.component.scss +7 -0
  726. package/src/specialized-clinics/oncology/oncology-queues.component.tsx +36 -0
  727. package/src/specialized-clinics/oncology/queues/consultation/oncology-consultation.tsx +15 -0
  728. package/src/specialized-clinics/oncology/queues/triage/oncology-triage.tsx +15 -0
  729. package/src/specialized-clinics/ophthalmology/ophthalmology-queues.component.scss +7 -0
  730. package/src/specialized-clinics/ophthalmology/ophthalmology-queues.component.tsx +36 -0
  731. package/src/specialized-clinics/ophthalmology/queues/consultation/ophthalmology-consultation.tsx +15 -0
  732. package/src/specialized-clinics/ophthalmology/queues/triage/ophthalmology-triage.tsx +15 -0
  733. package/src/specialized-clinics/psychiatry/psychiatry-queues.component.scss +7 -0
  734. package/src/specialized-clinics/psychiatry/psychiatry-queues.component.tsx +36 -0
  735. package/src/specialized-clinics/psychiatry/queues/consultation/psychiatry-consultation.tsx +15 -0
  736. package/src/specialized-clinics/psychiatry/queues/triage/psychiatry-triage.tsx +15 -0
  737. package/src/specialized-clinics/renal/queues/consultation/dialysis-consultation.tsx +15 -0
  738. package/src/specialized-clinics/renal/queues/triage/renal-triage.tsx +15 -0
  739. package/src/specialized-clinics/renal/renal-queues.component.scss +7 -0
  740. package/src/specialized-clinics/renal/renal-queues.component.tsx +36 -0
  741. package/src/specialized-clinics/specialized-clinics-root.tsx +27 -0
  742. package/src/triage/triage.component.scss +6 -0
  743. package/src/triage/triage.component.tsx +4 -0
  744. package/src/types/types.ts +56 -1
  745. package/webpack.config.js +54 -1
  746. package/dist/104.js +0 -2
  747. package/dist/104.js.map +0 -1
  748. package/dist/15.js +0 -1
  749. package/dist/15.js.map +0 -1
  750. package/dist/184.js +0 -2
  751. package/dist/184.js.map +0 -1
  752. package/dist/197.js +0 -1
  753. package/dist/246.js +0 -2
  754. package/dist/246.js.map +0 -1
  755. package/dist/255.js +0 -1
  756. package/dist/255.js.map +0 -1
  757. package/dist/300.js +0 -1
  758. package/dist/335.js +0 -1
  759. package/dist/339.js +0 -1
  760. package/dist/339.js.map +0 -1
  761. package/dist/353.js +0 -1
  762. package/dist/353.js.map +0 -1
  763. package/dist/420.js +0 -1
  764. package/dist/420.js.map +0 -1
  765. package/dist/540.js +0 -2
  766. package/dist/540.js.map +0 -1
  767. package/dist/55.js +0 -1
  768. package/dist/652.js +0 -1
  769. package/dist/709.js +0 -1
  770. package/dist/709.js.map +0 -1
  771. package/dist/710.js +0 -2
  772. package/dist/710.js.map +0 -1
  773. package/dist/729.js +0 -1
  774. package/dist/729.js.map +0 -1
  775. package/dist/752.js +0 -1
  776. package/dist/752.js.map +0 -1
  777. package/dist/833.js +0 -1
  778. package/dist/833.js.map +0 -1
  779. package/dist/907.js +0 -1
  780. package/dist/907.js.map +0 -1
  781. package/dist/91.js +0 -1
  782. package/dist/91.js.map +0 -1
  783. package/dist/93.js +0 -1
  784. package/dist/93.js.map +0 -1
  785. package/dist/943.js +0 -1
  786. package/dist/943.js.map +0 -1
  787. package/dist/99.js +0 -1
  788. /package/dist/{104.js.LICENSE.txt → 2177.js.LICENSE.txt} +0 -0
  789. /package/dist/{184.js.LICENSE.txt → 3184.js.LICENSE.txt} +0 -0
  790. /package/dist/{540.js.LICENSE.txt → 6540.js.LICENSE.txt} +0 -0
  791. /package/dist/{710.js.LICENSE.txt → 7830.js.LICENSE.txt} +0 -0
  792. /package/dist/{246.js.LICENSE.txt → 9583.js.LICENSE.txt} +0 -0
  793. /package/src/{service-queues/service-queue/stats → shared/ui}/stat-card/stat-card.component.scss +0 -0
@@ -0,0 +1,1478 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import {
3
+ Button,
4
+ ComboBox,
5
+ Dropdown,
6
+ FileUploaderItem,
7
+ FormLabel,
8
+ InlineLoading,
9
+ Modal,
10
+ ProgressIndicator,
11
+ ProgressStep,
12
+ RadioButton,
13
+ RadioButtonGroup,
14
+ Table,
15
+ TableBody,
16
+ TableCell,
17
+ TableHead,
18
+ TableHeader,
19
+ TableRow,
20
+ Tag,
21
+ } from '@carbon/react';
22
+ import {
23
+ ArrowRight,
24
+ CheckboxCheckedFilled,
25
+ CheckmarkOutline,
26
+ CloudUpload,
27
+ Close,
28
+ FingerprintRecognition,
29
+ Information,
30
+ PendingFilled,
31
+ Renew,
32
+ ScanDisabled,
33
+ WarningAltFilled,
34
+ } from '@carbon/react/icons';
35
+ import { type Patient, showSnackbar } from '@openmrs/esm-framework';
36
+ import styles from './workflow-drawer.component.scss';
37
+ import { type HieClient, type RequestCustomOtpDto, type Scheme } from '../types';
38
+ import { getClientEligibityStatus } from '../../shared/services/eligibility.resource';
39
+ import { maskCrNumber, maskExceptFirstAndLast } from '../utils/mask-data';
40
+ import OtpVerificationStep from './otp-verification-step.component';
41
+ import EmrCompare from './emr-compare.component';
42
+ import EmrCreatePreview from './emr-create-preview.component';
43
+ import {
44
+ getBiometricCaptureUrl,
45
+ getOtpWhitelistStatus,
46
+ isBiometricConfigured,
47
+ requestOtpWhitelist,
48
+ } from './verification.resource';
49
+ import { fetchServiceQueuesByLocationUuid } from '../../resources/queue.resource';
50
+ import { fetchCashPoints, fetchPaymentModes } from '../../shared/services/billing.resource';
51
+ import { getReadableErrorMessage } from '../utils/error-handler';
52
+ import { fetchPomsfBalance } from '../../claims/claims.resource';
53
+ import { type PomsfBalance } from '../../claims';
54
+ import { formatKes, getAllPomsfBenefitBalances, getPomsfDisplayBalance, isPomsfActive } from './pomsf-balance.util';
55
+
56
+ type Phase =
57
+ | 'biometric'
58
+ | 'biometric-not-setup'
59
+ | 'otp-gate'
60
+ | 'whitelist-request'
61
+ | 'whitelist-pending'
62
+ | 'otp'
63
+ | 'consent'
64
+ | 'visit';
65
+
66
+ type Method = 'cash' | 'insurance';
67
+
68
+ type RequiredField = 'visitType' | 'room' | 'insurance';
69
+
70
+ const STEPS = ['Verify & consent', 'Start visit'];
71
+ const BIOMETRIC_MAX_ATTEMPTS = 3;
72
+
73
+ // Decode HTML entities in backend-provided names (e.g. "Accident & Emergency").
74
+ function decodeHtmlEntities(value: string): string {
75
+ if (!value || typeof document === 'undefined') {
76
+ return value;
77
+ }
78
+ const el = document.createElement('textarea');
79
+ el.innerHTML = value;
80
+ return el.value;
81
+ }
82
+ const OTP_EXPIRY_SECONDS = 300; // 5 minutes
83
+
84
+ // Where the patient is sent first, and the rooms available for each category.
85
+ const PATIENT_CATEGORIES = ['Triage', 'Walk-in', 'CCC'];
86
+ const WALK_IN_ROOMS = [];
87
+
88
+ // Payment modes that are direct payment (not insurance schemes) — excluded from
89
+ // the insurance-scheme list.
90
+ const NON_INSURANCE_PAYMENT_MODES = /cash|mpesa|m-pesa|waiver/i;
91
+
92
+ // OpenMRS visit types (searchable).
93
+ const VISIT_TYPE_OPTIONS = ['Outpatient', 'Inpatient'];
94
+
95
+ // Keys that still have to work while an option is selected: menu navigation, commit
96
+ // and dismiss. Everything else that would mutate the text is blocked below.
97
+ const SELECTION_NAV_KEYS = new Set([
98
+ 'Tab',
99
+ 'Enter',
100
+ 'Escape',
101
+ 'ArrowUp',
102
+ 'ArrowDown',
103
+ 'ArrowLeft',
104
+ 'ArrowRight',
105
+ 'Home',
106
+ 'End',
107
+ 'Shift',
108
+ 'Control',
109
+ 'Alt',
110
+ 'Meta',
111
+ ]);
112
+
113
+ // A picked option behaves as a single locked token: while one is selected the field
114
+ // can't be typed into, pasted into, or erased from the keyboard, so it can never hold
115
+ // a half-edited label that still reads as a valid selection. Clearing is deliberate —
116
+ // only the combo box's ✕ button removes a selection. Bound on the wrapper in the
117
+ // capture phase so these run before Carbon's own handlers.
118
+ function lockSelection(hasSelection: boolean) {
119
+ const block = (event: React.SyntheticEvent) => {
120
+ event.preventDefault();
121
+ event.stopPropagation();
122
+ };
123
+ return {
124
+ onKeyDownCapture: (event: React.KeyboardEvent) => {
125
+ if (!hasSelection) {
126
+ return;
127
+ }
128
+ // Backspace/Delete included: use the ✕ button to change a selection.
129
+ if (event.key === 'Backspace' || event.key === 'Delete') {
130
+ block(event);
131
+ return;
132
+ }
133
+ // Let shortcuts through — an actual paste is stopped by onPasteCapture.
134
+ if (SELECTION_NAV_KEYS.has(event.key) || event.ctrlKey || event.metaKey) {
135
+ return;
136
+ }
137
+ // Any single-character key would append to the locked label.
138
+ if (event.key.length === 1) {
139
+ block(event);
140
+ }
141
+ },
142
+ onPasteCapture: (event: React.ClipboardEvent) => {
143
+ if (hasSelection) {
144
+ block(event);
145
+ }
146
+ },
147
+ };
148
+ }
149
+
150
+ // Carbon's ComboBox shows every item unless it's given a shouldFilterItem, so each
151
+ // searchable dropdown gets one of these. Once an item is picked Carbon puts its label
152
+ // in the input, which would otherwise filter the reopened menu down to that one item —
153
+ // hence treating "input equals the current selection" as an empty query.
154
+ function filterByLabel<T>(toLabel: (item: T) => string, selectedLabel: string) {
155
+ return ({ item, inputValue }: { item: T; inputValue: string | null }) => {
156
+ const query = (inputValue ?? '').trim().toLowerCase();
157
+ if (!query || query === (selectedLabel ?? '').trim().toLowerCase()) {
158
+ return true;
159
+ }
160
+ return toLabel(item).toLowerCase().includes(query);
161
+ };
162
+ }
163
+
164
+ // Reasons biometric identification could not be used (option set for the request).
165
+ const WHITELIST_REASONS = [
166
+ 'Biometric device not working',
167
+ 'Patient fingerprints not readable',
168
+ 'Patient has no usable fingerprints',
169
+ 'Fingerprint repeatedly not matching',
170
+ 'Other',
171
+ ];
172
+
173
+ const phaseToIndex: Record<Phase, number> = {
174
+ biometric: 0,
175
+ 'biometric-not-setup': 0,
176
+ 'otp-gate': 0,
177
+ 'whitelist-request': 0,
178
+ 'whitelist-pending': 0,
179
+ otp: 0,
180
+ consent: 0,
181
+ visit: 1,
182
+ };
183
+
184
+ interface WorkflowDrawerProps {
185
+ open: boolean;
186
+ client?: HieClient;
187
+ clientType?: string;
188
+ locationUuid?: string;
189
+ requestCustomOtpDto?: RequestCustomOtpDto;
190
+ phoneNumber?: string;
191
+ // EMR lookup result for the client, so the user can create or sync the record.
192
+ amrsPatient?: Patient | null;
193
+ amrsChecked?: boolean;
194
+ syncingAmrs?: boolean;
195
+ onCreatePatient?: () => void;
196
+ onSyncPatient?: () => void;
197
+ onClose: () => void;
198
+ onStartVisit: (details: {
199
+ patientCategory: string;
200
+ room: string;
201
+ roomUuid: string;
202
+ visitType: string;
203
+ method?: Method;
204
+ insurance?: string;
205
+ }) => void;
206
+ }
207
+
208
+ const WorkflowDrawer: React.FC<WorkflowDrawerProps> = ({
209
+ open,
210
+ client,
211
+ clientType,
212
+ locationUuid,
213
+ requestCustomOtpDto,
214
+ phoneNumber,
215
+ amrsPatient,
216
+ amrsChecked,
217
+ syncingAmrs,
218
+ onCreatePatient,
219
+ onSyncPatient,
220
+ onClose,
221
+ onStartVisit,
222
+ }) => {
223
+ const [phase, setPhase] = useState<Phase>('biometric');
224
+ const [pendingEmrAction, setPendingEmrAction] = useState<'create' | 'sync' | null>(null);
225
+ const [isOtpWhitelisted, setIsOtpWhitelisted] = useState(false);
226
+ const [consent, setConsent] = useState(false);
227
+ const [launchingBiometric, setLaunchingBiometric] = useState(false);
228
+ const [biometricUrl, setBiometricUrl] = useState<string | null>(null);
229
+ const [failCount, setFailCount] = useState(0);
230
+ const [checkingWhitelist, setCheckingWhitelist] = useState(false);
231
+ const [submittingWhitelist, setSubmittingWhitelist] = useState(false);
232
+ const [showWhitelistForm, setShowWhitelistForm] = useState(false);
233
+ const [reason, setReason] = useState('');
234
+ const [failedImage, setFailedImage] = useState<File | null>(null);
235
+ const [reasonError, setReasonError] = useState('');
236
+ const [imageError, setImageError] = useState('');
237
+ const [dragOver, setDragOver] = useState(false);
238
+ const fileInputRef = useRef<HTMLInputElement>(null);
239
+ const [method, setMethod] = useState<Method>('insurance');
240
+ const [patientCategory, setPatientCategory] = useState<string>(PATIENT_CATEGORIES[0]);
241
+ const [room, setRoom] = useState<string>('');
242
+ const [insurance, setInsurance] = useState<string>('');
243
+ const [visitType, setVisitType] = useState<string>('');
244
+ const [triageRooms, setTriageRooms] = useState<string[]>([]);
245
+ // Maps each triage room label to its service-queue uuid, needed to enqueue the patient.
246
+ const [triageQueueByRoom, setTriageQueueByRoom] = useState<Record<string, string>>({});
247
+ const [loadingRooms, setLoadingRooms] = useState(false);
248
+ const [insuranceSchemes, setInsuranceSchemes] = useState<string[]>([]);
249
+ const [loadingSchemes, setLoadingSchemes] = useState(false);
250
+ const [hasCashPoint, setHasCashPoint] = useState<boolean | null>(null);
251
+ const [hasCashMode, setHasCashMode] = useState<boolean | null>(null);
252
+ const [schemes, setSchemes] = useState<Scheme[]>([]);
253
+ const [loadingEligibility, setLoadingEligibility] = useState(false);
254
+ const [eligibilityChecked, setEligibilityChecked] = useState(false);
255
+ const [pomsfBalance, setPomsfBalance] = useState<PomsfBalance | null>(null);
256
+ const [insuranceError, setInsuranceError] = useState('');
257
+ // Required fields only flag once the user has actually been in them, so the step
258
+ // doesn't open pre-painted red. Each clears the moment its field has a value.
259
+ const [touched, setTouched] = useState<Record<RequiredField, boolean>>({
260
+ visitType: false,
261
+ room: false,
262
+ insurance: false,
263
+ });
264
+ const markTouched = (field: RequiredField) => () =>
265
+ setTouched((prev) => (prev[field] ? prev : { ...prev, [field]: true }));
266
+
267
+ useEffect(() => {
268
+ if (open) {
269
+ setPhase(isBiometricConfigured() ? 'biometric' : 'biometric-not-setup');
270
+ setPendingEmrAction(null);
271
+ setIsOtpWhitelisted(false);
272
+ setConsent(false);
273
+ setLaunchingBiometric(false);
274
+ setBiometricUrl(null);
275
+ setFailCount(0);
276
+ setReason('');
277
+ setFailedImage(null);
278
+ setReasonError('');
279
+ setImageError('');
280
+ setShowWhitelistForm(false);
281
+ setMethod('insurance');
282
+ setPatientCategory(PATIENT_CATEGORIES[0]);
283
+ setRoom('');
284
+ setInsurance('');
285
+ setVisitType('');
286
+ setInsuranceError('');
287
+ setTriageRooms([]);
288
+ setTriageQueueByRoom({});
289
+ setInsuranceSchemes([]);
290
+ setHasCashPoint(null);
291
+ setHasCashMode(null);
292
+ setEligibilityChecked(false);
293
+ setTouched({ visitType: false, room: false, insurance: false });
294
+ }
295
+ }, [open]);
296
+
297
+ // Load the patient's eligibility schemes up front so the eligible schemes and
298
+ // SHA eligibility can be shown on the consent summary and appended to the SHA
299
+ // payment option.
300
+ useEffect(() => {
301
+ if (!open || !client?.id || !locationUuid) {
302
+ return;
303
+ }
304
+ let active = true;
305
+ setLoadingEligibility(true);
306
+ setSchemes([]);
307
+ setEligibilityChecked(false);
308
+ getClientEligibityStatus({ requestIdNumber: client.id, requestIdType: '3', locationUuid })
309
+ .then((resp) => {
310
+ if (!active) {
311
+ return;
312
+ }
313
+ setSchemes(resp?.schemes ?? []);
314
+ setEligibilityChecked(true);
315
+ })
316
+ .catch(() => {
317
+ if (active) {
318
+ setSchemes([]);
319
+ setEligibilityChecked(false);
320
+ }
321
+ })
322
+ .finally(() => {
323
+ if (active) {
324
+ setLoadingEligibility(false);
325
+ }
326
+ });
327
+ return () => {
328
+ active = false;
329
+ };
330
+ }, [open, client?.id, locationUuid]);
331
+
332
+ // POMSF's balance lives behind a separate HIE endpoint (/pomsf-balance) from
333
+ // the /eligibility call above, so it's fetched independently — gated only on
334
+ // POMSF being Active (regardless of which scheme is selected in the dropdown,
335
+ // since the Eligibility row below lists every active scheme unconditionally),
336
+ // and never on Visit type. That means switching Visit type afterwards just
337
+ // re-picks a benefit line out of the response already in state (see
338
+ // pomsf-balance.util.ts) rather than re-fetching. Uses a plain fetch rather
339
+ // than the usePomsfBalance hook, which pulls in useConfig({ externalModuleName
340
+ // }) and has been observed to throw here.
341
+ const pomsfActive = isPomsfActive(schemes);
342
+ useEffect(() => {
343
+ if (!open || !pomsfActive || !client?.id || !locationUuid) {
344
+ setPomsfBalance(null);
345
+ return;
346
+ }
347
+ let active = true;
348
+ fetchPomsfBalance(client.id, locationUuid)
349
+ .then((balance) => {
350
+ if (active) {
351
+ setPomsfBalance(balance);
352
+ }
353
+ })
354
+ .catch(() => {
355
+ if (active) {
356
+ setPomsfBalance(null);
357
+ }
358
+ });
359
+ return () => {
360
+ active = false;
361
+ };
362
+ }, [open, pomsfActive, client?.id, locationUuid]);
363
+
364
+ // Load triage service queues for the LOGGED-IN location only (queues whose
365
+ // name contains "triage"), so rooms from other locations aren't shown.
366
+ useEffect(() => {
367
+ if (!open || !locationUuid) {
368
+ return;
369
+ }
370
+ let active = true;
371
+ setLoadingRooms(true);
372
+ fetchServiceQueuesByLocationUuid(locationUuid)
373
+ .then((resp) => {
374
+ if (!active) {
375
+ return;
376
+ }
377
+ const triageQueues = (resp?.results ?? [])
378
+ // Strictly this location — never queues from sibling/child locations.
379
+ .filter((q) => q.location?.uuid === locationUuid)
380
+ .filter((q) => /triage/i.test(q.name ?? q.display ?? ''))
381
+ .map((q) => ({ label: decodeHtmlEntities(q.display || q.name), uuid: q.uuid }))
382
+ .filter((q) => q.label && q.uuid);
383
+ const byRoom: Record<string, string> = {};
384
+ for (const q of triageQueues) {
385
+ // First queue wins for a given label (deduped below for the dropdown).
386
+ if (!byRoom[q.label]) {
387
+ byRoom[q.label] = q.uuid;
388
+ }
389
+ }
390
+ setTriageQueueByRoom(byRoom);
391
+ setTriageRooms(Array.from(new Set(triageQueues.map((q) => q.label))));
392
+ })
393
+ .catch((err) => {
394
+ if (active) {
395
+ showSnackbar({
396
+ kind: 'error',
397
+ title: 'Couldn’t load triage rooms',
398
+ subtitle: getReadableErrorMessage(err, 'Please try again.'),
399
+ });
400
+ }
401
+ })
402
+ .finally(() => {
403
+ if (active) {
404
+ setLoadingRooms(false);
405
+ }
406
+ });
407
+ return () => {
408
+ active = false;
409
+ };
410
+ }, [open, locationUuid]);
411
+
412
+ // Payment modes are global; cash points are what's tied to a location. So we
413
+ // (1) check the logged-in location has a cash point (can it collect payment),
414
+ // and (2) load the global insurance schemes for the dropdown.
415
+ useEffect(() => {
416
+ if (!open || !locationUuid) {
417
+ return;
418
+ }
419
+ let active = true;
420
+ setLoadingSchemes(true);
421
+ Promise.all([fetchCashPoints(), fetchPaymentModes()])
422
+ .then(([cashPoints, modes]) => {
423
+ if (!active) {
424
+ return;
425
+ }
426
+ const facilityCashPoints = (cashPoints ?? []).filter((cp) => !cp.retired && cp.location?.uuid === locationUuid);
427
+ setHasCashPoint(facilityCashPoints.length > 0);
428
+
429
+ // Whether a "cash" payment mode is configured on the backend.
430
+ setHasCashMode((modes ?? []).some((m) => !m.retired && /cash/i.test(m.name ?? '')));
431
+
432
+ const schemes = (modes ?? [])
433
+ .filter((m) => !m.retired && m.name && !NON_INSURANCE_PAYMENT_MODES.test(m.name))
434
+ .map((m) => decodeHtmlEntities(m.name));
435
+ setInsuranceSchemes(Array.from(new Set(schemes)));
436
+ })
437
+ .catch((err) => {
438
+ if (active) {
439
+ showSnackbar({
440
+ kind: 'error',
441
+ title: 'Couldn’t load payment options',
442
+ subtitle: getReadableErrorMessage(err, 'Please try again.'),
443
+ });
444
+ }
445
+ })
446
+ .finally(() => {
447
+ if (active) {
448
+ setLoadingSchemes(false);
449
+ }
450
+ });
451
+ return () => {
452
+ active = false;
453
+ };
454
+ }, [open, locationUuid]);
455
+
456
+ // Check upfront whether OTP is already whitelisted for this client, so that
457
+ // when biometrics fail we can go straight to sending the OTP.
458
+ useEffect(() => {
459
+ if (!open || !client) {
460
+ return;
461
+ }
462
+ let active = true;
463
+ getOtpWhitelistStatus(client.id).then((status) => {
464
+ if (active) {
465
+ setIsOtpWhitelisted(status === 'approved');
466
+ }
467
+ });
468
+ return () => {
469
+ active = false;
470
+ };
471
+ // eslint-disable-next-line react-hooks/exhaustive-deps
472
+ }, [open]);
473
+
474
+ // When we reach the OTP gate, resolve the whitelist status and route accordingly.
475
+ useEffect(() => {
476
+ if (phase !== 'otp-gate' || !client) {
477
+ return;
478
+ }
479
+ let active = true;
480
+ setCheckingWhitelist(true);
481
+ getOtpWhitelistStatus(client.id)
482
+ .then((status) => {
483
+ if (!active) return;
484
+ if (status === 'approved') {
485
+ setPhase('otp');
486
+ } else if (status === 'pending') {
487
+ setPhase('whitelist-pending');
488
+ } else {
489
+ setPhase('whitelist-request');
490
+ }
491
+ })
492
+ .finally(() => active && setCheckingWhitelist(false));
493
+ return () => {
494
+ active = false;
495
+ };
496
+ // eslint-disable-next-line react-hooks/exhaustive-deps
497
+ }, [phase]);
498
+
499
+ if (!open || !client) {
500
+ return null;
501
+ }
502
+
503
+ const fullName = `${client.first_name} ${maskExceptFirstAndLast(client.middle_name)} ${maskExceptFirstAndLast(
504
+ client.last_name,
505
+ )}`;
506
+
507
+ // Selected person shown as a patient header: initials avatar (colour-coded by
508
+ // type) + name and type on one line, CR number on a subtle second line.
509
+ const isPrincipal = clientType === 'Principal';
510
+ const initials = `${client.first_name?.[0] ?? ''}${client.last_name?.[0] ?? ''}`.toUpperCase();
511
+ const clientStrip = (
512
+ <div className={styles.patientStrip}>
513
+ <span className={`${styles.patientAvatar} ${isPrincipal ? styles.avatarPrincipal : styles.avatarDependant}`}>
514
+ {initials}
515
+ </span>
516
+ <div className={styles.patientInfo}>
517
+ <div className={styles.patientLine1}>
518
+ <span className={styles.patientName}>{fullName}</span>
519
+ {clientType ? (
520
+ <Tag type={isPrincipal ? 'blue' : 'teal'} size="sm">
521
+ {clientType}
522
+ </Tag>
523
+ ) : null}
524
+ </div>
525
+ <span className={styles.patientCr}>CR · {maskCrNumber(client.id)}</span>
526
+ </div>
527
+ </div>
528
+ );
529
+
530
+ // The single action button on the EMR status card. Clicking it opens a focused
531
+ // confirmation dialog (emrConfirmModal) rather than expanding the card inline.
532
+ const emrActionArea = (kind: 'create' | 'sync') => {
533
+ const handler = kind === 'create' ? onCreatePatient : onSyncPatient;
534
+ if (!handler) {
535
+ return null;
536
+ }
537
+ return kind === 'create' ? (
538
+ <Button kind="primary" size="sm" onClick={() => setPendingEmrAction('create')}>
539
+ Create in EMR
540
+ </Button>
541
+ ) : (
542
+ <Button
543
+ kind="tertiary"
544
+ size="sm"
545
+ renderIcon={Renew}
546
+ disabled={syncingAmrs}
547
+ onClick={() => setPendingEmrAction('sync')}
548
+ >
549
+ {syncingAmrs ? 'Syncing…' : 'Sync'}
550
+ </Button>
551
+ );
552
+ };
553
+
554
+ // Focused confirmation dialog for the create / sync EMR actions.
555
+ const emrConfirmModal = (
556
+ <Modal
557
+ open={pendingEmrAction !== null}
558
+ size="sm"
559
+ modalHeading={pendingEmrAction === 'create' ? 'Create patient in the EMR?' : 'Sync EMR record?'}
560
+ primaryButtonText={pendingEmrAction === 'create' ? 'Yes, create' : 'Yes, sync'}
561
+ secondaryButtonText="Cancel"
562
+ primaryButtonDisabled={syncingAmrs}
563
+ onRequestClose={() => setPendingEmrAction(null)}
564
+ onSecondarySubmit={() => setPendingEmrAction(null)}
565
+ onRequestSubmit={() => {
566
+ const action = pendingEmrAction;
567
+ setPendingEmrAction(null);
568
+ if (action === 'create') {
569
+ onCreatePatient?.();
570
+ } else if (action === 'sync') {
571
+ onSyncPatient?.();
572
+ }
573
+ }}
574
+ >
575
+ <p className={styles.emrConfirmText}>
576
+ {pendingEmrAction === 'create'
577
+ ? `This patient does not yet exist in our records. A new EMR record will be created for CR ${maskCrNumber(
578
+ client.id,
579
+ )} so they can be registered and attended to.`
580
+ : `This patient already exists in our records. Their EMR record for CR ${maskCrNumber(
581
+ client.id,
582
+ )} will be updated with the latest registry details so their information is current before they are attended to.`}
583
+ </p>
584
+ </Modal>
585
+ );
586
+
587
+ // Shows the EMR lookup result for the client and lets the user act on it:
588
+ // create the patient in the EMR (not found) or sync an existing record (found).
589
+ const emrStatusCard = !amrsChecked ? null : amrsPatient ? (
590
+ <div>
591
+ {/* <div className={`${styles.emrStatus} ${styles.emrStatusFound}`}> */}
592
+ {/* <span className={styles.emrStatusIcon}>
593
+ <CheckmarkOutline size={20} />
594
+ </span>
595
+ <div className={styles.emrStatusBody}>
596
+ <span className={styles.emrStatusTitle}>Patient found in the EMR</span>
597
+ <span className={styles.emrStatusText}>
598
+ CR {maskCrNumber(client.id)} already has a record. Review the differences below and update the EMR with the
599
+ details you choose.
600
+ </span>
601
+ {amrsPatient.uuid ? (
602
+ <EmrCompare client={client} patientUuid={amrsPatient.uuid} onUpdated={onSyncPatient} />
603
+ ) : null}
604
+ </div> */}
605
+ </div>
606
+ ) : (
607
+ <div className={`${styles.emrStatus} ${styles.emrStatusMissing}`}>
608
+ <span className={styles.emrStatusIcon}>
609
+ <WarningAltFilled size={20} />
610
+ </span>
611
+ <div className={styles.emrStatusBody}>
612
+ <span className={styles.emrStatusTitle}>Patient not found in the system</span>
613
+ <span className={styles.emrStatusText}>
614
+ No EMR record matches CR {maskCrNumber(client.id)}. Review the details below and create the record to
615
+ continue.
616
+ </span>
617
+ <EmrCreatePreview client={client} onCreate={() => onCreatePatient?.()} />
618
+ </div>
619
+ </div>
620
+ );
621
+
622
+ const launchBiometric = async () => {
623
+ setLaunchingBiometric(true);
624
+ try {
625
+ const url = await getBiometricCaptureUrl(client.id);
626
+ if (url) {
627
+ setBiometricUrl(url);
628
+ } else {
629
+ showSnackbar({ kind: 'error', title: 'Could not start biometric capture', subtitle: 'Please try again.' });
630
+ }
631
+ } finally {
632
+ setLaunchingBiometric(false);
633
+ }
634
+ };
635
+
636
+ const handleBiometricFailed = () => {
637
+ const attempts = failCount + 1;
638
+ setFailCount(attempts);
639
+ setBiometricUrl(null);
640
+ // Messaging is shown in-page (fail count on the scanner, fallback note on the
641
+ // OTP screen) rather than as toasts.
642
+ if (attempts >= BIOMETRIC_MAX_ATTEMPTS) {
643
+ // If OTP is already whitelisted, go straight to sending it (with the
644
+ // override option); otherwise route through the whitelist gate.
645
+ setPhase(isOtpWhitelisted ? 'otp' : 'otp-gate');
646
+ }
647
+ };
648
+
649
+ // `stay` keeps the current screen (both buttons) instead of moving to the
650
+ // pending screen when the status is not yet approved.
651
+ const checkWhitelistStatus = async (stay = false) => {
652
+ setCheckingWhitelist(true);
653
+ try {
654
+ const status = await getOtpWhitelistStatus(client.id);
655
+ if (status === 'approved') {
656
+ setIsOtpWhitelisted(true);
657
+ showSnackbar({ kind: 'success', title: 'Whitelisted', subtitle: 'You can now use OTP verification.' });
658
+ setPhase('otp');
659
+ } else {
660
+ showSnackbar({ kind: 'info', title: 'Awaiting approval', subtitle: 'The SHA team has not approved this yet.' });
661
+ if (!stay) {
662
+ setPhase('whitelist-pending');
663
+ }
664
+ }
665
+ } finally {
666
+ setCheckingWhitelist(false);
667
+ }
668
+ };
669
+
670
+ const submitWhitelistRequest = async () => {
671
+ // Inline validation
672
+ let valid = true;
673
+ if (!reason.trim()) {
674
+ setReasonError('Select a reason for OTP');
675
+ valid = false;
676
+ } else {
677
+ setReasonError('');
678
+ }
679
+ if (!failedImage) {
680
+ setImageError('Attach an image of the failed biometric');
681
+ valid = false;
682
+ } else {
683
+ setImageError('');
684
+ }
685
+ if (!valid) {
686
+ return;
687
+ }
688
+ setSubmittingWhitelist(true);
689
+ try {
690
+ await requestOtpWhitelist({
691
+ crId: client.id,
692
+ reason,
693
+ failureCount: failCount,
694
+ failedBiometricImage: failedImage,
695
+ });
696
+ showSnackbar({ kind: 'success', title: 'Request submitted', subtitle: 'Awaiting approval from the SHA team.' });
697
+ setPhase('whitelist-pending');
698
+ } finally {
699
+ setSubmittingWhitelist(false);
700
+ }
701
+ };
702
+
703
+ const handleStartVisit = () => {
704
+ const usingInsurance = method === 'insurance';
705
+
706
+ // CCC patients do not require a payment method selection.
707
+ if (!room || !visitType || (!isCccPatient && usingInsurance && !insurance)) {
708
+ return;
709
+ }
710
+
711
+ onStartVisit({
712
+ patientCategory,
713
+ room,
714
+ roomUuid: triageQueueByRoom[room] ?? '',
715
+ visitType,
716
+ ...(isCccPatient ? {} : { method, insurance: usingInsurance ? insurance : undefined }),
717
+ });
718
+ };
719
+
720
+ // Required-field validation. A field flags only once the user has been in it and
721
+ // left it empty, so the step doesn't open pre-painted red; each message then clears
722
+ // reactively the moment its field is filled.
723
+ const roomInvalidText =
724
+ touched.room && !room ? `Select a ${patientCategory === 'Walk-in' ? 'walk-in' : 'triage'} room` : '';
725
+ const visitTypeInvalidText = touched.visitType && !visitType ? 'Select a visit type' : '';
726
+ // The SHA-ineligibility message (set on selecting an ineligible scheme) takes
727
+ // precedence over the "select a scheme" prompt, and is shown regardless of touch
728
+ // state because it's a response to something the user just did.
729
+ const isCccPatient = patientCategory === 'CCC';
730
+
731
+ const insuranceInvalidText =
732
+ insuranceError ||
733
+ (!isCccPatient && method === 'insurance' && touched.insurance && !insurance ? 'Select an insurance scheme' : '');
734
+
735
+ // A scheme is active/eligible when its coverage status is '1'.
736
+ const isActiveScheme = (s: Scheme) => s.coverage?.status === '1';
737
+
738
+ // Balance for the benefit line matching the current Visit type, picked from
739
+ // the POMSF balance response fetched above — see pomsf-balance.util.ts for the
740
+ // PMF-07/PMF-12 mapping and the rest of the gating rules.
741
+ const pomsfDisplayBalance = getPomsfDisplayBalance(schemes, visitType, pomsfBalance);
742
+ // The full breakdown (every benefit line, not just the one for the current
743
+ // Visit type) — shown underneath so staff can see all of a patient's POMSF
744
+ // benefits at a glance, not just the auto-picked one.
745
+ const pomsfAllBenefits = pomsfActive ? getAllPomsfBenefitBalances(pomsfBalance) : [];
746
+
747
+ // Every eligible scheme the registry returns for the patient (all active
748
+ // schemes) — shown in full on the consent summary.
749
+ const eligibleSchemes = schemes.filter(isActiveScheme);
750
+
751
+ // SHA eligibility indicator, shown on the consent summary and beside the SHA
752
+ // payment option. Derived from the eligible schemes: eligible when the patient
753
+ // has at least one active scheme.
754
+ const shaActive = eligibleSchemes.length > 0;
755
+
756
+ // Insurance dropdown items. SHA carries its eligibility in the name and is not
757
+ // selectable unless the patient is eligible (has an active eligible scheme).
758
+ const insuranceItems = insuranceSchemes.map((name) => {
759
+ const isSha = /sha|shif/i.test(name);
760
+ if (!isSha) {
761
+ return { id: name, label: name, isSha: false, eligible: true, disabled: false };
762
+ }
763
+ const suffix = loadingEligibility
764
+ ? ' · checking eligibility…'
765
+ : shaActive
766
+ ? ' · eligible'
767
+ : eligibilityChecked
768
+ ? ' · not eligible'
769
+ : ' · eligibility unknown';
770
+ return { id: name, label: `${name}${suffix}`, isSha: true, eligible: shaActive, disabled: !shaActive };
771
+ });
772
+
773
+ const shaEligibilityTag = loadingEligibility ? (
774
+ <InlineLoading className={styles.eligibilityLoading} description="Checking SHA eligibility…" />
775
+ ) : (
776
+ <Tag size="sm" type={shaActive ? 'green' : 'red'}>
777
+ {shaActive ? 'SHA · Eligible' : eligibilityChecked ? 'SHA · Not eligible' : 'SHA · Unknown'}
778
+ </Tag>
779
+ );
780
+
781
+ // The full list of the patient's eligible schemes — shared by the consent
782
+ // summary and the insurance payment section so both show the same detail.
783
+ const eligibleSchemesList =
784
+ eligibleSchemes.length > 0 ? (
785
+ <div className={styles.schemes}>
786
+ <div className={styles.schemesHead}>Eligible scheme{eligibleSchemes.length === 1 ? '' : 's'}</div>
787
+ <ul className={styles.schemeList}>
788
+ {eligibleSchemes.map((s, i) => (
789
+ <li key={`${s.schemeName}-${i}`} className={styles.schemeItem}>
790
+ <div className={styles.schemeTop}>
791
+ <span className={styles.schemeName}>{s.schemeName}</span>
792
+ <Tag size="sm" type="green">
793
+ Active
794
+ </Tag>
795
+ </div>
796
+ <div className={styles.schemeMeta}>
797
+ {s.memberType ? (
798
+ <span>{s.memberType.charAt(0).toUpperCase() + s.memberType.slice(1).toLowerCase()}</span>
799
+ ) : null}
800
+ {s.coverage?.endDate ? <span>Valid to {String(s.coverage.endDate).slice(0, 10)}</span> : null}
801
+ </div>
802
+ </li>
803
+ ))}
804
+ </ul>
805
+ </div>
806
+ ) : null;
807
+
808
+ return (
809
+ <>
810
+ {/* Overlay does NOT close on click — the user must use Close or Cancel */}
811
+ <div className={styles.overlay} />
812
+ <aside className={styles.drawer} role="dialog" aria-label="Registration workflow">
813
+ <header className={styles.header}>
814
+ <h4 className={styles.title}>Patient registration</h4>
815
+ <Button kind="ghost" size="sm" hasIconOnly iconDescription="Close" renderIcon={Close} onClick={onClose} />
816
+ </header>
817
+
818
+ <div className={styles.body}>
819
+ {/* The stepper scrolls with the content */}
820
+ <div className={styles.stepper}>
821
+ <div className={styles.stepperCard}>
822
+ <ProgressIndicator currentIndex={phaseToIndex[phase]} spaceEqually>
823
+ {STEPS.map((label) => (
824
+ <ProgressStep key={label} label={label} />
825
+ ))}
826
+ </ProgressIndicator>
827
+ <p className={styles.stepCaption}>
828
+ Step {phaseToIndex[phase] + 1} of {STEPS.length}: <strong>{STEPS[phaseToIndex[phase]]}</strong>
829
+ </p>
830
+ </div>
831
+ </div>
832
+
833
+ <div className={styles.bodyInner}>
834
+ {/* ---- Step 1: Verify — biometric ---- */}
835
+ {phase === 'biometric' ? (
836
+ <div className={styles.verifyContent}>
837
+ {!biometricUrl && clientStrip}
838
+ {!biometricUrl ? (
839
+ <>
840
+ {/* The scanner card — the primary action */}
841
+ <div className={styles.biometricArea}>
842
+ <button
843
+ type="button"
844
+ className={styles.biometricLaunch}
845
+ onClick={launchBiometric}
846
+ disabled={launchingBiometric}
847
+ >
848
+ <span className={styles.biometricIcon}>
849
+ <FingerprintRecognition size={48} />
850
+ </span>
851
+ <span className={styles.biometricLaunchText}>
852
+ {launchingBiometric ? 'Starting scanner…' : 'Tap to scan fingerprint'}
853
+ </span>
854
+ <span className={styles.biometricLaunchHint}>Confirm the patient&apos;s identity</span>
855
+ </button>
856
+ {failCount > 0 ? (
857
+ <p className={styles.failNote}>
858
+ Attempt {failCount} of {BIOMETRIC_MAX_ATTEMPTS} failed. Please try again.
859
+ </p>
860
+ ) : (
861
+ <></>
862
+ )}
863
+ </div>
864
+ {/* The step-by-step guide, below the scanner */}
865
+ <div className={styles.guidePanel}>
866
+ <div className={styles.guideHead}>
867
+ <Information size={18} className={styles.guideHeadIcon} />
868
+ How verification works
869
+ </div>
870
+ <ol className={styles.guideSteps}>
871
+ <li>Scan the patient&apos;s fingerprint to confirm their identity.</li>
872
+ <li>If the fingerprint fails {BIOMETRIC_MAX_ATTEMPTS} times, switch to an OTP code.</li>
873
+ <li>If OTP isn&apos;t allowed for this patient yet, request OTP whitelisting.</li>
874
+ <li>Once approved (or if already allowed), verify with the OTP sent to their phone.</li>
875
+ </ol>
876
+ </div>
877
+ </>
878
+ ) : (
879
+ <div className={styles.biometricFrameWrap}>
880
+ <iframe title="Fingerprint capture" src={biometricUrl} className={styles.biometricFrame} />
881
+ <div className={styles.capturePrompt}>
882
+ <span className={styles.capturePromptText}>Did the fingerprint match the patient?</span>
883
+ <span className={styles.capturePromptHint}>
884
+ {failCount > 0
885
+ ? `Attempt ${failCount + 1} of ${BIOMETRIC_MAX_ATTEMPTS}. After ${BIOMETRIC_MAX_ATTEMPTS} tries you'll switch to OTP.`
886
+ : `You have ${BIOMETRIC_MAX_ATTEMPTS} tries before switching to OTP.`}
887
+ </span>
888
+ <div className={styles.captureActions}>
889
+ <Button kind="secondary" size="sm" renderIcon={Renew} onClick={handleBiometricFailed}>
890
+ No, try again
891
+ </Button>
892
+ <Button
893
+ kind="primary"
894
+ size="sm"
895
+ renderIcon={CheckmarkOutline}
896
+ onClick={() => {
897
+ setConsent(true);
898
+ setPhase('consent');
899
+ }}
900
+ >
901
+ Yes, identified
902
+ </Button>
903
+ </div>
904
+ </div>
905
+ </div>
906
+ )}
907
+ </div>
908
+ ) : (
909
+ <></>
910
+ )}
911
+
912
+ {/* ---- Step 1: Verify — biometric not configured ---- */}
913
+ {phase === 'biometric-not-setup' ? (
914
+ <div className={styles.verifyContent}>
915
+ {clientStrip}
916
+ <div className={`${styles.statusCard} ${styles.statusCardDanger}`}>
917
+ <span className={`${styles.statusBadge} ${styles.statusBadgeDanger}`}>
918
+ <ScanDisabled size={20} />
919
+ </span>
920
+ <h5 className={styles.statusTitle}>Biometric not detected</h5>
921
+ <p className={styles.statusText}>
922
+ We couldn&apos;t detect a fingerprint scanner on this workstation. You can proceed by verifying the
923
+ patient with a one-time PIN (OTP) sent to their phone.
924
+ </p>
925
+ <Button
926
+ kind="primary"
927
+ size="sm"
928
+ renderIcon={ArrowRight}
929
+ onClick={() => setPhase(isOtpWhitelisted ? 'otp' : 'otp-gate')}
930
+ >
931
+ Use OTP instead
932
+ </Button>
933
+ </div>
934
+ </div>
935
+ ) : (
936
+ <></>
937
+ )}
938
+
939
+ {/* ---- Step 1: Verify — checking whitelist ---- */}
940
+ {phase === 'otp-gate' ? (
941
+ <div className={styles.verifyContent}>
942
+ <div className={styles.loadingCard}>
943
+ <InlineLoading description="Checking OTP whitelist status…" />
944
+ </div>
945
+ </div>
946
+ ) : (
947
+ <></>
948
+ )}
949
+
950
+ {/* ---- Step 1: Verify — whitelist request ---- */}
951
+ {phase === 'whitelist-request' ? (
952
+ <div className={styles.verifyContent}>
953
+ {!showWhitelistForm ? (
954
+ <div className={styles.statusCard}>
955
+ <span className={styles.statusBadge}>
956
+ <WarningAltFilled size={24} />
957
+ </span>
958
+ <h5 className={styles.statusTitle}>Not whitelisted for OTP</h5>
959
+ <p className={styles.statusText}>
960
+ This patient isn&apos;t whitelisted to receive a One-Time Password. Request whitelisting from the
961
+ SHA team to continue verifying by OTP.
962
+ </p>
963
+ <div className={styles.statusActions}>
964
+ <Button
965
+ kind="tertiary"
966
+ size="sm"
967
+ disabled={checkingWhitelist}
968
+ onClick={() => checkWhitelistStatus(true)}
969
+ >
970
+ {checkingWhitelist ? 'Checking…' : 'Check whitelist status'}
971
+ </Button>
972
+ <Button
973
+ kind="primary"
974
+ size="sm"
975
+ renderIcon={ArrowRight}
976
+ onClick={() => setShowWhitelistForm(true)}
977
+ >
978
+ Request whitelisting
979
+ </Button>
980
+ </div>
981
+ </div>
982
+ ) : (
983
+ <div className={styles.panel}>
984
+ <div className={styles.panelHead}>Request OTP whitelisting</div>
985
+ <div className={styles.panelBody}>
986
+ <div className={styles.infoNote}>
987
+ <Information size={20} className={styles.infoNoteIcon} />
988
+ <p className={styles.infoNoteText}>
989
+ OTP is not yet approved for this patient. Submit the details below to request whitelisting
990
+ from the SHA team.
991
+ </p>
992
+ </div>
993
+ <div className={styles.readonlyField}>
994
+ <span className={styles.readonlyLabel}>Biometric attempts failed</span>
995
+ <span className={styles.readonlyValue}>
996
+ {failCount} of {BIOMETRIC_MAX_ATTEMPTS}
997
+ </span>
998
+ </div>
999
+ <Dropdown
1000
+ id="whitelist-reason"
1001
+ titleText={
1002
+ <span>
1003
+ Reason for OTP <span className={styles.required}>*</span>
1004
+ </span>
1005
+ }
1006
+ label="Select a reason"
1007
+ items={WHITELIST_REASONS}
1008
+ selectedItem={reason || null}
1009
+ invalid={!!reasonError}
1010
+ invalidText={reasonError}
1011
+ onChange={({ selectedItem }) => {
1012
+ setReason((selectedItem as string) ?? '');
1013
+ setReasonError('');
1014
+ }}
1015
+ />
1016
+ <div className={styles.uploadField}>
1017
+ <FormLabel>
1018
+ Image of failed biometric <span className={styles.required}>*</span>
1019
+ </FormLabel>
1020
+ <p className={styles.uploadHint}>
1021
+ Screenshot or photo of the failed attempt · PNG or JPG · one file
1022
+ </p>
1023
+ <div
1024
+ className={`${styles.dropZone} ${dragOver ? styles.dropZoneActive : ''} ${
1025
+ imageError ? styles.dropZoneInvalid : ''
1026
+ }`}
1027
+ role="button"
1028
+ tabIndex={0}
1029
+ onClick={() => fileInputRef.current?.click()}
1030
+ onKeyDown={(e) => {
1031
+ if (e.key === 'Enter' || e.key === ' ') {
1032
+ e.preventDefault();
1033
+ fileInputRef.current?.click();
1034
+ }
1035
+ }}
1036
+ onDragOver={(e) => {
1037
+ e.preventDefault();
1038
+ setDragOver(true);
1039
+ }}
1040
+ onDragLeave={() => setDragOver(false)}
1041
+ onDrop={(e) => {
1042
+ e.preventDefault();
1043
+ setDragOver(false);
1044
+ const file = e.dataTransfer.files?.[0];
1045
+ if (file) {
1046
+ setFailedImage(file);
1047
+ setImageError('');
1048
+ }
1049
+ }}
1050
+ >
1051
+ <span className={styles.dropIcon}>
1052
+ <CloudUpload size={24} />
1053
+ </span>
1054
+ <span className={styles.dropTitle}>Drag and drop an image here</span>
1055
+ <span className={styles.dropSubtitle}>or click to browse</span>
1056
+ <input
1057
+ ref={fileInputRef}
1058
+ type="file"
1059
+ accept=".png,.jpg,.jpeg"
1060
+ className={styles.hiddenInput}
1061
+ onChange={(e) => {
1062
+ const file = e.target.files?.[0] ?? null;
1063
+ setFailedImage(file);
1064
+ if (file) {
1065
+ setImageError('');
1066
+ }
1067
+ }}
1068
+ />
1069
+ </div>
1070
+ {failedImage ? (
1071
+ <FileUploaderItem
1072
+ name={failedImage.name}
1073
+ status="edit"
1074
+ iconDescription="Remove file"
1075
+ onDelete={() => setFailedImage(null)}
1076
+ />
1077
+ ) : null}
1078
+ {imageError ? <p className={styles.fieldError}>{imageError}</p> : null}
1079
+ </div>
1080
+ <Button
1081
+ className={styles.submitBtn}
1082
+ kind="primary"
1083
+ size="sm"
1084
+ disabled={submittingWhitelist || !reason.trim() || !failedImage}
1085
+ onClick={submitWhitelistRequest}
1086
+ >
1087
+ {submittingWhitelist ? 'Submitting…' : 'Submit request'}
1088
+ </Button>
1089
+ </div>
1090
+ </div>
1091
+ )}
1092
+ </div>
1093
+ ) : (
1094
+ <></>
1095
+ )}
1096
+
1097
+ {/* ---- Step 1: Verify — whitelist pending ---- */}
1098
+ {phase === 'whitelist-pending' ? (
1099
+ <div className={styles.verifyContent}>
1100
+ <div className={styles.statusCard}>
1101
+ <span className={styles.statusBadge}>
1102
+ <PendingFilled size={24} />
1103
+ </span>
1104
+ <h5 className={styles.statusTitle}>Awaiting approval</h5>
1105
+ <p className={styles.statusText}>
1106
+ Your OTP whitelisting request is pending approval. Check back to see if it has been approved.
1107
+ </p>
1108
+ <Button kind="primary" size="sm" disabled={checkingWhitelist} onClick={() => checkWhitelistStatus()}>
1109
+ {checkingWhitelist ? 'Checking…' : 'Check whitelist status'}
1110
+ </Button>
1111
+ </div>
1112
+ </div>
1113
+ ) : (
1114
+ <></>
1115
+ )}
1116
+
1117
+ {/* ---- Step 1: Verify — OTP ---- */}
1118
+ {phase === 'otp' && requestCustomOtpDto ? (
1119
+ <div className={styles.verifyContent}>
1120
+ <OtpVerificationStep
1121
+ requestCustomOtpDto={requestCustomOtpDto}
1122
+ phoneNumber={phoneNumber ?? ''}
1123
+ timerSeconds={OTP_EXPIRY_SECONDS}
1124
+ biometricFailedCount={failCount}
1125
+ onVerified={() => {
1126
+ setConsent(true);
1127
+ setPhase('consent');
1128
+ }}
1129
+ />
1130
+ </div>
1131
+ ) : (
1132
+ <></>
1133
+ )}
1134
+
1135
+ {/* ---- Step 2: Consent ---- */}
1136
+ {phase === 'consent' ? (
1137
+ <div className={styles.verifyContent}>
1138
+ <div className={styles.consentConfirmed}>
1139
+ <CheckboxCheckedFilled size={20} className={styles.consentConfirmedIcon} />
1140
+ <span className={styles.consentConfirmedText}>
1141
+ The patient has consented to you accessing their details. You can now proceed.
1142
+ </span>
1143
+ </div>
1144
+
1145
+ {consent ? (
1146
+ <>
1147
+ <div className={styles.panel}>
1148
+ <div className={styles.panelHead}>Patient details</div>
1149
+ <div className={styles.panelBody}>
1150
+ <dl className={styles.detailGrid}>
1151
+ <div className={`${styles.detailRow} ${styles.detailFull}`}>
1152
+ <dt>Full name</dt>
1153
+ <dd>
1154
+ {[client.first_name, client.middle_name, client.last_name].filter(Boolean).join(' ')}
1155
+ </dd>
1156
+ </div>
1157
+ <div className={styles.detailRow}>
1158
+ <dt>CR number</dt>
1159
+ <dd>{client.id}</dd>
1160
+ </div>
1161
+ <div className={styles.detailRow}>
1162
+ <dt>Phone number</dt>
1163
+ <dd>{client.phone || '—'}</dd>
1164
+ </div>
1165
+ <div className={styles.detailRow}>
1166
+ <dt>ID number</dt>
1167
+ <dd>{client.identification_number || '—'}</dd>
1168
+ </div>
1169
+ <div className={styles.detailRow}>
1170
+ <dt>SHA eligibility</dt>
1171
+ <dd>{shaEligibilityTag}</dd>
1172
+ </div>
1173
+ </dl>
1174
+
1175
+ {eligibleSchemesList}
1176
+ </div>
1177
+ </div>
1178
+ {emrStatusCard}
1179
+ {emrConfirmModal}
1180
+ </>
1181
+ ) : (
1182
+ <></>
1183
+ )}
1184
+ </div>
1185
+ ) : (
1186
+ <></>
1187
+ )}
1188
+
1189
+ {/* ---- Step 3: Start visit ---- */}
1190
+ {phase === 'visit' ? (
1191
+ <div className={styles.verifyContent}>
1192
+ <div className={`${styles.panelBody} ${styles.scrollBody}`}>
1193
+ <div {...lockSelection(!!visitType)} onBlurCapture={markTouched('visitType')}>
1194
+ <ComboBox
1195
+ id="visit-type"
1196
+ titleText={
1197
+ <span>
1198
+ Visit type<span className={styles.required}>*</span>
1199
+ </span>
1200
+ }
1201
+ placeholder="Search or select a visit type"
1202
+ items={VISIT_TYPE_OPTIONS}
1203
+ itemToString={(item) => item ?? ''}
1204
+ shouldFilterItem={filterByLabel<string>((item) => item ?? '', visitType)}
1205
+ selectedItem={visitType || null}
1206
+ invalid={!!visitTypeInvalidText}
1207
+ invalidText={visitTypeInvalidText}
1208
+ onChange={({ selectedItem }) => {
1209
+ setVisitType((selectedItem as string) ?? '');
1210
+ }}
1211
+ />
1212
+ </div>
1213
+ <div className={styles.formSection}>
1214
+ <h6 className={styles.sectionLabel}>Patient category</h6>
1215
+ <RadioButtonGroup
1216
+ legendText="Patient destination"
1217
+ name="patient-category-group"
1218
+ orientation="horizontal"
1219
+ valueSelected={patientCategory}
1220
+ onChange={(v) => {
1221
+ setPatientCategory(v as string);
1222
+ setRoom('');
1223
+ }}
1224
+ >
1225
+ {PATIENT_CATEGORIES.map((cat) => (
1226
+ <RadioButton key={cat} id={`cat-${cat.toLowerCase()}`} labelText={cat} value={cat} />
1227
+ ))}
1228
+ </RadioButtonGroup>
1229
+
1230
+ <div {...lockSelection(!!room)} onBlurCapture={markTouched('room')}>
1231
+ <ComboBox
1232
+ id="visit-room"
1233
+ titleText={
1234
+ <span>
1235
+ {patientCategory === 'Walk-in' ? 'Walk-in room' : 'Triage room'}
1236
+ <span className={styles.required}>*</span>
1237
+ </span>
1238
+ }
1239
+ placeholder={
1240
+ patientCategory === 'Walk-in'
1241
+ ? 'Search or select a walk-in room'
1242
+ : loadingRooms
1243
+ ? 'Loading triage rooms…'
1244
+ : triageRooms.length === 0
1245
+ ? 'No triage rooms for this location'
1246
+ : 'Search or select a triage room'
1247
+ }
1248
+ items={patientCategory === 'Walk-in' ? WALK_IN_ROOMS : triageRooms}
1249
+ itemToString={(item) => item ?? ''}
1250
+ shouldFilterItem={filterByLabel<string>((item) => item ?? '', room)}
1251
+ disabled={patientCategory === 'Triage' && (loadingRooms || triageRooms.length === 0)}
1252
+ selectedItem={room || null}
1253
+ invalid={!!roomInvalidText}
1254
+ invalidText={roomInvalidText}
1255
+ onChange={({ selectedItem }) => {
1256
+ setRoom((selectedItem as string) ?? '');
1257
+ }}
1258
+ />
1259
+ </div>
1260
+ </div>
1261
+
1262
+ <div className={styles.formSection}>
1263
+ {!isCccPatient ? <h6 className={styles.sectionLabel}>Payment</h6> : <></>}
1264
+ {hasCashPoint === false ? (
1265
+ <div className={styles.errorNote}>
1266
+ <WarningAltFilled size={20} className={styles.errorNoteIcon} />
1267
+ <p className={styles.errorNoteText}>
1268
+ Payment modes have not been configured. Contact your system administrator.
1269
+ </p>
1270
+ </div>
1271
+ ) : null}
1272
+
1273
+ <RadioButtonGroup
1274
+ legendText="Payment method"
1275
+ name="method-group"
1276
+ orientation="horizontal"
1277
+ valueSelected={method}
1278
+ disabled={isCccPatient || hasCashPoint === false}
1279
+ onChange={(v) => {
1280
+ // Switching payment method clears any preselected
1281
+ // insurance so it can't carry into the payer mapping —
1282
+ // insurance→cash and cash→insurance both start fresh.
1283
+ setMethod(v as Method);
1284
+ setInsurance('');
1285
+ setInsuranceError('');
1286
+ }}
1287
+ >
1288
+ <RadioButton id="method-insurance" labelText="Insurance" value="insurance" />
1289
+ <RadioButton id="method-cash" labelText="Cash" value="cash" />
1290
+ </RadioButtonGroup>
1291
+
1292
+ {method === 'cash' && hasCashMode === false ? (
1293
+ <div className={styles.errorNote}>
1294
+ <WarningAltFilled size={20} className={styles.errorNoteIcon} />
1295
+ <p className={styles.errorNoteText}>
1296
+ Cash payment mode is not set. Contact your system administrator.
1297
+ </p>
1298
+ </div>
1299
+ ) : null}
1300
+
1301
+ {method === 'insurance' && !isCccPatient ? (
1302
+ <div {...lockSelection(!!insurance)} onBlurCapture={markTouched('insurance')}>
1303
+ <ComboBox
1304
+ id="insurance-scheme"
1305
+ titleText={
1306
+ <span>
1307
+ Insurance scheme<span className={styles.required}>*</span>
1308
+ </span>
1309
+ }
1310
+ placeholder={
1311
+ loadingSchemes
1312
+ ? 'Loading insurance schemes…'
1313
+ : insuranceSchemes.length === 0
1314
+ ? 'No insurance schemes available'
1315
+ : 'Search or select insurance scheme'
1316
+ }
1317
+ items={insuranceItems}
1318
+ itemToString={(item) => (item ? item.label : '')}
1319
+ shouldFilterItem={filterByLabel(
1320
+ (item: (typeof insuranceItems)[number]) => item?.label ?? '',
1321
+ insuranceItems.find((i) => i.id === insurance)?.label ?? '',
1322
+ )}
1323
+ itemToElement={(item) =>
1324
+ item ? (
1325
+ item.isSha ? (
1326
+ <span
1327
+ className={`${styles.schemePill} ${
1328
+ item.eligible ? styles.schemePillEligible : styles.schemePillIneligible
1329
+ }`}
1330
+ >
1331
+ {item.label}
1332
+ </span>
1333
+ ) : (
1334
+ <span>{item.label}</span>
1335
+ )
1336
+ ) : null
1337
+ }
1338
+ disabled={loadingSchemes || insuranceSchemes.length === 0}
1339
+ selectedItem={insuranceItems.find((i) => i.id === insurance) ?? null}
1340
+ invalid={!!insuranceInvalidText}
1341
+ invalidText={insuranceInvalidText}
1342
+ onChange={({ selectedItem }) => {
1343
+ if (!selectedItem) {
1344
+ // The combo box's clear button hands back null — drop the selection.
1345
+ setInsurance('');
1346
+ setInsuranceError('');
1347
+ return;
1348
+ }
1349
+ if (selectedItem.disabled) {
1350
+ // Patient isn't SHA-eligible — block the selection.
1351
+ setInsurance('');
1352
+ setInsuranceError('Patient is not eligible for SHA. Choose another scheme.');
1353
+ return;
1354
+ }
1355
+ setInsurance(selectedItem.id);
1356
+ setInsuranceError('');
1357
+ }}
1358
+ />
1359
+ </div>
1360
+ ) : (
1361
+ <></>
1362
+ )}
1363
+
1364
+ {method === 'insurance' &&
1365
+ !isCccPatient &&
1366
+ /pomsf/i.test(insurance) &&
1367
+ pomsfDisplayBalance !== null ? (
1368
+ <div className={styles.eligibilityRow}>
1369
+ <span className={styles.eligibilityRowLabel}>Eligibility</span>
1370
+ <Tag size="sm" type="green">
1371
+ {`POMSF · Active · ${formatKes(pomsfDisplayBalance)}`}
1372
+ </Tag>
1373
+ </div>
1374
+ ) : null}
1375
+
1376
+ {method === 'insurance' && !isCccPatient && /sha|shif/i.test(insurance) ? (
1377
+ <div className={styles.eligibilityRow}>
1378
+ <span className={styles.eligibilityRowLabel}>Eligibility</span>
1379
+ {shaEligibilityTag}
1380
+ {eligibleSchemes.map((s, i) => (
1381
+ <Tag key={`${s.schemeName}-${i}`} size="sm" type="green">
1382
+ {/* POMSF's tag additionally carries its balance for the current Visit
1383
+ type (see pomsf-balance.util.ts), once one is picked — this row
1384
+ lists every active scheme regardless of which one is selected above. */}
1385
+ {/pomsf/i.test(s.schemeName) && pomsfDisplayBalance !== null
1386
+ ? `${s.schemeName} · Active · ${formatKes(pomsfDisplayBalance)}`
1387
+ : `${s.schemeName} · Active`}
1388
+ </Tag>
1389
+ ))}
1390
+ </div>
1391
+ ) : null}
1392
+
1393
+ {method === 'insurance' && !isCccPatient && pomsfAllBenefits.length > 0 ? (
1394
+ <div className={styles.pomsfBenefitsSection}>
1395
+ <span className={styles.eligibilityRowLabel}>POMSF benefits</span>
1396
+ <div className={styles.tableWrapper}>
1397
+ <Table size="sm" aria-label="POMSF benefits">
1398
+ <TableHead>
1399
+ <TableRow>
1400
+ <TableHeader>Benefit</TableHeader>
1401
+ <TableHeader>Balance</TableHeader>
1402
+ </TableRow>
1403
+ </TableHead>
1404
+ <TableBody>
1405
+ {pomsfAllBenefits.map((benefit) => (
1406
+ <TableRow key={benefit.code}>
1407
+ <TableCell>{benefit.name}</TableCell>
1408
+ <TableCell>{benefit.balance !== null ? formatKes(benefit.balance) : '—'}</TableCell>
1409
+ </TableRow>
1410
+ ))}
1411
+ </TableBody>
1412
+ </Table>
1413
+ </div>
1414
+ </div>
1415
+ ) : null}
1416
+ </div>
1417
+ </div>
1418
+ </div>
1419
+ ) : (
1420
+ <></>
1421
+ )}
1422
+ </div>
1423
+ </div>
1424
+
1425
+ <footer className={styles.footer}>
1426
+ {phase === 'consent' && amrsChecked && !amrsPatient ? (
1427
+ <span className={styles.footerHint}>
1428
+ <WarningAltFilled size={16} className={styles.footerHintIcon} />
1429
+ Create the patient in the EMR to continue.
1430
+ </span>
1431
+ ) : (
1432
+ <div />
1433
+ )}
1434
+ <div className={styles.footerRight}>
1435
+ <Button kind="secondary" size="sm" onClick={onClose}>
1436
+ Cancel
1437
+ </Button>
1438
+ {phase === 'consent' ? (
1439
+ <Button
1440
+ kind="primary"
1441
+ size="sm"
1442
+ renderIcon={ArrowRight}
1443
+ // Block continuing until the patient exists in the EMR (found or created).
1444
+ disabled={!consent || !amrsPatient}
1445
+ onClick={() => setPhase('visit')}
1446
+ >
1447
+ Continue
1448
+ </Button>
1449
+ ) : (
1450
+ <></>
1451
+ )}
1452
+ {phase === 'visit' ? (
1453
+ <Button
1454
+ kind="primary"
1455
+ size="sm"
1456
+ renderIcon={ArrowRight}
1457
+ disabled={
1458
+ !room ||
1459
+ !visitType ||
1460
+ (!isCccPatient && hasCashPoint === false) ||
1461
+ (!isCccPatient && method === 'cash' && hasCashMode === false) ||
1462
+ (!isCccPatient && method === 'insurance' && !insurance)
1463
+ }
1464
+ onClick={handleStartVisit}
1465
+ >
1466
+ Start visit &amp; send to {patientCategory === 'Walk-in' ? 'walk-in' : 'triage'}
1467
+ </Button>
1468
+ ) : (
1469
+ <></>
1470
+ )}
1471
+ </div>
1472
+ </footer>
1473
+ </aside>
1474
+ </>
1475
+ );
1476
+ };
1477
+
1478
+ export default WorkflowDrawer;