@ampath/esm-dha-workflow-app 4.0.0-next.43 → 4.0.0-next.445

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 (937) hide show
  1. package/README.md +47 -0
  2. package/dist/1100.js +1 -0
  3. package/dist/1100.js.map +1 -0
  4. package/dist/{197.js → 1197.js} +1 -1
  5. package/dist/1371.js +2 -0
  6. package/dist/1371.js.LICENSE.txt +282 -0
  7. package/dist/1371.js.map +1 -0
  8. package/dist/1435.js +1 -0
  9. package/dist/1435.js.map +1 -0
  10. package/dist/1673.js +1 -0
  11. package/dist/1673.js.map +1 -0
  12. package/dist/1843.js +1 -0
  13. package/dist/1843.js.map +1 -0
  14. package/dist/1931.js +1 -0
  15. package/dist/1931.js.map +1 -0
  16. package/dist/2272.js +2 -0
  17. package/dist/2272.js.map +1 -0
  18. package/dist/2383.js +1 -0
  19. package/dist/2383.js.map +1 -0
  20. package/dist/2439.js +1 -0
  21. package/dist/2439.js.map +1 -0
  22. package/dist/2535.js +1 -0
  23. package/dist/2535.js.map +1 -0
  24. package/dist/2592.js +1 -0
  25. package/dist/2592.js.map +1 -0
  26. package/dist/2632.js +1 -0
  27. package/dist/2632.js.map +1 -0
  28. package/dist/2635.js +1 -0
  29. package/dist/2635.js.map +1 -0
  30. package/dist/2663.js +1 -0
  31. package/dist/2663.js.map +1 -0
  32. package/dist/2687.js +1 -0
  33. package/dist/2687.js.map +1 -0
  34. package/dist/2802.js +1 -0
  35. package/dist/2802.js.map +1 -0
  36. package/dist/2808.js +1 -0
  37. package/dist/2808.js.map +1 -0
  38. package/dist/282.js +1 -1
  39. package/dist/282.js.LICENSE.txt +3 -3
  40. package/dist/282.js.map +1 -1
  41. package/dist/2848.js +1 -0
  42. package/dist/2848.js.map +1 -0
  43. package/dist/3.js +1 -0
  44. package/dist/3.js.map +1 -0
  45. package/dist/3016.js +1 -0
  46. package/dist/3016.js.map +1 -0
  47. package/dist/3041.js +1 -0
  48. package/dist/3041.js.map +1 -0
  49. package/dist/3099.js +1 -0
  50. package/dist/3182.js +1 -0
  51. package/dist/3182.js.map +1 -0
  52. package/dist/3184.js +2 -0
  53. package/dist/3184.js.map +1 -0
  54. package/dist/3196.js +1 -0
  55. package/dist/3196.js.map +1 -0
  56. package/dist/3242.js +1 -0
  57. package/dist/3242.js.map +1 -0
  58. package/dist/3270.js +1 -0
  59. package/dist/3270.js.map +1 -0
  60. package/dist/3288.js +1 -0
  61. package/dist/3288.js.map +1 -0
  62. package/dist/3311.js +2 -0
  63. package/dist/3311.js.LICENSE.txt +9 -0
  64. package/dist/3311.js.map +1 -0
  65. package/dist/3558.js +1 -0
  66. package/dist/3558.js.map +1 -0
  67. package/dist/3612.js +1 -0
  68. package/dist/3612.js.map +1 -0
  69. package/dist/3636.js +1 -0
  70. package/dist/3636.js.map +1 -0
  71. package/dist/3654.js +1 -0
  72. package/dist/3654.js.map +1 -0
  73. package/dist/3794.js +1 -0
  74. package/dist/3794.js.map +1 -0
  75. package/dist/3816.js +1 -0
  76. package/dist/3816.js.map +1 -0
  77. package/dist/3897.js +1 -0
  78. package/dist/3897.js.map +1 -0
  79. package/dist/3949.js +1 -0
  80. package/dist/3949.js.map +1 -0
  81. package/dist/4055.js +1 -0
  82. package/dist/408.js +1 -0
  83. package/dist/408.js.map +1 -0
  84. package/dist/409.js +1 -0
  85. package/dist/409.js.map +1 -0
  86. package/dist/411.js +1 -0
  87. package/dist/411.js.map +1 -0
  88. package/dist/4225.js +1 -0
  89. package/dist/4225.js.map +1 -0
  90. package/dist/4300.js +1 -0
  91. package/dist/{335.js → 4335.js} +1 -1
  92. package/dist/4353.js +1 -0
  93. package/dist/4353.js.map +1 -0
  94. package/dist/4399.js +1 -0
  95. package/dist/4399.js.map +1 -0
  96. package/dist/4569.js +1 -0
  97. package/dist/4569.js.map +1 -0
  98. package/dist/{652.js → 4652.js} +1 -1
  99. package/dist/474.js +1 -0
  100. package/dist/474.js.map +1 -0
  101. package/dist/4993.js +1 -0
  102. package/dist/4993.js.map +1 -0
  103. package/dist/5006.js +1 -0
  104. package/dist/5006.js.map +1 -0
  105. package/dist/5119.js +1 -0
  106. package/dist/5119.js.map +1 -0
  107. package/dist/5138.js +1 -0
  108. package/dist/5138.js.map +1 -0
  109. package/dist/5179.js +1 -0
  110. package/dist/5179.js.map +1 -0
  111. package/dist/5244.js +1 -0
  112. package/dist/5244.js.map +1 -0
  113. package/dist/5353.js +1 -0
  114. package/dist/5353.js.map +1 -0
  115. package/dist/5377.js +1 -0
  116. package/dist/5377.js.map +1 -0
  117. package/dist/5413.js +1 -0
  118. package/dist/5413.js.map +1 -0
  119. package/dist/5422.js +1 -0
  120. package/dist/5422.js.map +1 -0
  121. package/dist/5500.js +1 -0
  122. package/dist/5500.js.map +1 -0
  123. package/dist/5754.js +1 -0
  124. package/dist/5754.js.map +1 -0
  125. package/dist/5805.js +1 -0
  126. package/dist/5805.js.map +1 -0
  127. package/dist/6048.js +1 -0
  128. package/dist/6048.js.map +1 -0
  129. package/dist/6055.js +1 -0
  130. package/dist/6055.js.map +1 -0
  131. package/dist/6206.js +1 -0
  132. package/dist/6206.js.map +1 -0
  133. package/dist/6279.js +1 -0
  134. package/dist/6279.js.map +1 -0
  135. package/dist/6399.js +1 -0
  136. package/dist/6399.js.map +1 -0
  137. package/dist/6540.js +2 -0
  138. package/dist/6540.js.map +1 -0
  139. package/dist/6606.js +1 -0
  140. package/dist/6606.js.map +1 -0
  141. package/dist/6682.js +1 -0
  142. package/dist/6682.js.map +1 -0
  143. package/dist/6802.js +1 -0
  144. package/dist/6802.js.map +1 -0
  145. package/dist/7024.js +1 -0
  146. package/dist/7024.js.map +1 -0
  147. package/dist/72.js +1 -0
  148. package/dist/72.js.map +1 -0
  149. package/dist/7269.js +1 -0
  150. package/dist/7269.js.map +1 -0
  151. package/dist/7332.js +1 -0
  152. package/dist/7332.js.map +1 -0
  153. package/dist/7369.js +1 -0
  154. package/dist/7369.js.map +1 -0
  155. package/dist/7593.js +1 -0
  156. package/dist/7593.js.map +1 -0
  157. package/dist/7694.js +1 -0
  158. package/dist/7694.js.map +1 -0
  159. package/dist/7698.js +1 -0
  160. package/dist/7698.js.map +1 -0
  161. package/dist/7734.js +1 -0
  162. package/dist/7734.js.map +1 -0
  163. package/dist/774.js +1 -0
  164. package/dist/774.js.map +1 -0
  165. package/dist/7852.js +1 -0
  166. package/dist/7852.js.map +1 -0
  167. package/dist/7949.js +2 -0
  168. package/dist/{246.js.LICENSE.txt → 7949.js.LICENSE.txt} +1 -10
  169. package/dist/7949.js.map +1 -0
  170. package/dist/7958.js +1 -0
  171. package/dist/7958.js.map +1 -0
  172. package/dist/8137.js +1 -0
  173. package/dist/8137.js.map +1 -0
  174. package/dist/8167.js +1 -0
  175. package/dist/8167.js.map +1 -0
  176. package/dist/818.js +1 -0
  177. package/dist/818.js.map +1 -0
  178. package/dist/8250.js +1 -0
  179. package/dist/8250.js.map +1 -0
  180. package/dist/8308.js +1 -0
  181. package/dist/8308.js.map +1 -0
  182. package/dist/8735.js +1 -0
  183. package/dist/8735.js.map +1 -0
  184. package/dist/8947.js +1 -0
  185. package/dist/8947.js.map +1 -0
  186. package/dist/8961.js +1 -0
  187. package/dist/8961.js.map +1 -0
  188. package/dist/902.js +1 -0
  189. package/dist/902.js.map +1 -0
  190. package/dist/9062.js +1 -0
  191. package/dist/9062.js.map +1 -0
  192. package/dist/9134.js +1 -0
  193. package/dist/9134.js.map +1 -0
  194. package/dist/9249.js +1 -0
  195. package/dist/9249.js.map +1 -0
  196. package/dist/9418.js +2 -0
  197. package/dist/9418.js.LICENSE.txt +1 -0
  198. package/dist/9418.js.map +1 -0
  199. package/dist/9429.js +1 -0
  200. package/dist/9429.js.map +1 -0
  201. package/dist/9442.js +1 -0
  202. package/dist/9442.js.map +1 -0
  203. package/dist/961.js +1 -1
  204. package/dist/961.js.map +1 -1
  205. package/dist/968.js +1 -0
  206. package/dist/968.js.map +1 -0
  207. package/dist/9709.js +1 -0
  208. package/dist/9709.js.map +1 -0
  209. package/dist/9768.js +1 -0
  210. package/dist/9768.js.map +1 -0
  211. package/dist/9770.js +1 -0
  212. package/dist/9770.js.map +1 -0
  213. package/dist/9879.js +1 -0
  214. package/dist/9879.js.map +1 -0
  215. package/dist/9974.js +1 -0
  216. package/dist/9974.js.map +1 -0
  217. package/dist/esm-dha-workflow-app.js +1 -1
  218. package/dist/esm-dha-workflow-app.js.buildmanifest.json +2284 -210
  219. package/dist/esm-dha-workflow-app.js.map +1 -1
  220. package/dist/main.js +1 -1
  221. package/dist/main.js.map +1 -1
  222. package/dist/routes.json +1 -1
  223. package/jest.config.js +4 -0
  224. package/local-config.json +9 -0
  225. package/package.json +29 -11
  226. package/src/admissions/admission-request-list/admission-request-list.scss +0 -0
  227. package/src/admissions/admission-request-list/admission-request-list.tsx +263 -0
  228. package/src/admissions/admissions-dashboard.component.scss +15 -0
  229. package/src/admissions/admissions-dashboard.component.tsx +277 -0
  230. package/src/admissions/admissions.resource.ts +233 -0
  231. package/src/admissions/admitted-list/admitted-patients-list.tsx +268 -0
  232. package/src/admissions/awaiting-discharge-list/awaiting-discharge-list.tsx +197 -0
  233. package/src/admissions/bed-assigment-request/bed-assignment-request-list.tsx +134 -0
  234. package/src/admissions/constants/index.ts +33 -0
  235. package/src/admissions/discharged-list/discharged-list.scss +0 -0
  236. package/src/admissions/discharged-list/discharged-list.tsx +67 -0
  237. package/src/admissions/form-entry-workspace/form-entry-workspace.tsx +62 -0
  238. package/src/admissions/inpatient/admission-history/patient-admission-history.tsx +76 -0
  239. package/src/admissions/inpatient/admission-requests/patient-admission-requests.scss +19 -0
  240. package/src/admissions/inpatient/admission-requests/patient-admission-requests.tsx +72 -0
  241. package/src/admissions/inpatient/inpatient-admissions.component.scss +7 -0
  242. package/src/admissions/inpatient/inpatient-admissions.component.tsx +46 -0
  243. package/src/admissions/modal/add-bill-items/add-bill-items.modal.scss +17 -0
  244. package/src/admissions/modal/add-bill-items/add-bill-items.modal.tsx +220 -0
  245. package/src/admissions/modal/admit-elsewhere/admit-elsewhere.modal.scss +23 -0
  246. package/src/admissions/modal/admit-elsewhere/admit-elsewhere.modal.tsx +156 -0
  247. package/src/admissions/modal/admit-patient/admit-patient.modal.scss +0 -0
  248. package/src/admissions/modal/admit-patient/admit-patient.modal.tsx +111 -0
  249. package/src/admissions/modal/bed-swap/bed-swap.modal.scss +0 -0
  250. package/src/admissions/modal/bed-swap/bed-swap.modal.tsx +102 -0
  251. package/src/admissions/modal/cancel-admission-request/cancel-admission-request.scss +11 -0
  252. package/src/admissions/modal/cancel-admission-request/cancel-admission-request.tsx +105 -0
  253. package/src/admissions/modal/discharge/discharge-patient.modal.scss +13 -0
  254. package/src/admissions/modal/discharge/discharge-patient.modal.tsx +86 -0
  255. package/src/admissions/types/index.ts +263 -0
  256. package/src/appointments/appointments.component.scss +6 -0
  257. package/src/appointments/appointments.component.tsx +8 -1
  258. package/src/billing/admin/claims/claims-list.component.scss +13 -0
  259. package/src/billing/admin/claims/claims-list.component.tsx +163 -0
  260. package/src/billing/admin/claims-admin-dashboard.component.scss +0 -0
  261. package/src/billing/admin/claims-admin-dashboard.component.tsx +32 -0
  262. package/src/billing/api/billing.api.ts +139 -0
  263. package/src/billing/billing-claims.resource.ts +1112 -0
  264. package/src/billing/billing-dashboard-link.component.tsx +31 -0
  265. package/src/billing/billing-dashboard-reset.ts +27 -0
  266. package/src/billing/billing-root.tsx +37 -0
  267. package/src/billing/dashboard/billingDashboard.component.scss +0 -0
  268. package/src/billing/dashboard/billingDashboard.component.tsx +25 -0
  269. package/src/billing/dashboard/v2/active-visits/active-visits.component.tsx +257 -0
  270. package/src/billing/dashboard/v2/active-visits/active-visits.resource.ts +85 -0
  271. package/src/billing/dashboard/v2/active-visits/active-visits.scss +15 -0
  272. package/src/billing/dashboard/v2/active-visits.component.tsx +102 -0
  273. package/src/billing/dashboard/v2/admissions/admission-requests-tab.component.tsx +79 -0
  274. package/src/billing/dashboard/v2/billing-and-claims-patient-chart.component.tsx +52 -0
  275. package/src/billing/dashboard/v2/billing-claims-dashboard.component.scss +221 -0
  276. package/src/billing/dashboard/v2/billing-claims-dashboard.component.tsx +342 -0
  277. package/src/billing/dashboard/v2/cash-checklist/bill-document.component.scss +90 -0
  278. package/src/billing/dashboard/v2/cash-checklist/bill-document.component.tsx +101 -0
  279. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.component.scss +199 -0
  280. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.component.tsx +361 -0
  281. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.resource.ts +239 -0
  282. package/src/billing/dashboard/v2/cash-checklist/payment-drawer.component.scss +246 -0
  283. package/src/billing/dashboard/v2/cash-checklist/payment-drawer.component.tsx +182 -0
  284. package/src/billing/dashboard/v2/claim-statuses.ts +143 -0
  285. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.scss +0 -0
  286. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.tsx +35 -0
  287. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-panel.component.scss +67 -0
  288. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-panel.component.tsx +90 -0
  289. package/src/billing/dashboard/v2/claim-visits/claim-doctors/claim-doctors.scss +28 -0
  290. package/src/billing/dashboard/v2/claim-visits/claim-doctors/claim-doctors.tsx +36 -0
  291. package/src/billing/dashboard/v2/claim-visits/claim-history/claim-history.component.scss +119 -0
  292. package/src/billing/dashboard/v2/claim-visits/claim-history/claim-history.component.tsx +198 -0
  293. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-details.component.scss +5 -0
  294. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-details.component.tsx +160 -0
  295. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-panel.component.scss +105 -0
  296. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-panel.component.tsx +184 -0
  297. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/intervention-attachments.component.scss +161 -0
  298. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/intervention-attachments.component.tsx +328 -0
  299. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-details.component.tsx +96 -0
  300. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-document.component.tsx +236 -0
  301. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-panel.component.scss +98 -0
  302. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-panel.component.tsx +293 -0
  303. package/src/billing/dashboard/v2/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.scss +133 -0
  304. package/src/billing/dashboard/v2/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.tsx +217 -0
  305. package/src/billing/dashboard/v2/claim-visits/claim-list/claim-visits.component.scss +28 -0
  306. package/src/billing/dashboard/v2/claim-visits/claim-list/claim-visits.component.tsx +315 -0
  307. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-by-token.component.tsx +150 -0
  308. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-page.component.scss +13 -0
  309. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-page.component.tsx +116 -0
  310. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-visit-details.component.scss +338 -0
  311. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-visit-details.component.tsx +616 -0
  312. package/src/billing/dashboard/v2/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.scss +5 -0
  313. package/src/billing/dashboard/v2/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.tsx +49 -0
  314. package/src/billing/dashboard/v2/claim-visits/modal/claim-visit-details/claim-visit-details.modal.scss +17 -0
  315. package/src/billing/dashboard/v2/claim-visits/modal/claim-visit-details/claim-visit-details.modal.tsx +56 -0
  316. package/src/billing/dashboard/v2/claim-visits/modal/close-claim/close-claim.modal.scss +0 -0
  317. package/src/billing/dashboard/v2/claim-visits/modal/close-claim/close-claim.modal.tsx +129 -0
  318. package/src/billing/dashboard/v2/claim-visits/modal/submit-claim/submit-claim.modal.tsx +280 -0
  319. package/src/billing/dashboard/v2/claim-visits/shared/_empty-state.scss +28 -0
  320. package/src/billing/dashboard/v2/claim-visits/shared/record-cards.component.scss +298 -0
  321. package/src/billing/dashboard/v2/claim-visits/shared/record-cards.component.tsx +252 -0
  322. package/src/billing/dashboard/v2/claim-visits/shared/record-details.workspace.scss +42 -0
  323. package/src/billing/dashboard/v2/claim-visits/shared/record-details.workspace.tsx +67 -0
  324. package/src/billing/dashboard/v2/claim-visits/shared/record-table.component.scss +61 -0
  325. package/src/billing/dashboard/v2/claim-visits/shared/record-table.component.tsx +150 -0
  326. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.resource.ts +51 -0
  327. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.workspace.scss +191 -0
  328. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.workspace.tsx +660 -0
  329. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.component.scss +595 -0
  330. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.component.tsx +810 -0
  331. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.resource.ts +282 -0
  332. package/src/billing/dashboard/v2/claims-accounting/bill-utils.ts +134 -0
  333. package/src/billing/dashboard/v2/claims-accounting/claim-detail.component.tsx +346 -0
  334. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.component.scss +546 -0
  335. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.component.tsx +206 -0
  336. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.resource.ts +337 -0
  337. package/src/billing/dashboard/v2/claims-accounting/invoice-document.component.scss +90 -0
  338. package/src/billing/dashboard/v2/claims-accounting/invoice-document.component.tsx +90 -0
  339. package/src/billing/dashboard/v2/claims-accounting/remittances.component.tsx +169 -0
  340. package/src/billing/dashboard/v2/claims-accounting/remittances.resource.ts +46 -0
  341. package/src/billing/dashboard/v2/claims-accounting/status-meta.ts +25 -0
  342. package/src/billing/dashboard/v2/clearance/cash-patients.scss +18 -0
  343. package/src/billing/dashboard/v2/clearance/cash.component.tsx +145 -0
  344. package/src/billing/dashboard/v2/clearance/clearance.component.scss +84 -0
  345. package/src/billing/dashboard/v2/clearance/clearance.component.tsx +225 -0
  346. package/src/billing/dashboard/v2/clearance/pay-cash.component.tsx +199 -0
  347. package/src/billing/dashboard/v2/clearance/pay-cash.scss +28 -0
  348. package/src/billing/dashboard/v2/clearance/prepaid-services.component.tsx +112 -0
  349. package/src/billing/dashboard/v2/facility-bills/claim-status.ts +249 -0
  350. package/src/billing/dashboard/v2/facility-bills/facility-bills.component.scss +140 -0
  351. package/src/billing/dashboard/v2/facility-bills/facility-bills.component.tsx +688 -0
  352. package/src/billing/dashboard/v2/facility-bills/preauths-datatables/pending-preauths.component.tsx +132 -0
  353. package/src/billing/dashboard/v2/facility-bills/preauths-datatables/preauth-preview-table.component.tsx +267 -0
  354. package/src/billing/dashboard/v2/facility-bills/preauths.component.tsx +130 -0
  355. package/src/billing/dashboard/v2/inpatient-requests/inpatient-requests.component.scss +22 -0
  356. package/src/billing/dashboard/v2/inpatient-requests/inpatient-requests.component.tsx +382 -0
  357. package/src/billing/dashboard/v2/inpatient-requests/modal/start-inpatient-claim/start-inpatient-claim.component.scss +0 -0
  358. package/src/billing/dashboard/v2/inpatient-requests/modal/start-inpatient-claim/start-inpatient-claim.component.tsx +0 -0
  359. package/src/billing/dashboard/v2/new-facility-bills/bills-table.component.tsx +78 -0
  360. package/src/billing/dashboard/v2/new-facility-bills/bills-table.scss +18 -0
  361. package/src/billing/dashboard/v2/new-facility-bills/new-facility-bills.component.tsx +64 -0
  362. package/src/billing/dashboard/v2/new-facility-bills/new-facility-bills.scss +146 -0
  363. package/src/billing/dashboard/v2/patient-bill-details/attachments/add-attachments.component.tsx +234 -0
  364. package/src/billing/dashboard/v2/patient-bill-details/attachments/attachment.component.tsx +157 -0
  365. package/src/billing/dashboard/v2/patient-bill-details/attachments/attachments.scss +92 -0
  366. package/src/billing/dashboard/v2/patient-bill-details/attachments/case-summary/case-summary.scss +295 -0
  367. package/src/billing/dashboard/v2/patient-bill-details/attachments/case-summary/case-summary.tsx +326 -0
  368. package/src/billing/dashboard/v2/patient-bill-details/attachments/death-notification.component.tsx +162 -0
  369. package/src/billing/dashboard/v2/patient-bill-details/attachments/death-notification.resource.ts +112 -0
  370. package/src/billing/dashboard/v2/patient-bill-details/attachments/death-notification.scss +88 -0
  371. package/src/billing/dashboard/v2/patient-bill-details/attachments/dialysis/dialysis-chart.scss +238 -0
  372. package/src/billing/dashboard/v2/patient-bill-details/attachments/dialysis/dialysis-chart.tsx +269 -0
  373. package/src/billing/dashboard/v2/patient-bill-details/attachments/discharge-summary/discharge-summary.scss +96 -0
  374. package/src/billing/dashboard/v2/patient-bill-details/attachments/discharge-summary/discharge-summary.tsx +124 -0
  375. package/src/billing/dashboard/v2/patient-bill-details/attachments/final-bill.component.tsx +152 -0
  376. package/src/billing/dashboard/v2/patient-bill-details/attachments/final-bill.scss +225 -0
  377. package/src/billing/dashboard/v2/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.scss +182 -0
  378. package/src/billing/dashboard/v2/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.tsx +173 -0
  379. package/src/billing/dashboard/v2/patient-bill-details/attachments/generate-attachments.component.tsx +450 -0
  380. package/src/billing/dashboard/v2/patient-bill-details/attachments/invoice.component.tsx +151 -0
  381. package/src/billing/dashboard/v2/patient-bill-details/attachments/invoice.scss +225 -0
  382. package/src/billing/dashboard/v2/patient-bill-details/attachments/type.ts +44 -0
  383. package/src/billing/dashboard/v2/patient-bill-details/bill-details/bill-details.scss +107 -0
  384. package/src/billing/dashboard/v2/patient-bill-details/bill-details/bill-details.tsx +508 -0
  385. package/src/billing/dashboard/v2/patient-bill-details/bill-details-page.component.scss +30 -0
  386. package/src/billing/dashboard/v2/patient-bill-details/bill-details-page.component.tsx +94 -0
  387. package/src/billing/dashboard/v2/patient-bill-details/claim-details/claim-details-skeleton.component.scss +89 -0
  388. package/src/billing/dashboard/v2/patient-bill-details/claim-details/claim-details-skeleton.component.tsx +53 -0
  389. package/src/billing/dashboard/v2/patient-bill-details/claim-details/patient-claim-details.component.scss +32 -0
  390. package/src/billing/dashboard/v2/patient-bill-details/claim-details/patient-claim-details.component.tsx +215 -0
  391. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.scss +0 -0
  392. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.tsx +99 -0
  393. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-line/add-claim-line.modal.tsx +187 -0
  394. package/src/billing/dashboard/v2/patient-bill-details/patient-bill-details.scss +153 -0
  395. package/src/billing/dashboard/v2/patient-bill-details/patient-bill-details.tsx +458 -0
  396. package/src/billing/dashboard/v2/patient-bill-details/payment-mode.ts +124 -0
  397. package/src/billing/dashboard/v2/patient-bill-details/workspaces/add-claim-line/add-claim-line.workspace.scss +27 -0
  398. package/src/billing/dashboard/v2/patient-bill-details/workspaces/add-claim-line/add-claim-line.workspace.tsx +234 -0
  399. package/src/billing/dashboard/v2/patient-bill-details/workspaces/bill-item-payment/bill-item-payment.workspace.scss +27 -0
  400. package/src/billing/dashboard/v2/patient-bill-details/workspaces/bill-item-payment/bill-item-payment.workspace.tsx +123 -0
  401. package/src/billing/dashboard/v2/preauth/preauth-attachments.component.tsx +389 -0
  402. package/src/billing/dashboard/v2/preauth/preauth-list.component.scss +38 -0
  403. package/src/billing/dashboard/v2/preauth/preauth-list.component.tsx +241 -0
  404. package/src/billing/dashboard/v2/preauth/preauth-status-tag.component.tsx +75 -0
  405. package/src/billing/dashboard/v2/preauth/preauth-typed-fields.md +125 -0
  406. package/src/billing/dashboard/v2/preauth/preauth.resource.ts +1032 -0
  407. package/src/billing/dashboard/v2/preauth/preauth.workspace.scss +91 -0
  408. package/src/billing/dashboard/v2/preauth/preauth.workspace.tsx +1802 -0
  409. package/src/billing/dashboard/v2/preauth/preauthorizations-tab.component.tsx +53 -0
  410. package/src/billing/dashboard/v2/sha-claims/sha-claims-table.component.tsx +36 -0
  411. package/src/billing/dashboard/v2/sha-claims/sha-claims.component.tsx +60 -0
  412. package/src/billing/dashboard/v2/sha-claims/sha-claims.scss +8 -0
  413. package/src/billing/dashboard/v2/shared/dash-board-card/dash-board-card.component.scss +17 -0
  414. package/src/billing/dashboard/v2/shared/dash-board-card/dash-board-card.component.tsx +15 -0
  415. package/src/billing/dashboard/v2/shared/empty-state.component.scss +24 -0
  416. package/src/billing/dashboard/v2/shared/empty-state.component.tsx +13 -0
  417. package/src/billing/dashboard/v2/shared/scroll-to-top.component.scss +54 -0
  418. package/src/billing/dashboard/v2/shared/scroll-to-top.component.tsx +54 -0
  419. package/src/billing/dashboard/v2/shared/table-toolbar.component.scss +77 -0
  420. package/src/billing/dashboard/v2/shared/table-toolbar.component.tsx +48 -0
  421. package/src/billing/dashboard/v2/types/index.ts +534 -0
  422. package/src/billing/dashboard/v3/active-visits/active-visits.component.tsx +256 -0
  423. package/src/billing/dashboard/v3/active-visits/active-visits.resource.ts +57 -0
  424. package/src/billing/dashboard/v3/active-visits/active-visits.scss +15 -0
  425. package/src/billing/dashboard/v3/cash-checklist/bill-document.component.scss +90 -0
  426. package/src/billing/dashboard/v3/cash-checklist/bill-document.component.tsx +101 -0
  427. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.component.scss +199 -0
  428. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.component.tsx +361 -0
  429. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.resource.ts +240 -0
  430. package/src/billing/dashboard/v3/cash-checklist/payment-drawer.component.scss +246 -0
  431. package/src/billing/dashboard/v3/cash-checklist/payment-drawer.component.tsx +182 -0
  432. package/src/billing/dashboard/v3/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.scss +0 -0
  433. package/src/billing/dashboard/v3/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.tsx +44 -0
  434. package/src/billing/dashboard/v3/claim-visits/claim-doctors/claim-doctors.scss +5 -0
  435. package/src/billing/dashboard/v3/claim-visits/claim-doctors/claim-doctors.tsx +40 -0
  436. package/src/billing/dashboard/v3/claim-visits/claim-documents/claim-documents.scss +10 -0
  437. package/src/billing/dashboard/v3/claim-visits/claim-documents/claim-documents.tsx +25 -0
  438. package/src/billing/dashboard/v3/claim-visits/claim-intervention-details/claim-intervention-details.component.tsx +268 -0
  439. package/src/billing/dashboard/v3/claim-visits/claim-invoice-details/claim-invoice-details.component.scss +6 -0
  440. package/src/billing/dashboard/v3/claim-visits/claim-invoice-details/claim-invoice-details.component.tsx +85 -0
  441. package/src/billing/dashboard/v3/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.scss +0 -0
  442. package/src/billing/dashboard/v3/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.tsx +109 -0
  443. package/src/billing/dashboard/v3/claim-visits/claim-visit-details/claim-visit-details.component.scss +103 -0
  444. package/src/billing/dashboard/v3/claim-visits/claim-visit-details/claim-visit-details.component.tsx +519 -0
  445. package/src/billing/dashboard/v3/claim-visits/claim-visits.component.scss +5 -0
  446. package/src/billing/dashboard/v3/claim-visits/claim-visits.component.tsx +139 -0
  447. package/src/billing/dashboard/v3/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.scss +5 -0
  448. package/src/billing/dashboard/v3/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.tsx +49 -0
  449. package/src/billing/dashboard/v3/claim-visits/modal/claim-invoice-lines/claim-invoice-lines.modal.scss +7 -0
  450. package/src/billing/dashboard/v3/claim-visits/modal/claim-invoice-lines/claim-invoice-lines.modal.tsx +35 -0
  451. package/src/billing/dashboard/v3/claim-visits/modal/claim-visit-details/claim-visit-details.modal.scss +6 -0
  452. package/src/billing/dashboard/v3/claim-visits/modal/claim-visit-details/claim-visit-details.modal.tsx +33 -0
  453. package/src/billing/dashboard/v3/claim-visits/modal/close-claim/close-claim.modal.scss +0 -0
  454. package/src/billing/dashboard/v3/claim-visits/modal/close-claim/close-claim.modal.tsx +129 -0
  455. package/src/billing/dashboard/v3/claim-visits/modal/identify-emergency-unknown-patient/identify-emergencu-unknown-patient.scss +407 -0
  456. package/src/billing/dashboard/v3/claim-visits/modal/identify-emergency-unknown-patient/identify-emergency-unknown-patient.component.tsx +523 -0
  457. package/src/billing/dashboard/v3/claim-visits/modal/identify-emergency-unknown-patient/identify-patient-helper.ts +77 -0
  458. package/src/billing/dashboard/v3/claim-visits/modal/submit-claim/submit-claim.modal.tsx +280 -0
  459. package/src/billing/dashboard/v3/claim-visits/modal/submit-emergency-claim/submit-emergency-claim.component.tsx +91 -0
  460. package/src/billing/dashboard/v3/claim-visits/modal/submit-emergency-claim/submit-emergency.scss +14 -0
  461. package/src/billing/dashboard/v3/claim-visits/payer-preview/index.scss +140 -0
  462. package/src/billing/dashboard/v3/claim-visits/payer-preview/payer-preview-tile.component.tsx +55 -0
  463. package/src/billing/dashboard/v3/claim-visits/payer-preview/payer-preview-workspace.component.tsx +171 -0
  464. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-doctors.component.tsx +54 -0
  465. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-lines.component.tsx +48 -0
  466. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-notes.component.tsx +47 -0
  467. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-diagnoses.component.tsx +44 -0
  468. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-interventions.component.tsx +44 -0
  469. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.resource.ts +51 -0
  470. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.workspace.scss +191 -0
  471. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.workspace.tsx +644 -0
  472. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.component.scss +595 -0
  473. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.component.tsx +810 -0
  474. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.resource.ts +282 -0
  475. package/src/billing/dashboard/v3/claims-accounting/bill-utils.ts +134 -0
  476. package/src/billing/dashboard/v3/claims-accounting/claim-detail.component.tsx +346 -0
  477. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.component.scss +546 -0
  478. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.component.tsx +206 -0
  479. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.resource.ts +337 -0
  480. package/src/billing/dashboard/v3/claims-accounting/invoice-document.component.scss +90 -0
  481. package/src/billing/dashboard/v3/claims-accounting/invoice-document.component.tsx +90 -0
  482. package/src/billing/dashboard/v3/claims-accounting/remittances.component.tsx +169 -0
  483. package/src/billing/dashboard/v3/claims-accounting/remittances.resource.ts +46 -0
  484. package/src/billing/dashboard/v3/claims-accounting/status-meta.ts +25 -0
  485. package/src/billing/dashboard/v3/claims-stats-dashboard/claim-stat/claim-stat.component.scss +27 -0
  486. package/src/billing/dashboard/v3/claims-stats-dashboard/claim-stat/claim-stat.component.tsx +41 -0
  487. package/src/billing/dashboard/v3/claims-stats-dashboard/claims-stats-dashboard.component.scss +16 -0
  488. package/src/billing/dashboard/v3/claims-stats-dashboard/claims-stats-dashboard.component.tsx +184 -0
  489. package/src/billing/dashboard/v3/claims-stats-dashboard/modal/claim-stats-list/claim-stats-list.modal.scss +0 -0
  490. package/src/billing/dashboard/v3/claims-stats-dashboard/modal/claim-stats-list/claim-stats-list.modal.tsx +27 -0
  491. package/src/billing/dashboard/v3/clearance/clearance.component.scss +100 -0
  492. package/src/billing/dashboard/v3/clearance/clearance.component.tsx +0 -0
  493. package/src/billing/dashboard/v3/clearance/prepaid-services.component.tsx +112 -0
  494. package/src/billing/dashboard/v3/facility-bills/claim-status.ts +243 -0
  495. package/src/billing/dashboard/v3/facility-bills/facility-bills.component.scss +92 -0
  496. package/src/billing/dashboard/v3/facility-bills/facility-bills.component.tsx +306 -0
  497. package/src/billing/dashboard/v3/facility-bills/preauths-datatables/pending-preauths.component.tsx +132 -0
  498. package/src/billing/dashboard/v3/facility-bills/preauths-datatables/preauth-preview-table.component.tsx +232 -0
  499. package/src/billing/dashboard/v3/facility-bills/preauths.component.tsx +127 -0
  500. package/src/billing/dashboard/v3/patient-bill-details/attachments/add-attachments.component.tsx +228 -0
  501. package/src/billing/dashboard/v3/patient-bill-details/attachments/attachment.component.tsx +157 -0
  502. package/src/billing/dashboard/v3/patient-bill-details/attachments/attachments.scss +92 -0
  503. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary-helper.ts +58 -0
  504. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary.scss +295 -0
  505. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary.tsx +287 -0
  506. package/src/billing/dashboard/v3/patient-bill-details/attachments/dialysis/dialysis-chart.scss +238 -0
  507. package/src/billing/dashboard/v3/patient-bill-details/attachments/dialysis/dialysis-chart.tsx +352 -0
  508. package/src/billing/dashboard/v3/patient-bill-details/attachments/dialysis/dialysis-helper.ts +117 -0
  509. package/src/billing/dashboard/v3/patient-bill-details/attachments/discharge-summary/discharge-summary.scss +96 -0
  510. package/src/billing/dashboard/v3/patient-bill-details/attachments/discharge-summary/discharge-summary.tsx +126 -0
  511. package/src/billing/dashboard/v3/patient-bill-details/attachments/final-bill.component.tsx +75 -0
  512. package/src/billing/dashboard/v3/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.scss +182 -0
  513. package/src/billing/dashboard/v3/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.tsx +253 -0
  514. package/src/billing/dashboard/v3/patient-bill-details/attachments/generate-attachments.component.tsx +450 -0
  515. package/src/billing/dashboard/v3/patient-bill-details/attachments/invoice.component.tsx +151 -0
  516. package/src/billing/dashboard/v3/patient-bill-details/attachments/invoice.scss +225 -0
  517. package/src/billing/dashboard/v3/patient-bill-details/attachments/lab-results/lab-orders.component.tsx +198 -0
  518. package/src/billing/dashboard/v3/patient-bill-details/attachments/lab-results/lab-orders.scss +227 -0
  519. package/src/billing/dashboard/v3/patient-bill-details/attachments/medical-report/medical-report.component.tsx +346 -0
  520. package/src/billing/dashboard/v3/patient-bill-details/attachments/medical-report/medical-report.scss +265 -0
  521. package/src/billing/dashboard/v3/patient-bill-details/attachments/proforma-invoice/proforma-invoice.component.tsx +347 -0
  522. package/src/billing/dashboard/v3/patient-bill-details/attachments/proforma-invoice/proforma-invoice.scss +285 -0
  523. package/src/billing/dashboard/v3/patient-bill-details/attachments/type.ts +280 -0
  524. package/src/billing/dashboard/v3/patient-bill-details/attachments/ultrasound-report/ultrasound-report.scss +273 -0
  525. package/src/billing/dashboard/v3/patient-bill-details/attachments/ultrasound-report/utlrasound-report.component.tsx +435 -0
  526. package/src/billing/dashboard/v3/patient-bill-details/bill-details/bill-details.scss +17 -0
  527. package/src/billing/dashboard/v3/patient-bill-details/bill-details/bill-details.tsx +377 -0
  528. package/src/billing/dashboard/v3/patient-bill-details/claim-details/patient-claim-details.component.scss +0 -0
  529. package/src/billing/dashboard/v3/patient-bill-details/claim-details/patient-claim-details.component.tsx +71 -0
  530. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.scss +0 -0
  531. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.tsx +99 -0
  532. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-line/add-claim-line.modal.scss +14 -0
  533. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-line/add-claim-line.modal.tsx +156 -0
  534. package/src/billing/dashboard/v3/patient-bill-details/modals/bill-item-payment/bill-item-payment.modal.scss +6 -0
  535. package/src/billing/dashboard/v3/patient-bill-details/modals/bill-item-payment/bill-item-payment.modal.tsx +137 -0
  536. package/src/billing/dashboard/v3/patient-bill-details/modals/claim-details/claim-details.modal.scss +28 -0
  537. package/src/billing/dashboard/v3/patient-bill-details/modals/claim-details/claim-details.modal.tsx +170 -0
  538. package/src/billing/dashboard/v3/patient-bill-details/modals/pomsf/pomsf-scheme-balance.util.test.ts +56 -0
  539. package/src/billing/dashboard/v3/patient-bill-details/modals/pomsf/pomsf-scheme-balance.util.ts +27 -0
  540. package/src/billing/dashboard/v3/patient-bill-details/modals/pomsf/set-effective-pomsf-coverage.component.tsx +128 -0
  541. package/src/billing/dashboard/v3/patient-bill-details/modals/pomsf/set-effective-pomsf-coverage.scss +27 -0
  542. package/src/billing/dashboard/v3/patient-bill-details/patient-bill-details.scss +85 -0
  543. package/src/billing/dashboard/v3/patient-bill-details/patient-bill-details.tsx +363 -0
  544. package/src/billing/dashboard/v3/patient-bill-details/patient-visit-details.tsx +256 -0
  545. package/src/billing/dashboard/v3/patient-bill-details/patient-visit.scss +9 -0
  546. package/src/billing/dashboard/v3/patient-bill-details/visit-diagnosis-details/visit-diagnosis-details.component.scss +0 -0
  547. package/src/billing/dashboard/v3/patient-bill-details/visit-diagnosis-details/visit-diagnosis-details.component.tsx +102 -0
  548. package/src/billing/dashboard/v3/preauth/elective/elective-authorize.resource.ts +284 -0
  549. package/src/billing/dashboard/v3/preauth/elective/elective-preauth-request.workspace.scss +125 -0
  550. package/src/billing/dashboard/v3/preauth/elective/elective-preauth-request.workspace.tsx +1184 -0
  551. package/src/billing/dashboard/v3/preauth/elective/elective-preauth.component.scss +15 -0
  552. package/src/billing/dashboard/v3/preauth/elective/elective-preauth.component.tsx +377 -0
  553. package/src/billing/dashboard/v3/preauth/elective/elective-preauth.resource.ts +1378 -0
  554. package/src/billing/dashboard/v3/preauth/elective/elective-requests-list.component.tsx +357 -0
  555. package/src/billing/dashboard/v3/preauth/preauth-attachments.component.tsx +388 -0
  556. package/src/billing/dashboard/v3/preauth/preauth-list.component.scss +34 -0
  557. package/src/billing/dashboard/v3/preauth/preauth-list.component.tsx +300 -0
  558. package/src/billing/dashboard/v3/preauth/preauth-status-tag.component.tsx +75 -0
  559. package/src/billing/dashboard/v3/preauth/preauth-typed-fields.md +125 -0
  560. package/src/billing/dashboard/v3/preauth/preauth.resource.ts +1549 -0
  561. package/src/billing/dashboard/v3/preauth/preauth.workspace.scss +176 -0
  562. package/src/billing/dashboard/v3/preauth/preauth.workspace.tsx +2458 -0
  563. package/src/billing/dashboard/v3/preauth/preauthorizations-tab.component.tsx +55 -0
  564. package/src/billing/dashboard/v3/shared/empty-state.component.scss +25 -0
  565. package/src/billing/dashboard/v3/shared/empty-state.component.tsx +13 -0
  566. package/src/billing/dashboard/v3/shared/table-toolbar.component.scss +64 -0
  567. package/src/billing/dashboard/v3/shared/table-toolbar.component.tsx +48 -0
  568. package/src/billing/dashboard/v3/types/index.ts +450 -0
  569. package/src/billing/extensions/generate-order-bill-button/generate-order-bill-button.extension.tsx +55 -0
  570. package/src/billing/extensions/generate-order-bill-button/generate-order-bill-button.scss +16 -0
  571. package/src/billing/extensions/visit-billing/visit-billing.extension.scss +0 -0
  572. package/src/billing/extensions/visit-billing/visit-billing.extension.tsx +514 -0
  573. package/src/billing/invoice/bill.resource.ts +47 -0
  574. package/src/billing/invoice/invoice-header/header-card/header-card.scss +17 -0
  575. package/src/billing/invoice/invoice-header/header-card/header-card.tsx +21 -0
  576. package/src/billing/invoice/invoice.scss +113 -0
  577. package/src/billing/invoice/invoice.tsx +1441 -0
  578. package/src/billing/invoice/line-items/line-items.scss +0 -0
  579. package/src/billing/invoice/line-items/line-items.tsx +120 -0
  580. package/src/billing/invoice/modal/delete-bill-item/delete-bill-item.modal.scss +23 -0
  581. package/src/billing/invoice/modal/delete-bill-item/delete-bill-item.modal.tsx +114 -0
  582. package/src/billing/invoice/modal/edit-bill-item/edit-bill-item.modal.scss +0 -0
  583. package/src/billing/invoice/modal/edit-bill-item/edit-bill-item.modal.tsx +122 -0
  584. package/src/billing/invoice/payment-details/payment-details.scss +0 -0
  585. package/src/billing/invoice/payment-details/payment-details.tsx +43 -0
  586. package/src/billing/invoice/print-invoice/print-receipt.component.tsx +44 -0
  587. package/src/billing/invoice/print-invoice/print-receipt.scss +14 -0
  588. package/src/billing/maternity-discharge.resource.ts +21 -0
  589. package/src/billing/reports/billing-and-claims-reports-dashboard.scss +40 -0
  590. package/src/billing/reports/billing-and-claims-reports-dashboard.tsx +32 -0
  591. package/src/billing/reports/claims/claims-report-dashboard.scss +55 -0
  592. package/src/billing/reports/claims/claims-report-dashboard.tsx +136 -0
  593. package/src/billing/reports/claims/summary-data/summary-data.scss +24 -0
  594. package/src/billing/reports/claims/summary-data/summary-data.tsx +184 -0
  595. package/src/billing/types/index.ts +411 -0
  596. package/src/billing/utils/index.ts +17 -0
  597. package/src/billing/widgets/billingTotalsRow.component.scss +0 -0
  598. package/src/billing/widgets/billingTotalsRow.component.tsx +712 -0
  599. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.resource.ts +223 -0
  600. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.scss +58 -0
  601. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.workspace.tsx +874 -0
  602. package/src/billing/workspaces/create-order-bill-form-workspace/schema.ts +20 -0
  603. package/src/billing/workspaces/create-order-bill-form-workspace/types.ts +49 -0
  604. package/src/bookings/bookings.component.scss +7 -0
  605. package/src/bookings/bookings.component.tsx +35 -0
  606. package/src/bookings/daily/daily-bookings.resource.ts +2 -1
  607. package/src/case-summary/case-summary.extension.scss +13 -0
  608. package/src/case-summary/case-summary.extension.tsx +40 -0
  609. package/src/case-summary/case-summary.resource.test.ts +69 -0
  610. package/src/case-summary/case-summary.resource.ts +52 -0
  611. package/src/case-summary/components/case-summary-printable.component.scss +174 -0
  612. package/src/case-summary/components/case-summary-printable.component.tsx +288 -0
  613. package/src/case-summary/components/case-summary-printable.utils.ts +51 -0
  614. package/src/case-summary/types/case-summary.types.ts +152 -0
  615. package/src/claims/claims.component.scss +70 -0
  616. package/src/claims/claims.component.tsx +743 -0
  617. package/src/claims/claims.resource.ts +1855 -0
  618. package/src/claims/index.ts +365 -0
  619. package/src/claims/interventions.resource.ts +131 -0
  620. package/src/claims/utils.ts +64 -0
  621. package/src/config-schema.ts +264 -0
  622. package/src/context/patient-context.tsx +27 -0
  623. package/src/critical-care-unit/critical-care-root.tsx +23 -0
  624. package/src/critical-care-unit/hdu/hdu-queues.component.scss +7 -0
  625. package/src/critical-care-unit/hdu/hdu-queues.component.tsx +31 -0
  626. package/src/critical-care-unit/hdu/queues/consultation/hdu-consultation.tsx +18 -0
  627. package/src/critical-care-unit/icu/icu-queues.component.scss +7 -0
  628. package/src/critical-care-unit/icu/icu-queues.component.tsx +31 -0
  629. package/src/critical-care-unit/icu/queues/consultation/icu-consultation.tsx +17 -0
  630. package/src/critical-care-unit/icu-burns/icu-burns-queues.component.scss +7 -0
  631. package/src/critical-care-unit/icu-burns/icu-burns-queues.component.tsx +30 -0
  632. package/src/critical-care-unit/icu-burns/queues/consultation/icu-burns-consultation.tsx +17 -0
  633. package/src/critical-care-unit/nicu/nicu-queues.component.scss +7 -0
  634. package/src/critical-care-unit/nicu/nicu-queues.component.tsx +31 -0
  635. package/src/critical-care-unit/nicu/queues/consultation/nicu-consultation.tsx +17 -0
  636. package/src/critical-care-unit/picu/picu-queues.component.scss +7 -0
  637. package/src/critical-care-unit/picu/picu-queues.component.tsx +31 -0
  638. package/src/critical-care-unit/picu/queues/consultation/picu-consultation.tsx +17 -0
  639. package/src/dashboard/charts/chart.component.scss +24 -0
  640. package/src/dashboard/charts/chart.component.tsx +56 -0
  641. package/src/dashboard/dashboard.component.scss +48 -3
  642. package/src/dashboard/dashboard.component.tsx +29 -38
  643. package/src/dashboard/overview/overview.component.scss +40 -59
  644. package/src/dashboard/overview/overview.component.tsx +55 -41
  645. package/src/dashboard-meta/accounting-dashboard.meta.ts +6 -0
  646. package/src/dashboard-meta/admissions-dashboard.meta.ts +6 -0
  647. package/src/dashboard-meta/billing-dashboard.meta.ts +6 -0
  648. package/src/dashboard-meta/bookings-dashboard.meta.ts +6 -0
  649. package/src/dashboard-meta/case-summary.meta.ts +6 -0
  650. package/src/dashboard-meta/claims-admin.meta.ts +6 -0
  651. package/src/dashboard-meta/consultation-dashboard.meta.ts +6 -0
  652. package/src/dashboard-meta/dha-workflow-dashboard.meta.ts +6 -0
  653. package/src/dashboard-meta/elective-preauth.meta.ts +6 -0
  654. package/src/dashboard-meta/emt-dashboard.meta.ts +6 -0
  655. package/src/dashboard-meta/inpatient-admissions.meta.ts +6 -0
  656. package/src/dashboard-meta/maternity-dashboard.meta.ts +6 -0
  657. package/src/dashboard-meta/mch-dashboard.meta.ts +6 -0
  658. package/src/dashboard-meta/registers-dashboard.meta.ts +6 -0
  659. package/src/{registry-dashboard.meta.ts → dashboard-meta/registry-dashboard.meta.ts} +2 -2
  660. package/src/dashboard-meta/service-queue-admin.meta.ts +6 -0
  661. package/src/dashboard-meta/shr-dashboard.meta.ts +19 -0
  662. package/src/dashboard-meta/specialized-clinics-dashboard.meta.ts +6 -0
  663. package/src/dashboard-meta/telemedicine-dashboard.meta.ts +6 -0
  664. package/src/dashboard-meta/telemedicine-patient-chart.meta.ts +6 -0
  665. package/src/dashboard-meta/triage-dashboard.meta.ts +6 -0
  666. package/src/death-reporting/death-reporting-form-button.component.tsx +50 -0
  667. package/src/death-reporting/death-reporting-form-button.resource.ts +64 -0
  668. package/src/emt/cr-lookup.resource.test.ts +88 -0
  669. package/src/emt/cr-lookup.resource.ts +42 -0
  670. package/src/emt/emt-queue.component.test.tsx +353 -0
  671. package/src/emt/emt-queue.component.tsx +463 -0
  672. package/src/emt/emt-queue.scss +85 -0
  673. package/src/emt/emt.resource.test.ts +247 -0
  674. package/src/emt/emt.resource.ts +150 -0
  675. package/src/emt/handover-modal/handover-modal.component.test.tsx +273 -0
  676. package/src/emt/handover-modal/handover-modal.component.tsx +538 -0
  677. package/src/emt/handover-modal/handover-modal.scss +113 -0
  678. package/src/emt/types/emt.types.ts +137 -0
  679. package/src/index.ts +236 -10
  680. package/src/mnch/maternity/maternity-queues.component.scss +7 -0
  681. package/src/mnch/maternity/maternity-queues.component.tsx +32 -0
  682. package/src/mnch/maternity/queues/triage/maternity-triage.tsx +15 -0
  683. package/src/mnch/mch/mch-queues.component.scss +10 -0
  684. package/src/mnch/mch/mch-queues.component.tsx +36 -0
  685. package/src/{mch → mnch/mch}/queues/consultation/mch-consultation.tsx +2 -2
  686. package/src/{mch → mnch/mch}/queues/triage/mch-triage.tsx +2 -2
  687. package/src/mnch/mnch-root.tsx +17 -0
  688. package/src/mortuary/mortuary.component.tsx +2 -2
  689. package/src/pharmacy/pharmacy.component.scss +16 -0
  690. package/src/pharmacy/pharmacy.component.tsx +11 -6
  691. package/src/registers/registers.component.tsx +8 -0
  692. package/src/registry/drawer/emr-compare.component.scss +263 -0
  693. package/src/registry/drawer/emr-compare.component.tsx +302 -0
  694. package/src/registry/drawer/emr-compare.resource.ts +181 -0
  695. package/src/registry/drawer/emr-create-preview.component.tsx +123 -0
  696. package/src/registry/drawer/otp-verification-step.component.tsx +398 -0
  697. package/src/registry/drawer/pomsf-balance.util.test.ts +177 -0
  698. package/src/registry/drawer/pomsf-balance.util.ts +116 -0
  699. package/src/registry/drawer/verification.resource.ts +60 -0
  700. package/src/registry/drawer/workflow-drawer.component.scss +1242 -0
  701. package/src/registry/drawer/workflow-drawer.component.tsx +1542 -0
  702. package/src/registry/eligibility/eligibility-details/eligibility-details.scss +38 -0
  703. package/src/registry/eligibility/eligibility-details/eligibility-details.tsx +101 -0
  704. package/src/registry/eligibility/eliigibility-tags/eligibility-tags.scss +16 -0
  705. package/src/registry/eligibility/eliigibility-tags/eligibility-tags.tsx +120 -0
  706. package/src/registry/eligibility/modal/eligibility-details.modal.scss +0 -0
  707. package/src/registry/eligibility/modal/eligibility-details.modal.tsx +45 -0
  708. package/src/registry/emergency/emergency-extension.component.tsx +599 -0
  709. package/src/registry/emergency/emergency-helper.ts +47 -0
  710. package/src/registry/emergency/emergency.resource.ts +291 -0
  711. package/src/registry/emergency/emergency.scss +123 -0
  712. package/src/registry/emergency/otp-component.tsx +289 -0
  713. package/src/registry/emergency/type/index.ts +77 -0
  714. package/src/registry/emergency/unidentified/unidentified-registration.component.tsx +154 -0
  715. package/src/registry/emergency/unidentified/unidentified-registration.scss +0 -0
  716. package/src/registry/emergency/unidentified/unidentified.component.tsx +376 -0
  717. package/src/registry/emergency/unidentified/unidentified.scss +0 -0
  718. package/src/registry/hie.resource.ts +481 -0
  719. package/src/registry/hie.types.ts +63 -0
  720. package/src/registry/modal/biometrics-verification-modal/biometrics-verification-modal.scss +277 -0
  721. package/src/registry/modal/biometrics-verification-modal/biometrics-verification-modal.tsx +218 -0
  722. package/src/registry/modal/biometrics-verification-modal/type.ts +39 -0
  723. package/src/registry/modal/client-details-modal/client-details-modal.tsx +65 -29
  724. package/src/registry/modal/otp-modal/otp-whitlisting-modal.component.tsx +809 -0
  725. package/src/registry/modal/otp-modal/otp-whitlisting-modal.scss +354 -0
  726. package/src/registry/modal/otp-modal/otp-whitlisting.scss +0 -0
  727. package/src/registry/modal/otp-verification-modal/claims-consent.scss +72 -0
  728. package/src/registry/modal/otp-verification-modal/claims-consent.tsx +135 -0
  729. package/src/registry/modal/otp-verification-modal/extension/claims-consent.extension.tsx +130 -0
  730. package/src/registry/modal/otp-verification-modal/otp-verification-modal.scss +15 -3
  731. package/src/registry/modal/otp-verification-modal/otp-verification-modal.tsx +136 -44
  732. package/src/registry/modal/send-to-triage/payment-details.tsx +120 -0
  733. package/src/registry/modal/send-to-triage/payment-method.component.tsx +54 -0
  734. package/src/registry/modal/send-to-triage/send-to-queue.modal.tsx +991 -0
  735. package/src/registry/modal/send-to-triage/send-to-queue.workspace.tsx +24 -0
  736. package/src/registry/modal/send-to-triage/send-to-triage.modal.scss +156 -3
  737. package/src/registry/modal/send-to-triage/send-to-triage.modal.tsx +1086 -130
  738. package/src/registry/modal/start-patient-visit/start-patient-visit.modal.scss +34 -0
  739. package/src/registry/modal/start-patient-visit/start-patient-visit.modal.tsx +231 -0
  740. package/src/registry/payment-details/payment-options/payment-options.scss +13 -0
  741. package/src/registry/payment-details/payment-options/payment-options.tsx +61 -14
  742. package/src/registry/registration-list/registration-list.component.scss +32 -0
  743. package/src/registry/registration-list/registration-list.component.tsx +103 -0
  744. package/src/registry/registry-entry.tsx +11 -0
  745. package/src/registry/registry.component.scss +402 -78
  746. package/src/registry/registry.component.tsx +732 -220
  747. package/src/registry/registry.resource.ts +22 -3
  748. package/src/registry/types/index.ts +126 -9
  749. package/src/registry/utils/error-handler.ts +54 -0
  750. package/src/registry/utils/format-dependant-display-data.ts +1 -1
  751. package/src/registry/utils/hie-client-adapter.ts +7 -4
  752. package/src/registry/utils/mask-data.ts +40 -0
  753. package/src/registry/utils/phone-number-formatter.ts +11 -0
  754. package/src/resources/dashboard.resource.ts +20 -0
  755. package/src/resources/identifier-types.ts +2 -0
  756. package/src/resources/patient-resource.ts +7 -2
  757. package/src/resources/queue.resource.ts +3 -3
  758. package/src/resources/superset.resource.ts +41 -0
  759. package/src/resources/visit.resource.ts +19 -1
  760. package/src/root.component.tsx +9 -7
  761. package/src/routes.json +658 -30
  762. package/src/service-queues/admin/queue/modal/create-queue/create-queue.modal.scss +31 -0
  763. package/src/service-queues/admin/queue/modal/create-queue/create-queue.modal.tsx +193 -0
  764. package/src/service-queues/admin/queue/modal/edit-queue/edit-queue.modal.scss +0 -0
  765. package/src/service-queues/admin/queue/modal/edit-queue/edit-queue.modal.tsx +201 -0
  766. package/src/service-queues/admin/queue/queue-list/queue-list.scss +33 -0
  767. package/src/service-queues/admin/queue/queue-list/queue-list.tsx +113 -0
  768. package/src/service-queues/admin/queue-entry/queue-entry-list.component.scss +6 -0
  769. package/src/service-queues/admin/queue-entry/queue-entry-list.component.tsx +137 -0
  770. package/src/service-queues/admin/queue-room/modal/create-queue-room/create-queue-room.modal.scss +31 -0
  771. package/src/service-queues/admin/queue-room/modal/create-queue-room/create-queue-room.modal.tsx +137 -0
  772. package/src/service-queues/admin/queue-room/modal/edit-queue-room/edit-queue-room.modal.scss +0 -0
  773. package/src/service-queues/admin/queue-room/modal/edit-queue-room/edit-queue-room.modal.tsx +146 -0
  774. package/src/service-queues/admin/queue-room/queue-room-list/queue-room-list.scss +22 -0
  775. package/src/service-queues/admin/queue-room/queue-room-list/queue-room-list.tsx +120 -0
  776. package/src/service-queues/admin/service-queue-admin-dashboard.component.scss +6 -0
  777. package/src/service-queues/admin/service-queue-admin-dashboard.component.tsx +35 -0
  778. package/src/service-queues/consultation/consultation.component.tsx +9 -0
  779. package/src/service-queues/extensions/service-queue-patient-banner/service-queue-patient-banner.scss +30 -0
  780. package/src/service-queues/extensions/service-queue-patient-banner/service-queue-patient-banner.tsx +108 -0
  781. package/src/service-queues/modals/daily-report-patient-list/daily-report-patient-list.scss +26 -0
  782. package/src/service-queues/modals/daily-report-patient-list/daily-report-patient-list.tsx +110 -0
  783. package/src/service-queues/modals/move/move-patient.component.scss +1 -1
  784. package/src/service-queues/modals/move/move-patient.component.tsx +31 -17
  785. package/src/service-queues/queue-list/check-in.service.ts +26 -0
  786. package/src/service-queues/queue-list/queue-list.component.scss +37 -0
  787. package/src/service-queues/queue-list/queue-list.component.tsx +296 -60
  788. package/src/service-queues/service-queue/service-queue.component.tsx +151 -8
  789. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.scss +5 -0
  790. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.tsx +36 -7
  791. package/src/service-queues/service-queue.tsx +22 -16
  792. package/src/service-queues/service-queues.resource.ts +293 -2
  793. package/src/service-queues/service.resource.ts +1 -1
  794. package/src/shared/constants/concepts.ts +70 -0
  795. package/src/shared/constants/patient-category.ts +6 -0
  796. package/src/shared/constants/patient-type.ts +10 -0
  797. package/src/shared/constants/visit-types.ts +9 -0
  798. package/src/shared/services/billable-service.resource.ts +121 -0
  799. package/src/shared/services/billing.resource.ts +112 -0
  800. package/src/shared/services/claims.resource.ts +47 -0
  801. package/src/shared/services/client-payment-mode.resource.ts +27 -0
  802. package/src/shared/services/client-payment.resource.ts +17 -0
  803. package/src/shared/services/consultation-clearance.resource.ts +210 -0
  804. package/src/shared/services/eligibility.resource.ts +20 -0
  805. package/src/shared/services/encounters.resource.ts +33 -0
  806. package/src/shared/types/index.ts +156 -0
  807. package/src/shared/ui/aggregate-stat-card/aggregate-stat-card.scss +42 -0
  808. package/src/shared/ui/aggregate-stat-card/aggregate-stat-card.tsx +42 -0
  809. package/src/shared/ui/confirm-modal/confirm.modal.scss +18 -0
  810. package/src/shared/ui/confirm-modal/confirm.modal.tsx +38 -0
  811. package/src/shared/ui/facility-worker-slot/facility-worker.component-slot.component.scss +39 -0
  812. package/src/shared/ui/facility-worker-slot/facility-worker.component-slot.component.tsx +19 -0
  813. package/src/shared/ui/otp-input/otp-input.component.scss +12 -12
  814. package/src/shared/ui/otp-input/otp-input.component.tsx +13 -6
  815. package/src/{service-queues/service-queue/stats → shared/ui}/stat-card/stat-card.component.tsx +6 -3
  816. package/src/shared/utils/format-title-case.ts +8 -0
  817. package/src/shared/utils/get-base-url.ts +15 -0
  818. package/src/shared/utils/get-tag-type.ts +75 -0
  819. package/src/shr/shr-close-visit-form.component.tsx +102 -0
  820. package/src/shr/shr-code-systems.json +363 -0
  821. package/src/shr/shr-terminology.resource.test.ts +66 -0
  822. package/src/shr/shr-terminology.resource.ts +64 -0
  823. package/src/shr/shr-viewer/shr-categories.test.ts +241 -0
  824. package/src/shr/shr-viewer/shr-categories.ts +209 -0
  825. package/src/shr/shr-viewer/shr-presentation.test.ts +511 -0
  826. package/src/shr/shr-viewer/shr-presentation.ts +883 -0
  827. package/src/shr/shr-viewer/shr-viewer.component.test.tsx +176 -0
  828. package/src/shr/shr-viewer/shr-viewer.component.tsx +432 -0
  829. package/src/shr/shr-viewer/shr-viewer.scss +239 -0
  830. package/src/shr/shr-visit-sync.test.ts +88 -0
  831. package/src/shr/shr-visit-sync.ts +62 -0
  832. package/src/shr/shr.component.tsx +730 -0
  833. package/src/shr/shr.resource.test.ts +737 -0
  834. package/src/shr/shr.resource.ts +463 -0
  835. package/src/shr/shr.scss +114 -0
  836. package/src/shr/shr.types.ts +682 -0
  837. package/src/shr/workspaces/shr-consent-workspace/schema.ts +53 -0
  838. package/src/shr/workspaces/shr-consent-workspace/shr-consent.scss +71 -0
  839. package/src/shr/workspaces/shr-consent-workspace/shr-consent.workspace.tsx +686 -0
  840. package/src/side-nav-menu/accounting-nav-link-config.ts +16 -0
  841. package/src/side-nav-menu/accounting-nav-links.tsx +42 -0
  842. package/src/side-nav-menu/critical-care-nav-links.tsx +42 -0
  843. package/src/side-nav-menu/critical-care-unit-nav-link-config.ts +28 -0
  844. package/src/side-nav-menu/mnch-nav-link-config.ts +16 -0
  845. package/src/side-nav-menu/mnch-nav-links.tsx +42 -0
  846. package/src/side-nav-menu/nav-link-config.ts +5 -5
  847. package/src/side-nav-menu/specialized-clinics-nav-link-config.ts +32 -0
  848. package/src/side-nav-menu/specialized-clinics-nav-links.tsx +42 -0
  849. package/src/specialized-clinics/dental/dental-queues.component.scss +7 -0
  850. package/src/specialized-clinics/dental/dental-queues.component.tsx +36 -0
  851. package/src/specialized-clinics/dental/queues/consultation/dental-consultation.tsx +15 -0
  852. package/src/specialized-clinics/dental/queues/triage/dental-triage.tsx +15 -0
  853. package/src/specialized-clinics/diagnostic-and-imaging/diagnostic-and-imaging.component.scss +7 -0
  854. package/src/specialized-clinics/diagnostic-and-imaging/diagnostic-and-imaging.component.tsx +36 -0
  855. package/src/specialized-clinics/diagnostic-and-imaging/queues/consultation/diagnosis-and-imaging-consultation.tsx +15 -0
  856. package/src/specialized-clinics/diagnostic-and-imaging/queues/triage/diagnosis-and-imaging-triage.tsx +15 -0
  857. package/src/specialized-clinics/oncology/oncology-queues.component.scss +7 -0
  858. package/src/specialized-clinics/oncology/oncology-queues.component.tsx +36 -0
  859. package/src/specialized-clinics/oncology/queues/consultation/oncology-consultation.tsx +15 -0
  860. package/src/specialized-clinics/oncology/queues/triage/oncology-triage.tsx +15 -0
  861. package/src/specialized-clinics/ophthalmology/ophthalmology-queues.component.scss +7 -0
  862. package/src/specialized-clinics/ophthalmology/ophthalmology-queues.component.tsx +36 -0
  863. package/src/specialized-clinics/ophthalmology/queues/consultation/ophthalmology-consultation.tsx +15 -0
  864. package/src/specialized-clinics/ophthalmology/queues/triage/ophthalmology-triage.tsx +15 -0
  865. package/src/specialized-clinics/psychiatry/psychiatry-queues.component.scss +7 -0
  866. package/src/specialized-clinics/psychiatry/psychiatry-queues.component.tsx +36 -0
  867. package/src/specialized-clinics/psychiatry/queues/consultation/psychiatry-consultation.tsx +15 -0
  868. package/src/specialized-clinics/psychiatry/queues/triage/psychiatry-triage.tsx +15 -0
  869. package/src/specialized-clinics/renal/queues/consultation/dialysis-consultation.tsx +15 -0
  870. package/src/specialized-clinics/renal/queues/triage/renal-triage.tsx +15 -0
  871. package/src/specialized-clinics/renal/renal-queues.component.scss +7 -0
  872. package/src/specialized-clinics/renal/renal-queues.component.tsx +36 -0
  873. package/src/specialized-clinics/specialized-clinics-root.tsx +25 -0
  874. package/src/telemedicine/telemedicine-patient-chart.component.test.tsx +123 -0
  875. package/src/telemedicine/telemedicine-patient-chart.component.tsx +131 -0
  876. package/src/telemedicine/telemedicine.component.test.tsx +113 -0
  877. package/src/telemedicine/telemedicine.component.tsx +310 -0
  878. package/src/telemedicine/telemedicine.resource.test.ts +171 -0
  879. package/src/telemedicine/telemedicine.resource.ts +125 -0
  880. package/src/telemedicine/telemedicine.scss +91 -0
  881. package/src/triage/triage.component.scss +6 -0
  882. package/src/triage/triage.component.tsx +4 -0
  883. package/src/types/types.ts +56 -1
  884. package/tools/fetch-shr-code-systems.mjs +135 -0
  885. package/tools/strip-openmrs-declaration-maps.mjs +44 -0
  886. package/tools/update-openmrs-deps.mjs +36 -5
  887. package/translations/en.json +135 -0
  888. package/tsconfig.json +7 -4
  889. package/webpack.config.js +74 -1
  890. package/dist/104.js +0 -2
  891. package/dist/104.js.map +0 -1
  892. package/dist/15.js +0 -1
  893. package/dist/15.js.map +0 -1
  894. package/dist/184.js +0 -2
  895. package/dist/184.js.map +0 -1
  896. package/dist/246.js +0 -2
  897. package/dist/246.js.map +0 -1
  898. package/dist/255.js +0 -1
  899. package/dist/255.js.map +0 -1
  900. package/dist/28.js +0 -1
  901. package/dist/28.js.map +0 -1
  902. package/dist/300.js +0 -1
  903. package/dist/327.js +0 -1
  904. package/dist/327.js.map +0 -1
  905. package/dist/339.js +0 -1
  906. package/dist/339.js.map +0 -1
  907. package/dist/353.js +0 -1
  908. package/dist/353.js.map +0 -1
  909. package/dist/420.js +0 -1
  910. package/dist/420.js.map +0 -1
  911. package/dist/540.js +0 -2
  912. package/dist/540.js.map +0 -1
  913. package/dist/55.js +0 -1
  914. package/dist/619.js +0 -1
  915. package/dist/619.js.map +0 -1
  916. package/dist/65.js +0 -1
  917. package/dist/65.js.map +0 -1
  918. package/dist/709.js +0 -1
  919. package/dist/709.js.map +0 -1
  920. package/dist/710.js +0 -2
  921. package/dist/710.js.LICENSE.txt +0 -14
  922. package/dist/710.js.map +0 -1
  923. package/dist/729.js +0 -1
  924. package/dist/729.js.map +0 -1
  925. package/dist/752.js +0 -1
  926. package/dist/752.js.map +0 -1
  927. package/dist/833.js +0 -1
  928. package/dist/833.js.map +0 -1
  929. package/dist/93.js +0 -1
  930. package/dist/93.js.map +0 -1
  931. package/dist/99.js +0 -1
  932. /package/dist/{104.js.LICENSE.txt → 2272.js.LICENSE.txt} +0 -0
  933. /package/dist/{184.js.LICENSE.txt → 3184.js.LICENSE.txt} +0 -0
  934. /package/dist/{540.js.LICENSE.txt → 6540.js.LICENSE.txt} +0 -0
  935. /package/src/{pharmacy-dashboard.meta.ts → dashboard-meta/pharmacy-dashboard.meta.ts} +0 -0
  936. /package/src/{queue-dashboard.meta.ts → dashboard-meta/queue-dashboard.meta.ts} +0 -0
  937. /package/src/{service-queues/service-queue/stats → shared/ui}/stat-card/stat-card.component.scss +0 -0
@@ -0,0 +1,2458 @@
1
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
2
+ import {
3
+ Button,
4
+ ButtonSet,
5
+ Checkbox,
6
+ ComboBox,
7
+ DatePicker,
8
+ DatePickerInput,
9
+ Dropdown,
10
+ Form,
11
+ InlineLoading,
12
+ InlineNotification,
13
+ RadioButton,
14
+ RadioButtonGroup,
15
+ Tag,
16
+ TextArea,
17
+ TextInput,
18
+ } from '@carbon/react';
19
+ import {
20
+ showSnackbar,
21
+ useConfig,
22
+ useSession,
23
+ Workspace2,
24
+ type Workspace2DefinitionProps,
25
+ } from '@openmrs/esm-framework';
26
+ import { useTranslation } from 'react-i18next';
27
+ import dayjs from 'dayjs';
28
+ import {
29
+ cancelPreauth,
30
+ createPreauth,
31
+ extractHieErrorMessage,
32
+ fetchShaInterventionByCode,
33
+ findExistingPreauthForCrAndShaCode,
34
+ getServiceType,
35
+ pollPreauthUntilSubmitted,
36
+ preauthAttachmentFieldName,
37
+ type ExistingPreauthMatch,
38
+ type PreauthFormPayload,
39
+ } from '../../../../claims/claims.resource';
40
+ import { resolvePreVisitConsentAuthorization, sendClaimsOTP } from '../../../../registry/hie.resource';
41
+ import type { PatientContactResult } from '../../../../registry/hie.types';
42
+ import {
43
+ createElectivePreauth,
44
+ extractElectiveAuthorizationToken,
45
+ fetchElectivePatientContacts,
46
+ resolveOrCreateElectivePreVisitAuthorization,
47
+ sendElectivePreauthOtp,
48
+ } from './elective/elective-authorize.resource';
49
+ import { addClaimDiagnosis, fetchPatientDiagnosesForBilling, preferredDiagnosisForPreauth } from '../../../billing-claims.resource';
50
+ import { ensureInterventionOnVisit } from '../../../../claims/interventions.resource';
51
+ import type { ConfigObject } from '../../../../config-schema';
52
+ import { type AmrsVisitDiagnosis } from '../../../types';
53
+ import { type PatientFacilityBillDetails } from '../types';
54
+ import PreauthAttachments, { type PreauthAttachmentRow } from './preauth-attachments.component';
55
+ import {
56
+ billingDateToVisitDate,
57
+ dateToServiceIso,
58
+ fetchTodaysTriageVitalsConcat,
59
+ mergeSpecialtyFlags,
60
+ preauthFormLabel,
61
+ readSpecialtyFlags,
62
+ resolveAndLoadRaisePrefill,
63
+ resolvePatientUuidFromCr,
64
+ resolveUnitPriceFromPatientBills,
65
+ searchDiagnosisConcepts,
66
+ searchHealthWorkerRegistry,
67
+ searchOpenMrsProviders,
68
+ storePreauthCode,
69
+ usePreauthBillableServices,
70
+ type DiagnosisConceptHit,
71
+ type HwrSearchResult,
72
+ type OpenMrsProviderHit,
73
+ type PreauthFormFieldKey,
74
+ type PreauthInterventionProps,
75
+ } from './preauth.resource';
76
+ import styles from './preauth.workspace.scss';
77
+
78
+ export type { PreauthInterventionProps };
79
+
80
+ type ServicePrice = {
81
+ uuid?: string;
82
+ name?: string;
83
+ price?: number;
84
+ paymentMode?: { uuid?: string; name?: string };
85
+ };
86
+
87
+ type BillableServiceOption = {
88
+ uuid: string;
89
+ name: string;
90
+ servicePrices?: ServicePrice[];
91
+ };
92
+
93
+ function unitPriceFromBillableService(
94
+ item: BillableServiceOption | null | undefined,
95
+ shaPaymentModeUuid: string,
96
+ ): string {
97
+ const prices = item?.servicePrices ?? [];
98
+ if (!prices.length) return '';
99
+ const sha = prices.find((sp) => sp.paymentMode?.uuid === shaPaymentModeUuid);
100
+ const pick = sha ?? prices[0];
101
+ if (pick?.price == null || Number.isNaN(Number(pick.price))) return '';
102
+ return String(pick.price);
103
+ }
104
+
105
+ /** ComboBox row: visit diagnosis (ETL) or concept-dictionary hit. */
106
+ type DiagnosisPick =
107
+ | { kind: 'visit'; key: string; dx: AmrsVisitDiagnosis }
108
+ | { kind: 'concept'; key: string; hit: DiagnosisConceptHit };
109
+
110
+ const visitDxPick = (dx: AmrsVisitDiagnosis): DiagnosisPick => ({
111
+ kind: 'visit',
112
+ key: `visit-${dx.encounter_id}-${dx.icd11_code}-${dx.diagnosis_coded ?? dx.value_coded ?? ''}`,
113
+ dx,
114
+ });
115
+
116
+ const conceptDxPick = (hit: DiagnosisConceptHit): DiagnosisPick => ({
117
+ kind: 'concept',
118
+ key: `concept-${hit.uuid}-${hit.icd11Code}`,
119
+ hit,
120
+ });
121
+
122
+ const diagnosisPickLabel = (item: DiagnosisPick | null) => {
123
+ if (!item) return '';
124
+ if (item.kind === 'visit') {
125
+ const d = item.dx;
126
+ const rank =
127
+ d.dx_rank != null && Number.isFinite(Number(d.dx_rank)) ? ` · Rank ${Number(d.dx_rank)}` : '';
128
+ return `${d.icd11_code ?? '—'} · ${d.concept_source_name || d.encounter_type || 'Visit diagnosis'}${rank}`;
129
+ }
130
+ return `${item.hit.icd11Code} · ${item.hit.display}`;
131
+ };
132
+
133
+ const diagnosisPickCode = (item: DiagnosisPick | null) => {
134
+ if (!item) return '';
135
+ return item.kind === 'visit' ? item.dx.icd11_code ?? '' : item.hit.icd11Code;
136
+ };
137
+
138
+ const DEFAULT_DOCTOR_ID_TYPE = 'National ID' as const;
139
+
140
+ type FormFieldLoadStatus = 'idle' | 'loading' | 'from_form' | 'missing';
141
+
142
+ const FORM_MISSING_HINT =
143
+ 'Missing on the Pre-authorization form. Complete the form on the patient chart, then reopen Raise preauth.';
144
+
145
+ const SURGICAL_FORM_KEYS: PreauthFormFieldKey[] = [
146
+ 'chiefComplaint',
147
+ 'hpi',
148
+ 'physicalExam',
149
+ 'investigations',
150
+ 'anaesthesia',
151
+ 'surgeryDate',
152
+ 'relatedToEmployment',
153
+ 'relatedToAccident',
154
+ 'isCoInsured',
155
+ 'coInsuranceDetails',
156
+ ];
157
+
158
+ const RENAL_FORM_KEYS: PreauthFormFieldKey[] = [
159
+ 'clinicalIndications',
160
+ 'startDate',
161
+ 'sessionsRequired',
162
+ 'frequency',
163
+ 'isCoInsured',
164
+ 'coInsuranceDetails',
165
+ ];
166
+
167
+ interface PreauthWorkspaceProps {
168
+ consentToken: string;
169
+ patientUuid?: string;
170
+ locationUuid: string;
171
+ /** Elective (pre-visit) mode — uses authorize token + expected_service_start_date */
172
+ isElective?: boolean;
173
+ /** Elective hold encounter — Raise loads prefill from this encounter only */
174
+ encounterUuid?: string;
175
+ initialDoctorNationalId?: string;
176
+ initialProviderDisplay?: string;
177
+ initialExpectedServiceStartDate?: string;
178
+ billItem: Partial<PatientFacilityBillDetails> & {
179
+ intervention_code: string;
180
+ patient_uuid?: string;
181
+ cr_no?: string;
182
+ service_type?: string;
183
+ };
184
+ intervention: PreauthInterventionProps;
185
+ onSuccess?: (result: { consentToken: string; preauthCode?: string; status: string }) => void;
186
+ }
187
+
188
+ const ANAESTHESIA = ['GENERAL', 'LOCAL', 'SPINAL', 'SEDATION'];
189
+ const FREQUENCY = ['TWICE_A_WEEK', 'ONCE_A_WEEK', 'ONCE_EVERY_2_WEEKS', 'ONCE_EVERY_3_WEEKS', 'ONCE_A_MONTH'];
190
+ const STAGING = ['STAGE_1', 'STAGE_2', 'STAGE_3', 'STAGE_4'];
191
+ const METASTASES = ['LUNG', 'BRAIN', 'LIVER', 'OTHER'];
192
+ const TREATMENT = ['DAY_WARD', 'RECLINING_CHAIR', 'SIDE_ROOM'];
193
+ const LENS = ['FRAMES_LENSES', 'FRAMED', 'CONTACT'];
194
+ const NEW_OR_REPL = ['NEW', 'REPLACEMENT'];
195
+
196
+ const DOC_TYPE_OPTIONS = [
197
+ 'LAB_TESTS',
198
+ 'LAB_RESULTS',
199
+ 'DISCHARGE_SUMMARY',
200
+ 'INVOICE',
201
+ 'FINAL_BILL',
202
+ 'CLINICAL_DOCUMENTATION',
203
+ 'MEDICAL_REPORT',
204
+ 'IMAGING_RESULT',
205
+ 'RADIOLOGICAL_EXAM',
206
+ 'STAGING_RESULTS',
207
+ 'TREATMENT_PLAN',
208
+ 'THEATRE_LIST',
209
+ 'DIALYSIS_CHART',
210
+ 'PREAUTH_FORM',
211
+ 'OTHER',
212
+ ];
213
+
214
+ const toIsoLocal = (d: Date = new Date()) => dayjs(d).format('YYYY-MM-DDTHH:mm:ssZ');
215
+
216
+ /** HIE regulation bodies (abbreviated): COC = Clinical Officers Council, NCK = Nursing Council of Kenya */
217
+ const REGULATION_BODIES = ['KMPDC', 'COC', 'NCK'] as const;
218
+ type RegulationBody = (typeof REGULATION_BODIES)[number];
219
+
220
+ const normalizeRegulationBody = (value?: string | null): RegulationBody => {
221
+ if (!value) return 'KMPDC';
222
+ const raw = value.trim();
223
+ const exact = REGULATION_BODIES.find((b) => b.toLowerCase() === raw.toLowerCase());
224
+ if (exact) return exact;
225
+ const upper = raw.toUpperCase();
226
+ if (upper.includes('KMPDC') || upper.includes('MEDICAL PRACTITIONER') || upper.includes('DOCTOR')) {
227
+ return 'KMPDC';
228
+ }
229
+ if (
230
+ upper.includes('CLINICAL OFFICER') ||
231
+ upper === 'COC' ||
232
+ upper.includes('CLINICAL OFFICERS COUNCIL')
233
+ ) {
234
+ return 'COC';
235
+ }
236
+ if (upper.includes('NURS') || upper === 'NCK' || upper.includes('NURSING COUNCIL')) {
237
+ return 'NCK';
238
+ }
239
+ return 'KMPDC';
240
+ };
241
+
242
+ type PreauthFormProps = PreauthWorkspaceProps & Pick<Workspace2DefinitionProps, 'closeWorkspace'>;
243
+
244
+ const PreauthForm: React.FC<PreauthFormProps> = ({
245
+ closeWorkspace,
246
+ consentToken: consentTokenProp,
247
+ patientUuid,
248
+ locationUuid,
249
+ isElective = false,
250
+ encounterUuid: encounterUuidProp,
251
+ initialDoctorNationalId,
252
+ initialProviderDisplay,
253
+ initialExpectedServiceStartDate,
254
+ billItem,
255
+ intervention,
256
+ onSuccess,
257
+ }) => {
258
+ const { t } = useTranslation();
259
+ const session = useSession();
260
+ const { shaPaymentModeUuid } = useConfig<ConfigObject>();
261
+ const { lineItems: billableItems, isLoading: loadingBillableItems } = usePreauthBillableServices();
262
+ const [dirty, setDirty] = useState(false);
263
+ const [submitting, setSubmitting] = useState(false);
264
+ const [polling, setPolling] = useState(false);
265
+ const [consentMethod, setConsentMethod] = useState<'biometric' | 'otp'>('otp');
266
+ // Elective must mint a pre-visit authorization token (AUTHORIZED_PENDING_VISIT) —
267
+ // do not treat a prior visit claim token as ready consent.
268
+ const [consentDone, setConsentDone] = useState(isElective ? false : Boolean(consentTokenProp));
269
+ const [otpSent, setOtpSent] = useState(false);
270
+ const [otp, setOtp] = useState('');
271
+ const [sendingOtp, setSendingOtp] = useState(false);
272
+ /** Phase 2 step 6a — contact confirmed with patient before OTP. */
273
+ const [patientContacts, setPatientContacts] = useState<PatientContactResult[]>([]);
274
+ const [selectedContactId, setSelectedContactId] = useState('');
275
+ const [loadingContacts, setLoadingContacts] = useState(false);
276
+ const [activeConsentToken, setActiveConsentToken] = useState(isElective ? '' : consentTokenProp || '');
277
+ const [expectedServiceStartDate, setExpectedServiceStartDate] = useState(() => {
278
+ if (initialExpectedServiceStartDate) {
279
+ const d = dayjs(initialExpectedServiceStartDate);
280
+ if (d.isValid()) return d.format('YYYY-MM-DDTHH:mm:ssZ');
281
+ }
282
+ return toIsoLocal();
283
+ });
284
+ const abortRef = useRef<AbortController | null>(null);
285
+ /** Skip unsaved-changes prompt after a successful submit (state may still say submitting/dirty). */
286
+ const allowCloseWithoutPromptRef = useRef(false);
287
+ /** Encounter diagnoses[] already applied — ETL preferred must not overwrite. */
288
+ const encounterDxAppliedRef = useRef(false);
289
+ /** Provider National ID already applied from encounter / launch props. */
290
+ const providerPrefillAppliedRef = useRef(false);
291
+ const [existingPreauth, setExistingPreauth] = useState<ExistingPreauthMatch | null>(null);
292
+ const [checkingExistingPreauth, setCheckingExistingPreauth] = useState(false);
293
+ const [cancellingExistingPreauth, setCancellingExistingPreauth] = useState(false);
294
+
295
+ // Specialty from launch props + bill item; SHA coverage may enrich after mount
296
+ // (visit/claim payloads often omit requires_*_preauth even for oncology codes).
297
+ const [specialty, setSpecialty] = useState(() =>
298
+ mergeSpecialtyFlags(readSpecialtyFlags(intervention), readSpecialtyFlags(billItem)),
299
+ );
300
+ const specialtyLabel = preauthFormLabel(specialty);
301
+ const [requiredDocs, setRequiredDocs] = useState<string[]>(() => [
302
+ ...new Set(intervention.requiredPreauthDocumentTypes ?? []),
303
+ ]);
304
+ const [optionalDocs, setOptionalDocs] = useState<string[]>(() => {
305
+ const required = new Set(intervention.requiredPreauthDocumentTypes ?? []);
306
+ return [...new Set(intervention.applicableDocumentTypes ?? [])].filter((d) => !required.has(d));
307
+ });
308
+ const interventionForSubmit = useMemo(
309
+ () => ({
310
+ ...intervention,
311
+ ...specialty,
312
+ requiredPreauthDocumentTypes: requiredDocs,
313
+ applicableDocumentTypes: optionalDocs,
314
+ }),
315
+ [intervention, specialty, requiredDocs, optionalDocs],
316
+ );
317
+
318
+ /** Non-specialty “normal” preauth — needs clinical_indications in UI + HIE payload. */
319
+ const isPlainNormalPreauth =
320
+ !specialty.requiresSurgicalPreauth &&
321
+ !specialty.requiresRenalPreauth &&
322
+ !specialty.requiresOpticalPreauth &&
323
+ !specialty.requiresRadiologyPreauth &&
324
+ !specialty.requiresOncologyPreauth;
325
+
326
+ const [serviceStart, setServiceStart] = useState(toIsoLocal());
327
+ const [serviceEnd, setServiceEnd] = useState(toIsoLocal(dayjs().add(30, 'minute').toDate()));
328
+ const [providerEmail, setProviderEmail] = useState(session?.user?.username?.includes('@') ? session.user.username : '');
329
+ const [unitPrice, setUnitPrice] = useState(() =>
330
+ String(billItem.item_price ?? billItem.item_total_price ?? '').trim(),
331
+ );
332
+ const [billPriceLookupDone, setBillPriceLookupDone] = useState(false);
333
+ const [hasBillUnitPrice, setHasBillUnitPrice] = useState(() =>
334
+ Boolean(String(billItem.item_price ?? billItem.item_total_price ?? '').trim()),
335
+ );
336
+ const [selectedBillableService, setSelectedBillableService] = useState<BillableServiceOption | null>(null);
337
+
338
+ // Diagnosis: prefill from ETL encounter-diagnosis; search uses concept dictionary (ICD-11).
339
+ const [visitDiagnoses, setVisitDiagnoses] = useState<AmrsVisitDiagnosis[]>([]);
340
+ const [conceptDxHits, setConceptDxHits] = useState<DiagnosisConceptHit[]>([]);
341
+ const [loadingDx, setLoadingDx] = useState(false);
342
+ const [searchingDx, setSearchingDx] = useState(false);
343
+ const [selectedDx, setSelectedDx] = useState<DiagnosisPick | null>(null);
344
+ const [icdCode, setIcdCode] = useState('');
345
+ const dxSearchTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
346
+
347
+ // Provider — National ID for doctor; HWR for regulation body
348
+ const [providerHits, setProviderHits] = useState<OpenMrsProviderHit[]>([]);
349
+ const [searchingProviders, setSearchingProviders] = useState(false);
350
+ const [selectedProvider, setSelectedProvider] = useState<OpenMrsProviderHit | null>(null);
351
+ const providerSearchTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
352
+ const [searchingHwr, setSearchingHwr] = useState(false);
353
+ const [hwrHit, setHwrHit] = useState<HwrSearchResult | null>(null);
354
+ const [doctorId, setDoctorId] = useState(() => (initialDoctorNationalId ?? '').trim());
355
+ const [regulationBody, setRegulationBody] = useState<RegulationBody>('KMPDC');
356
+
357
+ // Specialty fields — empty until Pre-authorization form obs (or bill unit price) loads.
358
+ const [clinicalIndications, setClinicalIndications] = useState('');
359
+ const [formLoadState, setFormLoadState] = useState<'idle' | 'loading' | 'done'>('idle');
360
+ const [formFound, setFormFound] = useState<Set<PreauthFormFieldKey>>(() => new Set());
361
+ const [formRelevant, setFormRelevant] = useState<Set<PreauthFormFieldKey>>(() => new Set());
362
+ const [chiefComplaint, setChiefComplaint] = useState('');
363
+ const [vitalSigns, setVitalSigns] = useState('');
364
+ const [hpi, setHpi] = useState('');
365
+ const [physicalExam, setPhysicalExam] = useState('');
366
+ const [investigations, setInvestigations] = useState('');
367
+ const [anaesthesia, setAnaesthesia] = useState('');
368
+ const [surgeryDate, setSurgeryDate] = useState('');
369
+ const [sessionsRequired, setSessionsRequired] = useState('');
370
+ const [costPerSession, setCostPerSession] = useState('');
371
+ const [frequency, setFrequency] = useState('');
372
+ const [startDate, setStartDate] = useState('');
373
+ const [isCoInsured, setIsCoInsured] = useState(false);
374
+ const [necessity, setNecessity] = useState('');
375
+ const [lensPrescription, setLensPrescription] = useState('');
376
+ const [lensAmount, setLensAmount] = useState('');
377
+ const [eyeExamAmount, setEyeExamAmount] = useState('');
378
+ const [frameAmount, setFrameAmount] = useState('');
379
+ const [newOrReplacement, setNewOrReplacement] = useState('');
380
+ const [carcinomaStaging, setCarcinomaStaging] = useState('');
381
+ const [comorbidity, setComorbidity] = useState('');
382
+ const [metastases, setMetastases] = useState('');
383
+ const [treatmentSetting, setTreatmentSetting] = useState('');
384
+ const [progressReport, setProgressReport] = useState('');
385
+ const [relatedToEmployment, setRelatedToEmployment] = useState(false);
386
+ const [relatedToAccident, setRelatedToAccident] = useState(false);
387
+ const [coInsuranceDetails, setCoInsuranceDetails] = useState('');
388
+
389
+ const formFieldStatus = (key: PreauthFormFieldKey): FormFieldLoadStatus => {
390
+ if (formLoadState === 'idle') return 'idle';
391
+ if (formLoadState === 'loading') return 'loading';
392
+ if (!formRelevant.has(key)) return 'idle';
393
+ return formFound.has(key) ? 'from_form' : 'missing';
394
+ };
395
+
396
+ const formFieldLocked = (key: PreauthFormFieldKey) => {
397
+ const s = formFieldStatus(key);
398
+ return s === 'from_form' || s === 'missing' || s === 'loading';
399
+ };
400
+
401
+ const formFieldInvalid = (key: PreauthFormFieldKey) => formFieldStatus(key) === 'missing';
402
+
403
+ const patientName = billItem.patient_name ?? '';
404
+ const crNo = billItem.cr_no ?? '';
405
+ const billableService = billItem.billable_service ?? intervention.name ?? intervention.code;
406
+
407
+ const [attachments, setAttachments] = useState<PreauthAttachmentRow[]>(() => {
408
+ const required = requiredDocs.map((document_type) => ({
409
+ id: crypto.randomUUID(),
410
+ document_type,
411
+ document_title: document_type.replace(/_/g, ' '),
412
+ required: true,
413
+ }));
414
+ if (required.length === 0) {
415
+ return [
416
+ {
417
+ id: crypto.randomUUID(),
418
+ document_type: 'LAB_TESTS',
419
+ document_title: 'Lab Results',
420
+ required: false,
421
+ },
422
+ ];
423
+ }
424
+ return required;
425
+ });
426
+
427
+ useEffect(() => {
428
+ // Normal Raise needs the claim visit consent token. Elective may open without one
429
+ // and resolve a pre-visit token via GET /claim-authorizations (not /claims-authorize).
430
+ if (!isElective && !consentTokenProp) {
431
+ showSnackbar({
432
+ kind: 'error',
433
+ title: t('missingConsentToken', 'Missing claim token'),
434
+ subtitle: t(
435
+ 'missingConsentTokenDetail',
436
+ 'A preexisting visit claim token is required to raise preauth.',
437
+ ),
438
+ });
439
+ void closeWorkspace();
440
+ }
441
+ }, [consentTokenProp, isElective, closeWorkspace, t]);
442
+
443
+ // Phase 2 step 6a — GET contacts so OTP can target beneficiary_contact_id.
444
+ useEffect(() => {
445
+ if (!isElective || consentMethod !== 'otp') return;
446
+ const patientId = crNo.trim();
447
+ if (!patientId || !locationUuid) {
448
+ setPatientContacts([]);
449
+ setSelectedContactId('');
450
+ return;
451
+ }
452
+ let cancelled = false;
453
+ setLoadingContacts(true);
454
+ (async () => {
455
+ try {
456
+ const rows = await fetchElectivePatientContacts(patientId, locationUuid);
457
+ if (cancelled) return;
458
+ setPatientContacts(rows);
459
+ const preferred = rows.find((c) => c.isConfirmed) ?? rows[0];
460
+ setSelectedContactId(preferred?.id != null ? String(preferred.id) : '');
461
+ } catch {
462
+ if (!cancelled) {
463
+ setPatientContacts([]);
464
+ setSelectedContactId('');
465
+ }
466
+ } finally {
467
+ if (!cancelled) setLoadingContacts(false);
468
+ }
469
+ })();
470
+ return () => {
471
+ cancelled = true;
472
+ };
473
+ }, [isElective, consentMethod, crNo, locationUuid]);
474
+
475
+ const consentToken = activeConsentToken;
476
+
477
+ // Detect an existing active preauth for the same CR + SHA intervention code.
478
+ useEffect(() => {
479
+ const patientId = (billItem.cr_no ?? '').trim();
480
+ const code = (intervention.code || billItem.intervention_code || '').trim();
481
+ const patientIdUuid = (patientUuid || billItem.patient_uuid || '').trim();
482
+ if (!locationUuid || !code || (!patientId && !consentTokenProp && !patientIdUuid)) {
483
+ setExistingPreauth(null);
484
+ return;
485
+ }
486
+
487
+ let cancelled = false;
488
+ setCheckingExistingPreauth(true);
489
+ (async () => {
490
+ try {
491
+ const match = await findExistingPreauthForCrAndShaCode({
492
+ beneficiaryCr: patientId,
493
+ interventionCode: code,
494
+ locationUuid,
495
+ consentToken: isElective ? undefined : consentTokenProp,
496
+ patientUuid: patientIdUuid || undefined,
497
+ });
498
+ if (!cancelled) setExistingPreauth(match);
499
+ } catch {
500
+ if (!cancelled) setExistingPreauth(null);
501
+ } finally {
502
+ if (!cancelled) setCheckingExistingPreauth(false);
503
+ }
504
+ })();
505
+
506
+ return () => {
507
+ cancelled = true;
508
+ };
509
+ }, [
510
+ billItem.cr_no,
511
+ billItem.intervention_code,
512
+ billItem.patient_uuid,
513
+ consentTokenProp,
514
+ intervention.code,
515
+ isElective,
516
+ locationUuid,
517
+ patientUuid,
518
+ ]);
519
+
520
+ // Enrich specialty flags + preauth document types from SHA interventions coverage.
521
+ useEffect(() => {
522
+ const patientId = (billItem.cr_no ?? '').trim();
523
+ const code = (intervention.code || billItem.intervention_code || '').trim();
524
+ if (!patientId || !locationUuid || !code) return;
525
+
526
+ let cancelled = false;
527
+ (async () => {
528
+ try {
529
+ const sha = await fetchShaInterventionByCode(patientId, locationUuid, code);
530
+ if (cancelled || !sha) return;
531
+ const fromSha = readSpecialtyFlags(sha);
532
+ setSpecialty((prev) => {
533
+ const next = mergeSpecialtyFlags(prev, fromSha);
534
+ if (
535
+ next.requiresSurgicalPreauth === prev.requiresSurgicalPreauth &&
536
+ next.requiresRenalPreauth === prev.requiresRenalPreauth &&
537
+ next.requiresOncologyPreauth === prev.requiresOncologyPreauth &&
538
+ next.requiresRadiologyPreauth === prev.requiresRadiologyPreauth &&
539
+ next.requiresOpticalPreauth === prev.requiresOpticalPreauth
540
+ ) {
541
+ return prev;
542
+ }
543
+ return next;
544
+ });
545
+
546
+ const shaRequired = [...new Set((sha.requiredPreauthDocumentTypes ?? []).filter(Boolean))];
547
+ const shaApplicable = [...new Set((sha.applicableDocumentTypes ?? []).filter(Boolean))];
548
+ if (shaRequired.length || shaApplicable.length) {
549
+ const nextRequired = shaRequired.length ? shaRequired : requiredDocs;
550
+ const requiredSet = new Set(nextRequired);
551
+ const nextOptional = (shaApplicable.length ? shaApplicable : optionalDocs).filter(
552
+ (d) => !requiredSet.has(d),
553
+ );
554
+ setRequiredDocs(nextRequired);
555
+ setOptionalDocs(nextOptional);
556
+ // Reseed required rows only when the user has not attached files yet.
557
+ setAttachments((prev) => {
558
+ const hasUserFiles = prev.some((a) => Boolean(a.file));
559
+ if (hasUserFiles) return prev;
560
+ if (!nextRequired.length) return prev;
561
+ return nextRequired.map((document_type) => ({
562
+ id: crypto.randomUUID(),
563
+ document_type,
564
+ document_title: document_type.replace(/_/g, ' '),
565
+ required: true,
566
+ }));
567
+ });
568
+ }
569
+ } catch {
570
+ // Keep launch-prop flags / docs if coverage lookup fails
571
+ }
572
+ })();
573
+
574
+ return () => {
575
+ cancelled = true;
576
+ };
577
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- seed once from SHA; avoid re-loop on doc state
578
+ }, [billItem.cr_no, billItem.intervention_code, intervention.code, locationUuid]);
579
+
580
+ useEffect(() => () => {
581
+ abortRef.current?.abort();
582
+ if (providerSearchTimer.current) clearTimeout(providerSearchTimer.current);
583
+ if (dxSearchTimer.current) clearTimeout(dxSearchTimer.current);
584
+ }, []);
585
+
586
+ const markDirty = () => setDirty(true);
587
+
588
+ const applyDiagnosisPick = (pick: DiagnosisPick | null, opts?: { fromUser?: boolean }) => {
589
+ // Prefill from visit load must not trip "unsaved changes" on close.
590
+ if (opts?.fromUser !== false) {
591
+ markDirty();
592
+ }
593
+ setSelectedDx(pick);
594
+ const code = diagnosisPickCode(pick);
595
+ if (code) {
596
+ setIcdCode(code);
597
+ }
598
+ if (pick?.kind === 'visit') {
599
+ const dx = pick.dx;
600
+ if (dx.practioner_nat_id && !providerPrefillAppliedRef.current) {
601
+ setDoctorId(dx.practioner_nat_id);
602
+ }
603
+ if (dx.practitioner_body) {
604
+ setRegulationBody(normalizeRegulationBody(dx.practitioner_body));
605
+ }
606
+ }
607
+ };
608
+
609
+ // Prefill from visit + maternity + encounter diagnoses (ETL) — fallback when no encounter.diagnoses[].
610
+ useEffect(() => {
611
+ const uuid = patientUuid || billItem.patient_uuid;
612
+ if (!uuid || !locationUuid) return;
613
+ let cancelled = false;
614
+ const run = async () => {
615
+ setLoadingDx(true);
616
+ try {
617
+ const visitDate = billingDateToVisitDate(billItem.bill_date);
618
+ const billingDate = visitDate;
619
+ const results = await fetchPatientDiagnosesForBilling({
620
+ visitDate,
621
+ billingDate,
622
+ patientUuid: uuid,
623
+ locationUuid,
624
+ });
625
+ if (!cancelled) {
626
+ setVisitDiagnoses(results ?? []);
627
+ if (!encounterDxAppliedRef.current) {
628
+ const preferred = preferredDiagnosisForPreauth(results ?? []);
629
+ if (preferred) {
630
+ applyDiagnosisPick(visitDxPick(preferred), { fromUser: false });
631
+ }
632
+ }
633
+ }
634
+ } catch {
635
+ if (!cancelled) {
636
+ showSnackbar({
637
+ kind: 'warning',
638
+ title: 'Could not load diagnoses',
639
+ subtitle: 'Search the concept dictionary, or retry after the visit has ICD-11 coded diagnoses.',
640
+ });
641
+ }
642
+ } finally {
643
+ if (!cancelled) setLoadingDx(false);
644
+ }
645
+ };
646
+ run();
647
+ return () => {
648
+ cancelled = true;
649
+ };
650
+ // eslint-disable-next-line react-hooks/exhaustive-deps
651
+ }, [patientUuid, billItem.patient_uuid, billItem.bill_date, locationUuid]);
652
+
653
+ const diagnosisItems = useMemo((): DiagnosisPick[] => {
654
+ const base =
655
+ conceptDxHits.length > 0
656
+ ? conceptDxHits.map(conceptDxPick)
657
+ : visitDiagnoses.filter((d) => d.icd11_code).map(visitDxPick);
658
+ if (!selectedDx) return base;
659
+ if (!base.some((i) => i.key === selectedDx.key)) {
660
+ return [selectedDx, ...base];
661
+ }
662
+ return base.map((i) => (i.key === selectedDx.key ? selectedDx : i));
663
+ }, [conceptDxHits, visitDiagnoses, selectedDx]);
664
+
665
+ const handleDiagnosisInputChange = (inputValue: string) => {
666
+ const selectedLabel = diagnosisPickLabel(selectedDx);
667
+ if (inputValue === selectedLabel) {
668
+ return;
669
+ }
670
+ if (selectedDx) {
671
+ setSelectedDx(null);
672
+ }
673
+ if (dxSearchTimer.current) {
674
+ clearTimeout(dxSearchTimer.current);
675
+ }
676
+ const q = (inputValue ?? '').trim();
677
+ if (q.length < 2) {
678
+ setConceptDxHits([]);
679
+ setSearchingDx(false);
680
+ return;
681
+ }
682
+ dxSearchTimer.current = setTimeout(async () => {
683
+ setSearchingDx(true);
684
+ try {
685
+ const hits = await searchDiagnosisConcepts(q);
686
+ setConceptDxHits(hits);
687
+ } catch {
688
+ setConceptDxHits([]);
689
+ } finally {
690
+ setSearchingDx(false);
691
+ }
692
+ }, 300);
693
+ };
694
+ // Resolve unit_price from patient facility bill lines (match intervention + service name).
695
+ // Elective holds often have no bill line yet — fall back to billable-service catalog picker.
696
+ useEffect(() => {
697
+ const uuid = patientUuid || billItem.patient_uuid;
698
+ const code = (intervention.code || billItem.intervention_code || '').trim();
699
+ if (!uuid || !locationUuid || !code) {
700
+ setBillPriceLookupDone(true);
701
+ return;
702
+ }
703
+
704
+ let cancelled = false;
705
+ setBillPriceLookupDone(false);
706
+ (async () => {
707
+ try {
708
+ const { unitPrice: fromBills, billLine } = await resolveUnitPriceFromPatientBills({
709
+ patientUuid: uuid,
710
+ locationUuid,
711
+ billingDate: billItem.bill_date,
712
+ interventionCode: code,
713
+ serviceHint: billItem.billable_service || intervention.name || code,
714
+ });
715
+ if (cancelled) return;
716
+ if (fromBills) {
717
+ setUnitPrice(fromBills);
718
+ setHasBillUnitPrice(true);
719
+ setSelectedBillableService(null);
720
+ setCostPerSession((prev) => (prev.trim() ? prev : fromBills));
721
+ // Prefer matched billable_service label when launch used intervention name only
722
+ if (billLine?.billable_service && !(billItem.billable_service || '').trim()) {
723
+ // billItem is a prop — display uses billableService derived from it; unit price is enough
724
+ }
725
+ } else {
726
+ setHasBillUnitPrice(false);
727
+ }
728
+ } finally {
729
+ if (!cancelled) setBillPriceLookupDone(true);
730
+ }
731
+ })();
732
+
733
+ return () => {
734
+ cancelled = true;
735
+ };
736
+ }, [
737
+ patientUuid,
738
+ billItem.patient_uuid,
739
+ billItem.bill_date,
740
+ billItem.intervention_code,
741
+ billItem.billable_service,
742
+ intervention.code,
743
+ intervention.name,
744
+ locationUuid,
745
+ specialty.requiresRenalPreauth,
746
+ ]);
747
+
748
+ // Elective preauth usually has no patient bill yet — always offer the catalog picker.
749
+ const needsBillableServicePicker = isElective;
750
+
751
+ // Unified Raise prefill: Preauth/Clinical (or explicit encounterUuid) → formValues + diagnoses + provider.
752
+ useEffect(() => {
753
+ const specialtyNeedsForm =
754
+ specialty.requiresSurgicalPreauth ||
755
+ specialty.requiresRenalPreauth ||
756
+ specialty.requiresRadiologyPreauth ||
757
+ specialty.requiresOpticalPreauth;
758
+ const needsForm = specialtyNeedsForm || isPlainNormalPreauth;
759
+ const uuid = patientUuid || billItem.patient_uuid;
760
+ if (!needsForm || !uuid) {
761
+ setFormLoadState('idle');
762
+ setFormFound(new Set());
763
+ setFormRelevant(new Set());
764
+ return;
765
+ }
766
+
767
+ let cancelled = false;
768
+
769
+ (async () => {
770
+ let uuid = (patientUuid || billItem.patient_uuid || '').trim();
771
+ if (!uuid) {
772
+ const cr = (billItem.cr_no || '').trim();
773
+ if (cr) {
774
+ uuid = await resolvePatientUuidFromCr(cr);
775
+ }
776
+ }
777
+ if (!uuid) {
778
+ if (!cancelled) {
779
+ setFormLoadState('idle');
780
+ setFormFound(new Set());
781
+ setFormRelevant(new Set());
782
+ }
783
+ return;
784
+ }
785
+
786
+ setFormLoadState('loading');
787
+ let model: Awaited<ReturnType<typeof resolveAndLoadRaisePrefill>> = null;
788
+ try {
789
+ model = await resolveAndLoadRaisePrefill({
790
+ patientUuid: uuid,
791
+ encounterUuid: encounterUuidProp,
792
+ specialtyNeedsForm,
793
+ });
794
+ } catch {
795
+ if (!cancelled) {
796
+ setFormLoadState(needsForm ? 'done' : 'idle');
797
+ setFormFound(new Set());
798
+ setFormRelevant(new Set());
799
+ }
800
+ return;
801
+ }
802
+ if (cancelled) return;
803
+
804
+ const values = model?.formValues;
805
+ if (values) {
806
+ if (values.found.has('clinicalIndications') || values.clinicalIndications.trim()) {
807
+ setClinicalIndications(values.clinicalIndications);
808
+ }
809
+ if (values.found.has('startDate')) setStartDate(values.startDate);
810
+ if (values.found.has('sessionsRequired')) setSessionsRequired(values.sessionsRequired);
811
+ if (values.found.has('frequency')) setFrequency(values.frequency);
812
+ if (values.found.has('chiefComplaint')) setChiefComplaint(values.chiefComplaint);
813
+ if (values.found.has('hpi')) setHpi(values.hpi);
814
+ if (values.found.has('physicalExam')) setPhysicalExam(values.physicalExam);
815
+ if (values.found.has('investigations')) setInvestigations(values.investigations);
816
+ if (values.found.has('anaesthesia')) setAnaesthesia(values.anaesthesia);
817
+ if (values.found.has('surgeryDate')) setSurgeryDate(values.surgeryDate);
818
+ if (values.found.has('relatedToEmployment') && values.relatedToEmployment !== null) {
819
+ setRelatedToEmployment(values.relatedToEmployment);
820
+ }
821
+ if (values.found.has('relatedToAccident') && values.relatedToAccident !== null) {
822
+ setRelatedToAccident(values.relatedToAccident);
823
+ }
824
+ if (values.found.has('isCoInsured') && values.isCoInsured !== null) {
825
+ setIsCoInsured(values.isCoInsured);
826
+ }
827
+ if (values.found.has('coInsuranceDetails')) {
828
+ setCoInsuranceDetails(values.coInsuranceDetails);
829
+ }
830
+ if (isElective && values.expectedServiceStartDate) {
831
+ const d = dayjs(values.expectedServiceStartDate);
832
+ if (d.isValid()) setExpectedServiceStartDate(d.format('YYYY-MM-DDTHH:mm:ssZ'));
833
+ }
834
+ }
835
+
836
+ const preferredDx = model?.diagnoses?.[0];
837
+ if (preferredDx?.conceptUuid) {
838
+ encounterDxAppliedRef.current = true;
839
+ const hit: DiagnosisConceptHit = {
840
+ uuid: preferredDx.conceptUuid,
841
+ display: preferredDx.display || preferredDx.icd11Code || preferredDx.conceptUuid,
842
+ icd11Code: preferredDx.icd11Code || '',
843
+ };
844
+ applyDiagnosisPick(conceptDxPick(hit), { fromUser: false });
845
+ setConceptDxHits((prev) => {
846
+ if (prev.some((p) => p.uuid === hit.uuid)) return prev;
847
+ return [hit, ...prev];
848
+ });
849
+ }
850
+
851
+ const natId =
852
+ (model?.providerNationalId || initialDoctorNationalId || '').trim() ||
853
+ (initialDoctorNationalId ?? '').trim();
854
+ if (natId && !providerPrefillAppliedRef.current) {
855
+ providerPrefillAppliedRef.current = true;
856
+ setDoctorId(natId);
857
+ if (model?.providerDisplay || initialProviderDisplay) {
858
+ setSelectedProvider({
859
+ uuid: model?.providerUuid || 'prefill',
860
+ display: model?.providerDisplay || initialProviderDisplay || natId,
861
+ nationalId: natId,
862
+ });
863
+ }
864
+ try {
865
+ const results = await searchHealthWorkerRegistry({
866
+ identifierType: DEFAULT_DOCTOR_ID_TYPE,
867
+ identifierValue: natId,
868
+ locationUuid,
869
+ });
870
+ if (!cancelled && results[0]) {
871
+ setHwrHit(results[0]);
872
+ setRegulationBody(normalizeRegulationBody(results[0].membership?.licensing_body));
873
+ if (results[0].contacts?.email) {
874
+ setProviderEmail(results[0].contacts.email);
875
+ }
876
+ }
877
+ } catch {
878
+ // soft-fail HWR
879
+ }
880
+ }
881
+
882
+ const relevant = new Set<PreauthFormFieldKey>();
883
+ if (
884
+ specialty.requiresRadiologyPreauth ||
885
+ specialty.requiresOpticalPreauth ||
886
+ specialty.requiresRenalPreauth
887
+ ) {
888
+ // Specialty: clinical indications must come from the Pre-authorization form (locked).
889
+ relevant.add('clinicalIndications');
890
+ }
891
+ // Plain normal: prefill when present but keep the field editable (not formRelevant).
892
+ if (specialty.requiresRenalPreauth) {
893
+ RENAL_FORM_KEYS.forEach((k) => relevant.add(k));
894
+ }
895
+ if (specialty.requiresSurgicalPreauth) {
896
+ SURGICAL_FORM_KEYS.forEach((k) => relevant.add(k));
897
+ }
898
+ if (values?.isCoInsured !== true) {
899
+ relevant.delete('coInsuranceDetails');
900
+ }
901
+
902
+ setFormRelevant(relevant);
903
+ setFormFound(
904
+ values ? new Set([...relevant].filter((k) => values.found.has(k))) : new Set(),
905
+ );
906
+ setFormLoadState(needsForm || model ? 'done' : 'idle');
907
+ })();
908
+
909
+ return () => {
910
+ cancelled = true;
911
+ };
912
+ // eslint-disable-next-line react-hooks/exhaustive-deps
913
+ }, [
914
+ patientUuid,
915
+ billItem.patient_uuid,
916
+ isPlainNormalPreauth,
917
+ specialty.requiresSurgicalPreauth,
918
+ specialty.requiresRenalPreauth,
919
+ specialty.requiresRadiologyPreauth,
920
+ specialty.requiresOpticalPreauth,
921
+ locationUuid,
922
+ ]);
923
+
924
+ // Surgical vital_signs — concatenate today's OPD Triage vitals (editable after prefill).
925
+ useEffect(() => {
926
+ if (!specialty.requiresSurgicalPreauth) return;
927
+ const uuid = patientUuid || billItem.patient_uuid;
928
+ if (!uuid) return;
929
+ let cancelled = false;
930
+ (async () => {
931
+ const concat = await fetchTodaysTriageVitalsConcat(uuid, locationUuid);
932
+ if (!cancelled && concat) {
933
+ setVitalSigns((prev) => (prev.trim() ? prev : concat));
934
+ }
935
+ })();
936
+ return () => {
937
+ cancelled = true;
938
+ };
939
+ }, [patientUuid, billItem.patient_uuid, locationUuid, specialty.requiresSurgicalPreauth]);
940
+
941
+ const clinicalIndicationsFieldProps = {
942
+ labelText: 'Clinical indications',
943
+ value: formFieldStatus('clinicalIndications') === 'loading' ? '' : clinicalIndications,
944
+ readOnly: formFieldLocked('clinicalIndications'),
945
+ placeholder: formFieldStatus('clinicalIndications') === 'loading' ? 'Loading clinical notes…' : undefined,
946
+ invalid: formFieldInvalid('clinicalIndications'),
947
+ invalidText: formFieldInvalid('clinicalIndications') ? FORM_MISSING_HINT : undefined,
948
+ onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => {
949
+ if (formFieldLocked('clinicalIndications')) return;
950
+ markDirty();
951
+ setClinicalIndications(e.target.value);
952
+ },
953
+ };
954
+
955
+ const providerItemLabel = (item: OpenMrsProviderHit | null) =>
956
+ item ? (item.nationalId ? `${item.display} · ${item.nationalId}` : item.display) : '';
957
+
958
+ const applyProviderSelection = (hit: OpenMrsProviderHit | null) => {
959
+ setSelectedProvider(hit);
960
+ if (!hit) return;
961
+ markDirty();
962
+ if (hit.nationalId) {
963
+ setDoctorId(hit.nationalId);
964
+ void handleSearchHwr(hit.nationalId);
965
+ } else {
966
+ setDoctorId('');
967
+ setHwrHit(null);
968
+ showSnackbar({
969
+ kind: 'warning',
970
+ title: 'No National ID on provider',
971
+ subtitle: 'Enter the doctor National ID, then Search HWR for the regulation body.',
972
+ });
973
+ }
974
+ };
975
+
976
+ const handleSearchHwr = async (idOverride?: string) => {
977
+ const idValue = (idOverride ?? doctorId).trim();
978
+ if (!idValue) {
979
+ showSnackbar({
980
+ kind: 'error',
981
+ title: 'Enter National ID',
982
+ subtitle: 'Doctor National ID is required to look up the regulation body in HWR.',
983
+ });
984
+ return;
985
+ }
986
+ setSearchingHwr(true);
987
+ try {
988
+ const results = await searchHealthWorkerRegistry({
989
+ identifierType: DEFAULT_DOCTOR_ID_TYPE,
990
+ identifierValue: idValue,
991
+ locationUuid,
992
+ });
993
+ const hit = results[0];
994
+ if (!hit) {
995
+ setHwrHit(null);
996
+ showSnackbar({ kind: 'warning', title: 'No health worker found' });
997
+ return;
998
+ }
999
+ setHwrHit(hit);
1000
+ // Keep doctor ID as National ID; only take regulation body (and email) from HWR
1001
+ const body = normalizeRegulationBody(hit.membership?.licensing_body);
1002
+ setRegulationBody(body);
1003
+ if (hit.contacts?.email) {
1004
+ setProviderEmail(hit.contacts.email);
1005
+ }
1006
+ markDirty();
1007
+ showSnackbar({
1008
+ kind: 'success',
1009
+ title: 'Regulation body from HWR',
1010
+ subtitle: `${hit.membership?.full_name || 'Match'} · ${body}`,
1011
+ });
1012
+ } catch (e: any) {
1013
+ showSnackbar({ kind: 'error', title: 'HWR search failed', subtitle: String(e?.message ?? e) });
1014
+ } finally {
1015
+ setSearchingHwr(false);
1016
+ }
1017
+ };
1018
+
1019
+ const handleProviderInputChange = (inputValue: string) => {
1020
+ const selectedLabel = providerItemLabel(selectedProvider);
1021
+ if (inputValue === selectedLabel) {
1022
+ return;
1023
+ }
1024
+ if (selectedProvider) {
1025
+ setSelectedProvider(null);
1026
+ }
1027
+ if (providerSearchTimer.current) {
1028
+ clearTimeout(providerSearchTimer.current);
1029
+ }
1030
+ if (!inputValue || inputValue.trim().length < 2) {
1031
+ setProviderHits([]);
1032
+ setSearchingProviders(false);
1033
+ return;
1034
+ }
1035
+ providerSearchTimer.current = setTimeout(async () => {
1036
+ setSearchingProviders(true);
1037
+ try {
1038
+ const hits = await searchOpenMrsProviders(inputValue);
1039
+ setProviderHits(hits);
1040
+ } catch (e: any) {
1041
+ setProviderHits([]);
1042
+ showSnackbar({ kind: 'error', title: 'Provider search failed', subtitle: String(e?.message ?? e) });
1043
+ } finally {
1044
+ setSearchingProviders(false);
1045
+ }
1046
+ }, 300);
1047
+ };
1048
+
1049
+ const requiredAttachmentsReady = useMemo(() => {
1050
+ return attachments.filter((a) => a.required).every((a) => Boolean(a.file));
1051
+ }, [attachments]);
1052
+
1053
+ const handleSendOtp = async () => {
1054
+ if (!crNo) {
1055
+ showSnackbar({ kind: 'error', title: 'Missing CR number', subtitle: 'Cannot send OTP without patient CR id.' });
1056
+ return;
1057
+ }
1058
+ if (isElective && !selectedContactId && patientContacts.length > 0) {
1059
+ showSnackbar({
1060
+ kind: 'error',
1061
+ title: 'Select a contact',
1062
+ subtitle: 'Confirm which patient contact should receive the OTP.',
1063
+ });
1064
+ return;
1065
+ }
1066
+ setSendingOtp(true);
1067
+ try {
1068
+ if (isElective) {
1069
+ // Phase 2 step 7a — elective-only OTP helper (not normal sendClaimsOTP).
1070
+ const response = await sendElectivePreauthOtp({
1071
+ patientId: crNo,
1072
+ locationUuid,
1073
+ interventionCode: intervention.code,
1074
+ beneficiaryContactId: selectedContactId || undefined,
1075
+ });
1076
+ if ((response as any)?.message?.includes('OTP') || response) {
1077
+ setOtpSent(true);
1078
+ setConsentDone(false);
1079
+ showSnackbar({ kind: 'success', title: 'OTP sent' });
1080
+ }
1081
+ } else {
1082
+ // Do not cancelAllPendingAuthorizations — that can wipe in-flight consent for this CR.
1083
+ const response = await sendClaimsOTP(crNo, locationUuid, intervention.code);
1084
+ if (response?.message?.includes('OTP') || response) {
1085
+ setOtpSent(true);
1086
+ setConsentDone(false);
1087
+ showSnackbar({ kind: 'success', title: 'OTP sent' });
1088
+ }
1089
+ }
1090
+ } catch (e: any) {
1091
+ showSnackbar({ kind: 'error', title: 'Failed to send OTP', subtitle: String(e?.message ?? e) });
1092
+ } finally {
1093
+ setSendingOtp(false);
1094
+ }
1095
+ };
1096
+
1097
+ const resolveElectiveServiceType = (): string => {
1098
+ const fromBill = String(billItem.service_type ?? '').trim().toUpperCase();
1099
+ if (fromBill === 'OUTPATIENT' || fromBill === 'INPATIENT' || fromBill === 'CAPITATION') {
1100
+ return fromBill;
1101
+ }
1102
+ try {
1103
+ return getServiceType(intervention as any, 'OUTPATIENT') || 'OUTPATIENT';
1104
+ } catch {
1105
+ return 'OUTPATIENT';
1106
+ }
1107
+ };
1108
+
1109
+ const handleVerifyOtp = async () => {
1110
+ if (!otp || otp.length < 4) {
1111
+ showSnackbar({ kind: 'error', title: 'Enter OTP' });
1112
+ return;
1113
+ }
1114
+
1115
+ // Elective: Confirm OTP locally only. HIE authorize runs on Submit so Send OTP /
1116
+ // Confirm never hit /claims-authorize or create a preauth.
1117
+ if (isElective) {
1118
+ setConsentDone(true);
1119
+ showSnackbar({
1120
+ kind: 'success',
1121
+ title: 'OTP confirmed',
1122
+ subtitle: 'Pre-visit authorization will be created when you submit the preauth.',
1123
+ });
1124
+ return;
1125
+ }
1126
+
1127
+ setSendingOtp(true);
1128
+ try {
1129
+ const token = String(activeConsentToken || consentTokenProp || '').trim();
1130
+ if (!token) {
1131
+ throw new Error('A claim consent token is required.');
1132
+ }
1133
+ setActiveConsentToken(token);
1134
+ setConsentDone(true);
1135
+ showSnackbar({
1136
+ kind: 'success',
1137
+ title: 'Consent verified',
1138
+ });
1139
+ } catch (e: any) {
1140
+ showSnackbar({
1141
+ kind: 'error',
1142
+ title: 'Consent token verification failed',
1143
+ subtitle: String(e?.message ?? e),
1144
+ });
1145
+ } finally {
1146
+ setSendingOtp(false);
1147
+ }
1148
+ };
1149
+
1150
+ const handleConfirmBiometric = async () => {
1151
+ setSendingOtp(true);
1152
+ try {
1153
+ if (!isElective) {
1154
+ const token = String(activeConsentToken || consentTokenProp || '').trim();
1155
+ if (!token) {
1156
+ throw new Error('A claim consent token is required.');
1157
+ }
1158
+ setActiveConsentToken(token);
1159
+ setConsentDone(true);
1160
+ showSnackbar({ kind: 'success', title: 'Consent verified' });
1161
+ return;
1162
+ }
1163
+
1164
+ // Elective biometrics: after iframe authorize, resolve AUTHORIZED_PENDING_VISIT only
1165
+ // (do not accept a visit claim token).
1166
+ const auth = await resolvePreVisitConsentAuthorization({
1167
+ locationUuid,
1168
+ beneficiaryCode: crNo,
1169
+ });
1170
+ const token = String(auth?.token ?? '').trim();
1171
+ const status = String(auth?.status ?? '').trim().toUpperCase();
1172
+ if (!token) {
1173
+ throw new Error(
1174
+ 'No pre-visit authorization found. Finish biometric authorize, then confirm here.',
1175
+ );
1176
+ }
1177
+ if (status && status !== 'AUTHORIZED_PENDING_VISIT') {
1178
+ throw new Error(
1179
+ `Expected AUTHORIZED_PENDING_VISIT for elective preauth, got ${status}. Complete pre-visit biometric authorize first.`,
1180
+ );
1181
+ }
1182
+ setActiveConsentToken(token);
1183
+ setConsentDone(true);
1184
+ showSnackbar({
1185
+ kind: 'success',
1186
+ title: 'Pre-visit authorization verified',
1187
+ subtitle: auth?.status ? `Status: ${auth.status}` : undefined,
1188
+ });
1189
+ } catch (e: any) {
1190
+ showSnackbar({
1191
+ kind: 'error',
1192
+ title: 'Consent token verification failed',
1193
+ subtitle: String(e?.message ?? e),
1194
+ });
1195
+ } finally {
1196
+ setSendingOtp(false);
1197
+ }
1198
+ };
1199
+
1200
+ const handleAttachmentsChange = (updater: (prev: PreauthAttachmentRow[]) => PreauthAttachmentRow[]) => {
1201
+ markDirty();
1202
+ setAttachments(updater);
1203
+ };
1204
+
1205
+ const addableDocTypes = useMemo(() => {
1206
+ const attached = new Set(attachments.map((a) => a.document_type));
1207
+ const base = optionalDocs.length > 0 ? optionalDocs : DOC_TYPE_OPTIONS;
1208
+ return [...new Set(base)].filter((d) => !attached.has(d));
1209
+ }, [attachments, optionalDocs]);
1210
+
1211
+ useEffect(
1212
+ () => () => {
1213
+ attachments.forEach((a) => {
1214
+ if (a.previewUrl) URL.revokeObjectURL(a.previewUrl);
1215
+ });
1216
+ },
1217
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1218
+ [],
1219
+ );
1220
+
1221
+ const buildPayload = (): PreauthFormPayload => {
1222
+ // Contiguous indexes: attachments[i] → attachments_i_file_blob
1223
+ const withFiles = attachments.filter((a) => a.file);
1224
+ const files: Record<string, File> = {};
1225
+ const attachmentMeta = withFiles.map((a, index) => {
1226
+ const field = preauthAttachmentFieldName(index);
1227
+ files[field] = a.file!;
1228
+ return {
1229
+ document_title: a.document_title,
1230
+ document_type: a.document_type,
1231
+ file_field_name: field,
1232
+ };
1233
+ });
1234
+
1235
+ // Prefer the text-box value so edits are submitted, not the launch bill line.
1236
+ const billUnitPrice = String(unitPrice ?? billItem.item_price ?? billItem.item_total_price ?? '').trim();
1237
+ const resolvedUnitPrice = billUnitPrice;
1238
+
1239
+ const payload: PreauthFormPayload = {
1240
+ service_start: serviceStart,
1241
+ service_end: serviceEnd,
1242
+ items: [{ unit_price: resolvedUnitPrice || '0' }],
1243
+ diagnoses: [{ consent_token: consentToken, icd_code: icdCode.trim() }],
1244
+ doctors: [
1245
+ {
1246
+ identification_number: doctorId.trim(),
1247
+ identification_type: DEFAULT_DOCTOR_ID_TYPE,
1248
+ regulation_body: normalizeRegulationBody(regulationBody),
1249
+ intervention_code: intervention.code,
1250
+ is_primary: true,
1251
+ },
1252
+ ],
1253
+ attachments: attachmentMeta,
1254
+ provider_notification_email: providerEmail.trim(),
1255
+ locationUuid,
1256
+ files,
1257
+ };
1258
+
1259
+ if (specialty.requiresSurgicalPreauth) {
1260
+ payload.chief_complaint = chiefComplaint.trim();
1261
+ payload.vital_signs = vitalSigns.trim();
1262
+ payload.history_of_present_illness = hpi.trim();
1263
+ payload.physical_examination = physicalExam.trim();
1264
+ payload.investigation_report_details = investigations.trim();
1265
+ payload.type_of_anaesthesia = anaesthesia;
1266
+ payload.surgery_date = surgeryDate;
1267
+ payload.is_condition_related_to_employment = relatedToEmployment;
1268
+ payload.is_condition_related_to_auto_or_other_accident = relatedToAccident;
1269
+ payload.is_co_insured = isCoInsured;
1270
+ if (isCoInsured && coInsuranceDetails.trim()) {
1271
+ payload.co_insurance_details = coInsuranceDetails.trim();
1272
+ }
1273
+ }
1274
+
1275
+ if (specialty.requiresRenalPreauth) {
1276
+ const sessionsNum = Number(sessionsRequired);
1277
+ payload.number_of_sessions_required = Number.isFinite(sessionsNum) ? sessionsNum : sessionsRequired;
1278
+ payload.cost_per_session = String(costPerSession || billUnitPrice || '').trim();
1279
+ payload.frequency_of_sessions = frequency;
1280
+ payload.start_date = startDate;
1281
+ payload.is_co_insured = isCoInsured;
1282
+ if (isCoInsured && coInsuranceDetails.trim()) {
1283
+ payload.co_insurance_details = coInsuranceDetails.trim();
1284
+ }
1285
+ }
1286
+
1287
+ if (specialty.requiresOpticalPreauth) {
1288
+ payload.necessity_of_service = necessity.trim();
1289
+ payload.lens_prescription = lensPrescription;
1290
+ payload.lens_amount = lensAmount;
1291
+ payload.eye_examination_amount = eyeExamAmount;
1292
+ payload.frame_amount = frameAmount;
1293
+ payload.new_or_replacement = newOrReplacement;
1294
+ }
1295
+
1296
+ if (specialty.requiresOncologyPreauth) {
1297
+ payload.carcinoma_staging = carcinomaStaging;
1298
+ payload.comorbidity = comorbidity.trim();
1299
+ // Always arrays — HIE: "Expected a JSON list for metastases and treatment_setting"
1300
+ payload.metastases = [metastases];
1301
+ payload.treatment_setting = [treatmentSetting];
1302
+ {
1303
+ const sessionsNum = Number(sessionsRequired);
1304
+ payload.number_of_sessions_required = Number.isFinite(sessionsNum) ? sessionsNum : sessionsRequired;
1305
+ }
1306
+ payload.cost_per_session = costPerSession;
1307
+ payload.is_co_insured = isCoInsured;
1308
+ payload.start_date = startDate;
1309
+ if (progressReport.trim()) {
1310
+ payload.progress_report = progressReport.trim();
1311
+ }
1312
+ }
1313
+
1314
+ // Renal / optical / imaging / plain normal — always send when captured.
1315
+ if (clinicalIndications.trim()) {
1316
+ payload.clinical_indications = clinicalIndications.trim();
1317
+ }
1318
+
1319
+ if (isElective) {
1320
+ payload.expected_service_start_date = expectedServiceStartDate;
1321
+ }
1322
+
1323
+ return payload;
1324
+ };
1325
+
1326
+ const handleCancelExistingPreauth = async () => {
1327
+ const code = String(intervention.code || billItem.intervention_code || '').trim();
1328
+ const token = String(
1329
+ existingPreauth?.consentToken || activeConsentToken || consentTokenProp || '',
1330
+ ).trim();
1331
+ if (!token || !code || !locationUuid) {
1332
+ showSnackbar({
1333
+ kind: 'error',
1334
+ title: 'Cannot cancel preauth',
1335
+ subtitle: 'Missing consent token or intervention code for this preauth.',
1336
+ });
1337
+ return;
1338
+ }
1339
+ setCancellingExistingPreauth(true);
1340
+ try {
1341
+ await cancelPreauth({
1342
+ consentToken: token,
1343
+ interventionCode: code,
1344
+ locationUuid,
1345
+ });
1346
+ setExistingPreauth(null);
1347
+ showSnackbar({
1348
+ kind: 'success',
1349
+ title: 'Preauth cancelled',
1350
+ subtitle: `${code} was cancelled. You can raise a new preauth.`,
1351
+ });
1352
+ } catch (e: any) {
1353
+ showSnackbar({
1354
+ kind: 'error',
1355
+ title: 'Cancel failed',
1356
+ subtitle: extractHieErrorMessage(e, 'Failed to cancel preauth'),
1357
+ });
1358
+ } finally {
1359
+ setCancellingExistingPreauth(false);
1360
+ }
1361
+ };
1362
+
1363
+ const handleSubmit = async () => {
1364
+ if (!consentDone) {
1365
+ showSnackbar({ kind: 'error', title: 'Consent required', subtitle: 'Complete OTP or biometric consent first.' });
1366
+ return;
1367
+ }
1368
+ if (existingPreauth?.blocking) {
1369
+ showSnackbar({
1370
+ kind: 'error',
1371
+ title: 'Existing preauth found',
1372
+ subtitle: `An active preauth already exists for ${intervention.code} (status: ${existingPreauth.status}${
1373
+ existingPreauth.preauthCode ? `, code: ${existingPreauth.preauthCode}` : ''
1374
+ }).`,
1375
+ });
1376
+ return;
1377
+ }
1378
+ if (isElective && consentMethod === 'otp' && (!otp || otp.length < 4)) {
1379
+ showSnackbar({
1380
+ kind: 'error',
1381
+ title: 'Missing OTP',
1382
+ subtitle: 'Send OTP, enter the code, confirm it, then submit.',
1383
+ });
1384
+ return;
1385
+ }
1386
+ if (!isElective && !consentToken) {
1387
+ showSnackbar({
1388
+ kind: 'error',
1389
+ title: 'Missing authorization',
1390
+ subtitle: 'A claim token is required.',
1391
+ });
1392
+ return;
1393
+ }
1394
+ // Prefer the text-box value so edits are validated/submitted, not the launch bill line.
1395
+ const billUnitPrice = String(unitPrice ?? billItem.item_price ?? billItem.item_total_price ?? '').trim();
1396
+ const resolvedUnitPrice = billUnitPrice;
1397
+ const needsClinicalIndications =
1398
+ isPlainNormalPreauth ||
1399
+ specialty.requiresRadiologyPreauth ||
1400
+ specialty.requiresRenalPreauth ||
1401
+ specialty.requiresOpticalPreauth;
1402
+ const missingFormFields = [...formRelevant].filter((k) => !formFound.has(k));
1403
+ const missingRequired = [
1404
+ !icdCode.trim() && 'ICD-11 diagnosis',
1405
+ !doctorId.trim() && 'Doctor National ID',
1406
+ !providerEmail.trim() && 'Provider notification email',
1407
+ !resolvedUnitPrice &&
1408
+ (needsBillableServicePicker ? 'Unit price (select a billable service)' : 'Unit price (from bill)'),
1409
+ isElective && !expectedServiceStartDate && 'Expected service start date',
1410
+ needsClinicalIndications &&
1411
+ !clinicalIndications.trim() &&
1412
+ (isPlainNormalPreauth
1413
+ ? 'Clinical indications'
1414
+ : 'Clinical indications (complete Pre-authorization form on the patient chart)'),
1415
+ missingFormFields.length > 0 &&
1416
+ `Pre-authorization form fields (${missingFormFields.join(', ')})`,
1417
+ ].filter(Boolean);
1418
+ if (missingRequired.length) {
1419
+ showSnackbar({
1420
+ kind: 'error',
1421
+ title: 'Missing required fields',
1422
+ subtitle: `Fill: ${missingRequired.join(', ')}`,
1423
+ });
1424
+ return;
1425
+ }
1426
+ if (!requiredAttachmentsReady) {
1427
+ showSnackbar({
1428
+ kind: 'error',
1429
+ title: 'Attachments required',
1430
+ subtitle: 'Generate or add a file for every required document, then Submit preauth.',
1431
+ });
1432
+ return;
1433
+ }
1434
+
1435
+ setSubmitting(true);
1436
+ abortRef.current = new AbortController();
1437
+ try {
1438
+ let tokenForPreauth = consentToken;
1439
+
1440
+ if (isElective) {
1441
+ // Elective is pre-visit: mint AUTHORIZED_PENDING_VISIT via authorize, then POST /preauths.
1442
+ // Do not close/reject existing open claim visits.
1443
+ if (consentMethod === 'otp') {
1444
+ const auth = await resolveOrCreateElectivePreVisitAuthorization({
1445
+ patientId: crNo,
1446
+ otp,
1447
+ interventions: [intervention.code],
1448
+ serviceType: resolveElectiveServiceType(),
1449
+ locationUuid,
1450
+ beneficiaryContactId: selectedContactId || undefined,
1451
+ });
1452
+ tokenForPreauth = extractElectiveAuthorizationToken(auth);
1453
+ if (!tokenForPreauth) {
1454
+ throw new Error('Authorize succeeded but no authorization token was returned.');
1455
+ }
1456
+ setActiveConsentToken(tokenForPreauth);
1457
+ } else if (!tokenForPreauth) {
1458
+ throw new Error(
1459
+ 'Missing pre-visit authorization token. Confirm biometric consent, then submit.',
1460
+ );
1461
+ }
1462
+ } else {
1463
+ await ensureInterventionOnVisit(tokenForPreauth, intervention.code, locationUuid);
1464
+ }
1465
+
1466
+ const payload = buildPayload();
1467
+ if (isElective && tokenForPreauth) {
1468
+ payload.diagnoses = (payload.diagnoses ?? []).map((d) => ({
1469
+ ...d,
1470
+ consent_token: tokenForPreauth,
1471
+ }));
1472
+ }
1473
+ if (isElective) {
1474
+ await createElectivePreauth(
1475
+ payload,
1476
+ {
1477
+ code: interventionForSubmit.code,
1478
+ requiresRadiologyPreauth: interventionForSubmit.requiresRadiologyPreauth,
1479
+ requiresOncologyPreauth: interventionForSubmit.requiresOncologyPreauth,
1480
+ requiresOpticalPreauth: interventionForSubmit.requiresOpticalPreauth,
1481
+ requiresRenalPreauth: interventionForSubmit.requiresRenalPreauth,
1482
+ requiresSurgicalPreauth: interventionForSubmit.requiresSurgicalPreauth,
1483
+ },
1484
+ tokenForPreauth,
1485
+ );
1486
+ } else {
1487
+ await createPreauth(
1488
+ payload,
1489
+ {
1490
+ code: interventionForSubmit.code,
1491
+ requiresRadiologyPreauth: interventionForSubmit.requiresRadiologyPreauth,
1492
+ requiresOncologyPreauth: interventionForSubmit.requiresOncologyPreauth,
1493
+ requiresOpticalPreauth: interventionForSubmit.requiresOpticalPreauth,
1494
+ requiresRenalPreauth: interventionForSubmit.requiresRenalPreauth,
1495
+ requiresSurgicalPreauth: interventionForSubmit.requiresSurgicalPreauth,
1496
+ },
1497
+ tokenForPreauth,
1498
+ );
1499
+ }
1500
+
1501
+ setPolling(true);
1502
+ const polled = await pollPreauthUntilSubmitted(
1503
+ tokenForPreauth,
1504
+ locationUuid,
1505
+ intervention.code,
1506
+ { signal: abortRef.current.signal },
1507
+ );
1508
+ const status = polled.status;
1509
+ const preauthCode = polled.preauthCode;
1510
+
1511
+ if (preauthCode) {
1512
+ storePreauthCode(tokenForPreauth, intervention.code, preauthCode);
1513
+ }
1514
+
1515
+ // Sync selected ICD onto the claim (normal / post-claim only).
1516
+ if (!isElective) {
1517
+ try {
1518
+ const visitDx = selectedDx?.kind === 'visit' ? selectedDx.dx : null;
1519
+ await addClaimDiagnosis({
1520
+ consentToken: tokenForPreauth,
1521
+ interventionCode: intervention.code,
1522
+ icdCode: icdCode.trim(),
1523
+ locationUuid,
1524
+ practitionerIdentificationNumber: (visitDx?.practioner_nat_id || doctorId || '').trim(),
1525
+ practitionerIdentificationType: DEFAULT_DOCTOR_ID_TYPE,
1526
+ practitionerRegulationBody: normalizeRegulationBody(
1527
+ visitDx?.practitioner_body || regulationBody,
1528
+ ),
1529
+ });
1530
+ } catch {
1531
+ // Preauth succeeded; claim diagnosis can still be added from bill details.
1532
+ }
1533
+ }
1534
+
1535
+ const awaitingDoctor = status === 'PENDING_DOCTOR_APPROVAL';
1536
+ showSnackbar({
1537
+ kind: 'success',
1538
+ title: awaitingDoctor
1539
+ ? isElective
1540
+ ? 'Elective preauth submitted'
1541
+ : 'Preauth submitted'
1542
+ : status === 'FINALISED' || status === 'FINALIZED'
1543
+ ? 'Preauth finalised'
1544
+ : 'Preauth submitted',
1545
+ subtitle: awaitingDoctor
1546
+ ? 'Awaiting doctor approval. Track progress on the Preauthorizations Status tab.'
1547
+ : preauthCode
1548
+ ? `Code: ${preauthCode}`
1549
+ : `Status: ${status}`,
1550
+ });
1551
+ onSuccess?.({ consentToken: tokenForPreauth, preauthCode, status });
1552
+ allowCloseWithoutPromptRef.current = true;
1553
+ setDirty(false);
1554
+ setSubmitting(false);
1555
+ setPolling(false);
1556
+ void closeWorkspace({ discardUnsavedChanges: true });
1557
+ } catch (e: any) {
1558
+ showSnackbar({
1559
+ kind: 'error',
1560
+ title: 'Preauth failed',
1561
+ subtitle: extractHieErrorMessage(e, 'Failed to create preauth'),
1562
+ });
1563
+ } finally {
1564
+ if (!allowCloseWithoutPromptRef.current) {
1565
+ setSubmitting(false);
1566
+ setPolling(false);
1567
+ }
1568
+ }
1569
+ };
1570
+
1571
+ if (!isElective && !consentToken) {
1572
+ return null;
1573
+ }
1574
+
1575
+ return (
1576
+ <Workspace2
1577
+ title={t('raisePreauth', 'Raise preauth')}
1578
+ hasUnsavedChanges={!allowCloseWithoutPromptRef.current && (dirty || submitting || polling)}
1579
+ >
1580
+ <Form className={styles.form}>
1581
+ <div className={styles.body}>
1582
+ <div className={styles.header}>
1583
+ <div>
1584
+ <h4>{t('raisePreauth', 'Raise preauth')}</h4>
1585
+ <p className={styles.muted}>
1586
+ {patientName} · {intervention.code} · {billableService}
1587
+ </p>
1588
+ </div>
1589
+ <Tag type={isElective ? 'magenta' : 'blue'} size="md">
1590
+ {isElective ? 'Elective' : specialtyLabel} preauth
1591
+ </Tag>
1592
+ </div>
1593
+
1594
+ {checkingExistingPreauth ? (
1595
+ <InlineLoading description="Checking for existing preauth…" />
1596
+ ) : existingPreauth ? (
1597
+ <div
1598
+ className={`${styles.existingBanner} ${
1599
+ existingPreauth.blocking ? styles.existingBannerError : styles.existingBannerWarning
1600
+ }`}
1601
+ role="status"
1602
+ >
1603
+ <p className={styles.existingBannerTitle}>
1604
+ {existingPreauth.blocking ? 'Existing active preauth' : 'Prior preauth found'}
1605
+ </p>
1606
+ <p className={styles.existingBannerMeta}>
1607
+ {[
1608
+ `SHA ${intervention.code}`,
1609
+ `Status: ${existingPreauth.status}`,
1610
+ existingPreauth.preauthCode ? `Code: ${existingPreauth.preauthCode}` : null,
1611
+ ]
1612
+ .filter(Boolean)
1613
+ .join(' · ')}
1614
+ </p>
1615
+ <p className={styles.existingBannerHint}>
1616
+ {existingPreauth.blocking
1617
+ ? 'Submit is blocked to avoid duplicates.'
1618
+ : String(existingPreauth.status).toUpperCase().includes('EXPIRED')
1619
+ ? 'This preauth has expired. You can raise a new one.'
1620
+ : 'You may resubmit after correcting the prior request.'}
1621
+ </p>
1622
+ <div className={styles.existingBannerActions}>
1623
+ <button
1624
+ type="button"
1625
+ className={styles.existingBannerCancel}
1626
+ onClick={() => void handleCancelExistingPreauth()}
1627
+ disabled={submitting || polling || cancellingExistingPreauth}
1628
+ >
1629
+ {cancellingExistingPreauth ? 'Cancelling…' : 'Cancel preauth'}
1630
+ </button>
1631
+ </div>
1632
+ </div>
1633
+ ) : null}
1634
+
1635
+ {isElective ? (
1636
+ <section className={styles.section}>
1637
+ <h5>Expected service start</h5>
1638
+ <DatePicker
1639
+ datePickerType="single"
1640
+ dateFormat="Y-m-d"
1641
+ value={expectedServiceStartDate ? dayjs(expectedServiceStartDate).toDate() : undefined}
1642
+ onChange={(dates: Date[]) => {
1643
+ markDirty();
1644
+ if (dates?.[0]) setExpectedServiceStartDate(dateToServiceIso(dates[0]));
1645
+ }}
1646
+ >
1647
+ <DatePickerInput
1648
+ id="expected-service-start"
1649
+ labelText="Expected service start date"
1650
+ placeholder="yyyy-mm-dd"
1651
+ />
1652
+ </DatePicker>
1653
+ </section>
1654
+ ) : null}
1655
+
1656
+ <section className={styles.section}>
1657
+ <h5>Consent</h5>
1658
+ <RadioButtonGroup
1659
+ legendText="Consent method"
1660
+ name="consent-method"
1661
+ valueSelected={consentMethod}
1662
+ onChange={(v) => {
1663
+ setConsentMethod(v as 'biometric' | 'otp');
1664
+ setConsentDone(false);
1665
+ }}
1666
+ >
1667
+ <RadioButton labelText="OTP" value="otp" id="preauth-otp" />
1668
+ <RadioButton labelText="Biometrics" value="biometric" id="preauth-bio" />
1669
+ </RadioButtonGroup>
1670
+ {consentMethod === 'otp' ? (
1671
+ <div className={styles.row}>
1672
+ {isElective ? (
1673
+ loadingContacts ? (
1674
+ <InlineLoading description="Loading contacts…" />
1675
+ ) : (
1676
+ <Dropdown
1677
+ id="preauth-otp-contact"
1678
+ titleText="Patient contact (OTP)"
1679
+ label="Select contact"
1680
+ items={patientContacts}
1681
+ itemToString={(item: PatientContactResult | null) =>
1682
+ item
1683
+ ? `${item.contactType || 'Contact'}: ${item.contactValue}${
1684
+ item.isConfirmed ? ' (confirmed)' : ''
1685
+ }`
1686
+ : ''
1687
+ }
1688
+ selectedItem={
1689
+ patientContacts.find((c) => String(c.id) === selectedContactId) ?? null
1690
+ }
1691
+ onChange={({ selectedItem }) => {
1692
+ setSelectedContactId(selectedItem?.id != null ? String(selectedItem.id) : '');
1693
+ setOtpSent(false);
1694
+ setConsentDone(false);
1695
+ setOtp('');
1696
+ }}
1697
+ />
1698
+ )
1699
+ ) : null}
1700
+ <Button
1701
+ type="button"
1702
+ kind="tertiary"
1703
+ size="sm"
1704
+ onClick={handleSendOtp}
1705
+ disabled={
1706
+ sendingOtp ||
1707
+ consentDone ||
1708
+ (isElective && (loadingContacts || (!selectedContactId && patientContacts.length > 0)))
1709
+ }
1710
+ >
1711
+ {sendingOtp ? <InlineLoading description="Sending…" /> : 'Send OTP'}
1712
+ </Button>
1713
+ <TextInput
1714
+ id="preauth-otp-input"
1715
+ labelText="OTP"
1716
+ value={otp}
1717
+ disabled={!otpSent || consentDone}
1718
+ onChange={(e) => setOtp(e.target.value)}
1719
+ />
1720
+ <Button
1721
+ type="button"
1722
+ kind="primary"
1723
+ size="sm"
1724
+ onClick={handleVerifyOtp}
1725
+ disabled={!otpSent || consentDone}
1726
+ >
1727
+ Confirm OTP
1728
+ </Button>
1729
+ </div>
1730
+ ) : (
1731
+ <div className={styles.row}>
1732
+ <p className={styles.muted}>
1733
+ Complete biometric capture on the patient device, then confirm below.
1734
+ </p>
1735
+ <Button kind="primary" size="sm" onClick={handleConfirmBiometric} disabled={consentDone}>
1736
+ Confirm biometric consent
1737
+ </Button>
1738
+ </div>
1739
+ )}
1740
+ {consentDone ? <Tag type="green" size="sm">Consent complete</Tag> : null}
1741
+ </section>
1742
+
1743
+ <section className={styles.section}>
1744
+ <h5>Service &amp; provider</h5>
1745
+ <div className={styles.row}>
1746
+ <DatePicker
1747
+ datePickerType="single"
1748
+ dateFormat="Y-m-d"
1749
+ value={serviceStart ? dayjs(serviceStart).toDate() : undefined}
1750
+ onChange={([date]) => {
1751
+ if (!date) return;
1752
+ markDirty();
1753
+ setServiceStart(dateToServiceIso(date, dayjs(serviceStart).format('HH:mm:ss')));
1754
+ }}
1755
+ >
1756
+ <DatePickerInput id="preauth-service-start" labelText="Service start" placeholder="yyyy-mm-dd" />
1757
+ </DatePicker>
1758
+ <TextInput
1759
+ id="preauth-service-start-time"
1760
+ type="time"
1761
+ labelText="Start time"
1762
+ value={dayjs(serviceStart).format('HH:mm')}
1763
+ onChange={(e) => {
1764
+ markDirty();
1765
+ setServiceStart(dateToServiceIso(dayjs(serviceStart).toDate(), `${e.target.value}:00`));
1766
+ }}
1767
+ />
1768
+ </div>
1769
+ <div className={styles.row}>
1770
+ <DatePicker
1771
+ datePickerType="single"
1772
+ dateFormat="Y-m-d"
1773
+ value={serviceEnd ? dayjs(serviceEnd).toDate() : undefined}
1774
+ onChange={([date]) => {
1775
+ if (!date) return;
1776
+ markDirty();
1777
+ setServiceEnd(dateToServiceIso(date, dayjs(serviceEnd).format('HH:mm:ss')));
1778
+ }}
1779
+ >
1780
+ <DatePickerInput id="preauth-service-end" labelText="Service end" placeholder="yyyy-mm-dd" />
1781
+ </DatePicker>
1782
+ <TextInput
1783
+ id="preauth-service-end-time"
1784
+ type="time"
1785
+ labelText="End time"
1786
+ value={dayjs(serviceEnd).format('HH:mm')}
1787
+ onChange={(e) => {
1788
+ markDirty();
1789
+ setServiceEnd(dateToServiceIso(dayjs(serviceEnd).toDate(), `${e.target.value}:00`));
1790
+ }}
1791
+ />
1792
+ </div>
1793
+
1794
+ <TextInput
1795
+ id="provider-email"
1796
+ labelText="Provider notification email"
1797
+ value={providerEmail}
1798
+ onChange={(e) => {
1799
+ markDirty();
1800
+ setProviderEmail(e.target.value);
1801
+ }}
1802
+ />
1803
+
1804
+ {needsBillableServicePicker ? (
1805
+ <div className={styles.searchBlock}>
1806
+ <p className={styles.fieldHint}>
1807
+ No unit price on a patient bill for this intervention. Select a billable service to
1808
+ use its SHA tariff as the preauth unit price.
1809
+ </p>
1810
+ {loadingBillableItems ? (
1811
+ <InlineLoading description="Loading billable services…" />
1812
+ ) : (
1813
+ <ComboBox
1814
+ id="preauth-billable-service"
1815
+ titleText="Billable service"
1816
+ placeholder="Search billable service"
1817
+ items={(billableItems ?? []) as BillableServiceOption[]}
1818
+ itemToString={(item: BillableServiceOption | null) => item?.name ?? ''}
1819
+ selectedItem={selectedBillableService}
1820
+ onChange={({ selectedItem }) => {
1821
+ markDirty();
1822
+ const item = (selectedItem as BillableServiceOption | null) ?? null;
1823
+ setSelectedBillableService(item);
1824
+ const price = unitPriceFromBillableService(item, shaPaymentModeUuid);
1825
+ setUnitPrice(price);
1826
+ if (price) {
1827
+ setCostPerSession((prev) => (prev.trim() ? prev : price));
1828
+ }
1829
+ }}
1830
+ />
1831
+ )}
1832
+ {selectedBillableService && !unitPrice.trim() ? (
1833
+ <InlineNotification
1834
+ kind="warning"
1835
+ lowContrast
1836
+ hideCloseButton
1837
+ title="No price on service"
1838
+ subtitle="This billable service has no SHA (or other) price configured."
1839
+ />
1840
+ ) : null}
1841
+ </div>
1842
+ ) : null}
1843
+ {!billPriceLookupDone && isElective ? (
1844
+ <InlineLoading description="Looking up unit price from patient bills…" />
1845
+ ) : null}
1846
+ <TextInput
1847
+ id="unit-price"
1848
+ labelText={
1849
+ needsBillableServicePicker ? 'Unit price (from billable service)' : 'Unit price (from bill)'
1850
+ }
1851
+ type="number"
1852
+ value={unitPrice}
1853
+ onChange={(e) => {
1854
+ markDirty();
1855
+ setUnitPrice(e.target.value);
1856
+ }}
1857
+ />
1858
+
1859
+ <div className={styles.searchBlock}>
1860
+ <p className={styles.fieldHint}>
1861
+ Diagnosis (ICD-11). Prefills rank 1 when available; choose another if needed.
1862
+ </p>
1863
+ {loadingDx ? (
1864
+ <InlineLoading description="Loading patient diagnoses…" />
1865
+ ) : (
1866
+ <ComboBox
1867
+ id="preauth-diagnosis"
1868
+ titleText="Select diagnosis"
1869
+ placeholder="Search diagnosis / ICD-11 code"
1870
+ items={diagnosisItems}
1871
+ itemToString={diagnosisPickLabel}
1872
+ selectedItem={selectedDx}
1873
+ shouldFilterItem={() => true}
1874
+ onInputChange={handleDiagnosisInputChange}
1875
+ onChange={({ selectedItem }) => {
1876
+ applyDiagnosisPick(selectedItem as DiagnosisPick | null, { fromUser: true });
1877
+ if (selectedItem) {
1878
+ setConceptDxHits([]);
1879
+ }
1880
+ }}
1881
+ />
1882
+ )}
1883
+ {searchingDx ? <InlineLoading description="Searching concepts…" /> : null}
1884
+ <TextInput
1885
+ id="preauth-icd11"
1886
+ labelText="ICD-11 code"
1887
+ placeholder="Filled from selection (or type manually)"
1888
+ value={icdCode}
1889
+ onChange={(e) => {
1890
+ markDirty();
1891
+ setIcdCode(e.target.value.trim());
1892
+ }}
1893
+ />
1894
+ </div>
1895
+
1896
+ <div className={styles.searchBlock}>
1897
+ <p className={styles.fieldHint}>Search OpenMRS providers</p>
1898
+ <ComboBox
1899
+ id="preauth-provider"
1900
+ titleText="Provider"
1901
+ placeholder="Type at least 2 characters to search"
1902
+ items={providerHits}
1903
+ itemToString={providerItemLabel}
1904
+ selectedItem={selectedProvider}
1905
+ shouldFilterItem={() => true}
1906
+ onInputChange={handleProviderInputChange}
1907
+ onChange={({ selectedItem }) => applyProviderSelection(selectedItem as OpenMrsProviderHit | null)}
1908
+ />
1909
+ {searchingProviders ? <InlineLoading description="Searching providers…" /> : null}
1910
+ </div>
1911
+
1912
+ <div className={styles.row}>
1913
+ <TextInput
1914
+ id="doctor-id"
1915
+ labelText="Doctor National ID"
1916
+ value={doctorId}
1917
+ onChange={(e) => {
1918
+ markDirty();
1919
+ setDoctorId(e.target.value);
1920
+ setHwrHit(null);
1921
+ }}
1922
+ />
1923
+ <TextInput
1924
+ id="doctor-id-type"
1925
+ labelText="Doctor ID type"
1926
+ value={DEFAULT_DOCTOR_ID_TYPE}
1927
+ readOnly
1928
+ />
1929
+ <Button kind="tertiary" size="md" onClick={() => handleSearchHwr()} disabled={searchingHwr || !doctorId.trim()}>
1930
+ {searchingHwr ? 'Searching HWR…' : 'Search HWR (body)'}
1931
+ </Button>
1932
+ </div>
1933
+ {hwrHit ? (
1934
+ <Tag type="green" size="sm">
1935
+ {hwrHit.membership?.full_name || 'Match'} · {normalizeRegulationBody(hwrHit.membership?.licensing_body)}
1936
+ </Tag>
1937
+ ) : null}
1938
+ <div className={styles.row}>
1939
+ <Dropdown
1940
+ id="reg-body"
1941
+ titleText="Regulation body"
1942
+ label="Select regulation body"
1943
+ items={[...REGULATION_BODIES]}
1944
+ selectedItem={normalizeRegulationBody(regulationBody)}
1945
+ onChange={({ selectedItem }) => {
1946
+ markDirty();
1947
+ setRegulationBody(normalizeRegulationBody(selectedItem));
1948
+ }}
1949
+ />
1950
+ <p className={styles.fieldHint}>COC = Clinical Officers Council · NCK = Nursing Council of Kenya</p>
1951
+ </div>
1952
+ </section>
1953
+
1954
+ {isPlainNormalPreauth ? (
1955
+ <section className={styles.section}>
1956
+ <h5>Clinical indications</h5>
1957
+ <TextArea id="normal-clinical-indications" {...clinicalIndicationsFieldProps} />
1958
+ </section>
1959
+ ) : null}
1960
+
1961
+ {specialty.requiresSurgicalPreauth ? (
1962
+ <section className={styles.section}>
1963
+ <h5>Surgical preauth</h5>
1964
+ <TextArea
1965
+ id="chief-complaint"
1966
+ labelText="Chief complaint"
1967
+ value={formFieldStatus('chiefComplaint') === 'loading' ? '' : chiefComplaint}
1968
+ readOnly={formFieldLocked('chiefComplaint')}
1969
+ invalid={formFieldInvalid('chiefComplaint')}
1970
+ invalidText={formFieldInvalid('chiefComplaint') ? FORM_MISSING_HINT : undefined}
1971
+ onChange={(e) => {
1972
+ if (formFieldLocked('chiefComplaint')) return;
1973
+ markDirty();
1974
+ setChiefComplaint(e.target.value);
1975
+ }}
1976
+ />
1977
+ <TextInput
1978
+ id="vital-signs"
1979
+ labelText="Vital signs"
1980
+ value={vitalSigns}
1981
+ onChange={(e) => {
1982
+ markDirty();
1983
+ setVitalSigns(e.target.value);
1984
+ }}
1985
+ />
1986
+ <TextArea
1987
+ id="hpi"
1988
+ labelText="History of present illness"
1989
+ value={formFieldStatus('hpi') === 'loading' ? '' : hpi}
1990
+ readOnly={formFieldLocked('hpi')}
1991
+ invalid={formFieldInvalid('hpi')}
1992
+ invalidText={formFieldInvalid('hpi') ? FORM_MISSING_HINT : undefined}
1993
+ onChange={(e) => {
1994
+ if (formFieldLocked('hpi')) return;
1995
+ markDirty();
1996
+ setHpi(e.target.value);
1997
+ }}
1998
+ />
1999
+ <TextArea
2000
+ id="physical-exam"
2001
+ labelText="Physical examination"
2002
+ value={formFieldStatus('physicalExam') === 'loading' ? '' : physicalExam}
2003
+ readOnly={formFieldLocked('physicalExam')}
2004
+ invalid={formFieldInvalid('physicalExam')}
2005
+ invalidText={formFieldInvalid('physicalExam') ? FORM_MISSING_HINT : undefined}
2006
+ onChange={(e) => {
2007
+ if (formFieldLocked('physicalExam')) return;
2008
+ markDirty();
2009
+ setPhysicalExam(e.target.value);
2010
+ }}
2011
+ />
2012
+ <TextArea
2013
+ id="investigations"
2014
+ labelText="Investigation report details"
2015
+ value={formFieldStatus('investigations') === 'loading' ? '' : investigations}
2016
+ readOnly={formFieldLocked('investigations')}
2017
+ invalid={formFieldInvalid('investigations')}
2018
+ invalidText={formFieldInvalid('investigations') ? FORM_MISSING_HINT : undefined}
2019
+ onChange={(e) => {
2020
+ if (formFieldLocked('investigations')) return;
2021
+ markDirty();
2022
+ setInvestigations(e.target.value);
2023
+ }}
2024
+ />
2025
+ <div className={styles.row}>
2026
+ <Dropdown
2027
+ id="anaesthesia"
2028
+ titleText="Type of anaesthesia"
2029
+ label="Select"
2030
+ items={ANAESTHESIA}
2031
+ selectedItem={anaesthesia || null}
2032
+ disabled={formFieldLocked('anaesthesia')}
2033
+ invalid={formFieldInvalid('anaesthesia')}
2034
+ invalidText={formFieldInvalid('anaesthesia') ? FORM_MISSING_HINT : undefined}
2035
+ onChange={({ selectedItem }) => {
2036
+ if (formFieldLocked('anaesthesia')) return;
2037
+ markDirty();
2038
+ setAnaesthesia(selectedItem ?? '');
2039
+ }}
2040
+ />
2041
+ <DatePicker
2042
+ datePickerType="single"
2043
+ dateFormat="Y-m-d"
2044
+ value={surgeryDate ? dayjs(surgeryDate).toDate() : undefined}
2045
+ onChange={(dates: Date[]) => {
2046
+ if (formFieldLocked('surgeryDate')) return;
2047
+ markDirty();
2048
+ if (dates?.[0]) setSurgeryDate(dateToServiceIso(dates[0]));
2049
+ }}
2050
+ >
2051
+ <DatePickerInput
2052
+ id="surgery-date"
2053
+ labelText="Surgery date"
2054
+ placeholder="yyyy-mm-dd"
2055
+ readOnly={formFieldLocked('surgeryDate')}
2056
+ invalid={formFieldInvalid('surgeryDate')}
2057
+ invalidText={formFieldInvalid('surgeryDate') ? FORM_MISSING_HINT : undefined}
2058
+ />
2059
+ </DatePicker>
2060
+ </div>
2061
+ <div className={styles.row}>
2062
+ <Checkbox
2063
+ id="related-employment"
2064
+ labelText="Related to employment"
2065
+ checked={relatedToEmployment}
2066
+ readOnly={formFieldLocked('relatedToEmployment')}
2067
+ onChange={(_, { checked }) => {
2068
+ if (formFieldLocked('relatedToEmployment')) return;
2069
+ markDirty();
2070
+ setRelatedToEmployment(checked);
2071
+ }}
2072
+ />
2073
+ <Checkbox
2074
+ id="related-accident"
2075
+ labelText="Related to auto/other accident"
2076
+ checked={relatedToAccident}
2077
+ readOnly={formFieldLocked('relatedToAccident')}
2078
+ onChange={(_, { checked }) => {
2079
+ if (formFieldLocked('relatedToAccident')) return;
2080
+ markDirty();
2081
+ setRelatedToAccident(checked);
2082
+ }}
2083
+ />
2084
+ <Checkbox
2085
+ id="surgical-co-insured"
2086
+ labelText="Is co-insured"
2087
+ checked={isCoInsured}
2088
+ readOnly={formFieldLocked('isCoInsured')}
2089
+ onChange={(_, { checked }) => {
2090
+ if (formFieldLocked('isCoInsured')) return;
2091
+ markDirty();
2092
+ setIsCoInsured(checked);
2093
+ }}
2094
+ />
2095
+ </div>
2096
+ {formFieldInvalid('relatedToEmployment') ||
2097
+ formFieldInvalid('relatedToAccident') ||
2098
+ formFieldInvalid('isCoInsured') ? (
2099
+ <InlineNotification
2100
+ kind="error"
2101
+ lowContrast
2102
+ hideCloseButton
2103
+ title="Missing Pre-authorization form answers"
2104
+ subtitle={FORM_MISSING_HINT}
2105
+ />
2106
+ ) : null}
2107
+ {isCoInsured ? (
2108
+ <TextArea
2109
+ id="co-insurance-details"
2110
+ labelText="Co-insurance details"
2111
+ value={formFieldStatus('coInsuranceDetails') === 'loading' ? '' : coInsuranceDetails}
2112
+ readOnly={formFieldLocked('coInsuranceDetails')}
2113
+ invalid={formFieldInvalid('coInsuranceDetails')}
2114
+ invalidText={formFieldInvalid('coInsuranceDetails') ? FORM_MISSING_HINT : undefined}
2115
+ onChange={(e) => {
2116
+ if (formFieldLocked('coInsuranceDetails')) return;
2117
+ markDirty();
2118
+ setCoInsuranceDetails(e.target.value);
2119
+ }}
2120
+ />
2121
+ ) : null}
2122
+ </section>
2123
+ ) : null}
2124
+
2125
+ {specialty.requiresRenalPreauth ? (
2126
+ <section className={styles.section}>
2127
+ <h5>Renal preauth</h5>
2128
+ <div className={styles.row}>
2129
+ <TextInput
2130
+ id="sessions-required"
2131
+ labelText="Number of sessions required"
2132
+ value={formFieldStatus('sessionsRequired') === 'loading' ? '' : sessionsRequired}
2133
+ readOnly={formFieldLocked('sessionsRequired')}
2134
+ invalid={formFieldInvalid('sessionsRequired')}
2135
+ invalidText={formFieldInvalid('sessionsRequired') ? FORM_MISSING_HINT : undefined}
2136
+ onChange={(e) => {
2137
+ if (formFieldLocked('sessionsRequired')) return;
2138
+ markDirty();
2139
+ setSessionsRequired(e.target.value);
2140
+ }}
2141
+ />
2142
+ <TextInput
2143
+ id="cost-per-session"
2144
+ labelText="Cost per session"
2145
+ value={costPerSession}
2146
+ onChange={(e) => {
2147
+ markDirty();
2148
+ setCostPerSession(e.target.value);
2149
+ }}
2150
+ />
2151
+ <Dropdown
2152
+ id="frequency"
2153
+ titleText="Frequency of sessions"
2154
+ label="Select"
2155
+ items={FREQUENCY}
2156
+ selectedItem={frequency || null}
2157
+ disabled={formFieldLocked('frequency')}
2158
+ invalid={formFieldInvalid('frequency')}
2159
+ invalidText={formFieldInvalid('frequency') ? FORM_MISSING_HINT : undefined}
2160
+ onChange={({ selectedItem }) => {
2161
+ if (formFieldLocked('frequency')) return;
2162
+ markDirty();
2163
+ setFrequency(selectedItem ?? '');
2164
+ }}
2165
+ />
2166
+ </div>
2167
+ <TextArea id="renal-indications" {...clinicalIndicationsFieldProps} />
2168
+ <div className={styles.row}>
2169
+ <DatePicker
2170
+ datePickerType="single"
2171
+ dateFormat="Y-m-d"
2172
+ value={startDate ? dayjs(startDate).toDate() : undefined}
2173
+ onChange={(dates: Date[]) => {
2174
+ if (formFieldLocked('startDate')) return;
2175
+ markDirty();
2176
+ if (dates?.[0]) setStartDate(dateToServiceIso(dates[0]));
2177
+ }}
2178
+ >
2179
+ <DatePickerInput
2180
+ id="renal-start"
2181
+ labelText="Start date"
2182
+ placeholder="yyyy-mm-dd"
2183
+ readOnly={formFieldLocked('startDate')}
2184
+ invalid={formFieldInvalid('startDate')}
2185
+ invalidText={formFieldInvalid('startDate') ? FORM_MISSING_HINT : undefined}
2186
+ />
2187
+ </DatePicker>
2188
+ <Checkbox
2189
+ id="renal-co-insured"
2190
+ labelText="Is co-insured"
2191
+ checked={isCoInsured}
2192
+ readOnly={formFieldLocked('isCoInsured')}
2193
+ onChange={(_, { checked }) => {
2194
+ if (formFieldLocked('isCoInsured')) return;
2195
+ markDirty();
2196
+ setIsCoInsured(checked);
2197
+ }}
2198
+ />
2199
+ </div>
2200
+ {formFieldInvalid('isCoInsured') ? (
2201
+ <InlineNotification
2202
+ kind="error"
2203
+ lowContrast
2204
+ hideCloseButton
2205
+ title="Missing co-insured answer"
2206
+ subtitle={FORM_MISSING_HINT}
2207
+ />
2208
+ ) : null}
2209
+ {isCoInsured ? (
2210
+ <TextArea
2211
+ id="renal-co-insurance-details"
2212
+ labelText="Co-insurance details"
2213
+ value={formFieldStatus('coInsuranceDetails') === 'loading' ? '' : coInsuranceDetails}
2214
+ readOnly={formFieldLocked('coInsuranceDetails')}
2215
+ invalid={formFieldInvalid('coInsuranceDetails')}
2216
+ invalidText={formFieldInvalid('coInsuranceDetails') ? FORM_MISSING_HINT : undefined}
2217
+ onChange={(e) => {
2218
+ if (formFieldLocked('coInsuranceDetails')) return;
2219
+ markDirty();
2220
+ setCoInsuranceDetails(e.target.value);
2221
+ }}
2222
+ />
2223
+ ) : null}
2224
+ </section>
2225
+ ) : null}
2226
+
2227
+ {specialty.requiresOpticalPreauth ? (
2228
+ <section className={styles.section}>
2229
+ <h5>Optical preauth</h5>
2230
+ <TextArea id="optical-indications" {...clinicalIndicationsFieldProps} />
2231
+ <TextArea
2232
+ id="necessity"
2233
+ labelText="Necessity of service"
2234
+ value={necessity}
2235
+ onChange={(e) => {
2236
+ markDirty();
2237
+ setNecessity(e.target.value);
2238
+ }}
2239
+ />
2240
+ <div className={styles.row}>
2241
+ <Dropdown
2242
+ id="lens-rx"
2243
+ titleText="Lens prescription"
2244
+ label="Select"
2245
+ items={LENS}
2246
+ selectedItem={lensPrescription || null}
2247
+ onChange={({ selectedItem }) => {
2248
+ markDirty();
2249
+ setLensPrescription(selectedItem ?? '');
2250
+ }}
2251
+ />
2252
+ <Dropdown
2253
+ id="new-or-repl"
2254
+ titleText="New or replacement"
2255
+ label="Select"
2256
+ items={NEW_OR_REPL}
2257
+ selectedItem={newOrReplacement || null}
2258
+ onChange={({ selectedItem }) => {
2259
+ markDirty();
2260
+ setNewOrReplacement(selectedItem ?? '');
2261
+ }}
2262
+ />
2263
+ </div>
2264
+ <div className={styles.row}>
2265
+ <TextInput
2266
+ id="lens-amount"
2267
+ labelText="Lens amount"
2268
+ value={lensAmount}
2269
+ onChange={(e) => {
2270
+ markDirty();
2271
+ setLensAmount(e.target.value);
2272
+ }}
2273
+ />
2274
+ <TextInput
2275
+ id="eye-exam-amount"
2276
+ labelText="Eye examination amount"
2277
+ value={eyeExamAmount}
2278
+ onChange={(e) => {
2279
+ markDirty();
2280
+ setEyeExamAmount(e.target.value);
2281
+ }}
2282
+ />
2283
+ <TextInput
2284
+ id="frame-amount"
2285
+ labelText="Frame amount"
2286
+ value={frameAmount}
2287
+ onChange={(e) => {
2288
+ markDirty();
2289
+ setFrameAmount(e.target.value);
2290
+ }}
2291
+ />
2292
+ </div>
2293
+ </section>
2294
+ ) : null}
2295
+
2296
+ {specialty.requiresOncologyPreauth ? (
2297
+ <section className={styles.section}>
2298
+ <h5>Oncology preauth</h5>
2299
+ <div className={styles.row}>
2300
+ <Dropdown
2301
+ id="carcinoma-staging"
2302
+ titleText="Carcinoma staging"
2303
+ label="Select"
2304
+ items={STAGING}
2305
+ selectedItem={carcinomaStaging || null}
2306
+ onChange={({ selectedItem }) => {
2307
+ markDirty();
2308
+ setCarcinomaStaging(selectedItem ?? '');
2309
+ }}
2310
+ />
2311
+ <Dropdown
2312
+ id="metastases"
2313
+ titleText="Metastases"
2314
+ label="Select"
2315
+ items={METASTASES}
2316
+ selectedItem={metastases || null}
2317
+ onChange={({ selectedItem }) => {
2318
+ markDirty();
2319
+ setMetastases(selectedItem ?? '');
2320
+ }}
2321
+ />
2322
+ <Dropdown
2323
+ id="treatment-setting"
2324
+ titleText="Treatment setting"
2325
+ label="Select"
2326
+ items={TREATMENT}
2327
+ selectedItem={treatmentSetting || null}
2328
+ onChange={({ selectedItem }) => {
2329
+ markDirty();
2330
+ setTreatmentSetting(selectedItem ?? '');
2331
+ }}
2332
+ />
2333
+ </div>
2334
+ <TextArea
2335
+ id="comorbidity"
2336
+ labelText="Comorbidity"
2337
+ value={comorbidity}
2338
+ onChange={(e) => {
2339
+ markDirty();
2340
+ setComorbidity(e.target.value);
2341
+ }}
2342
+ />
2343
+ <TextArea
2344
+ id="progress-report"
2345
+ labelText="Progress report"
2346
+ value={progressReport}
2347
+ onChange={(e) => {
2348
+ markDirty();
2349
+ setProgressReport(e.target.value);
2350
+ }}
2351
+ />
2352
+ <div className={styles.row}>
2353
+ <DatePicker
2354
+ datePickerType="single"
2355
+ dateFormat="Y-m-d"
2356
+ value={startDate ? dayjs(startDate).toDate() : undefined}
2357
+ onChange={(dates: Date[]) => {
2358
+ markDirty();
2359
+ if (dates?.[0]) setStartDate(dateToServiceIso(dates[0]));
2360
+ }}
2361
+ >
2362
+ <DatePickerInput id="oncology-start" labelText="Start date" placeholder="yyyy-mm-dd" />
2363
+ </DatePicker>
2364
+ </div>
2365
+ <div className={styles.row}>
2366
+ <TextInput
2367
+ id="onc-sessions"
2368
+ labelText="Number of sessions required"
2369
+ value={sessionsRequired}
2370
+ onChange={(e) => {
2371
+ markDirty();
2372
+ setSessionsRequired(e.target.value);
2373
+ }}
2374
+ />
2375
+ <TextInput
2376
+ id="onc-cost"
2377
+ labelText="Cost per session"
2378
+ value={costPerSession}
2379
+ onChange={(e) => {
2380
+ markDirty();
2381
+ setCostPerSession(e.target.value);
2382
+ }}
2383
+ />
2384
+ <Checkbox
2385
+ id="onc-co-insured"
2386
+ labelText="Is co-insured"
2387
+ checked={isCoInsured}
2388
+ onChange={(_, { checked }) => {
2389
+ markDirty();
2390
+ setIsCoInsured(checked);
2391
+ }}
2392
+ />
2393
+ </div>
2394
+ </section>
2395
+ ) : null}
2396
+
2397
+ {specialty.requiresRadiologyPreauth ? (
2398
+ <section className={styles.section}>
2399
+ <h5>Imaging / radiology preauth</h5>
2400
+ <TextArea id="imaging-indications" {...clinicalIndicationsFieldProps} />
2401
+ </section>
2402
+ ) : null}
2403
+
2404
+ <PreauthAttachments
2405
+ attachments={attachments}
2406
+ onChange={handleAttachmentsChange}
2407
+ addableDocTypes={addableDocTypes}
2408
+ billItem={billItem as Record<string, unknown>}
2409
+ intervention={interventionForSubmit}
2410
+ disabled={submitting || polling}
2411
+ />
2412
+ </div>
2413
+
2414
+ <ButtonSet className={styles.buttonSet}>
2415
+ <Button kind="secondary" onClick={() => closeWorkspace()} disabled={submitting || polling}>
2416
+ Cancel
2417
+ </Button>
2418
+ <Button
2419
+ kind="primary"
2420
+ onClick={handleSubmit}
2421
+ disabled={!consentDone || submitting || polling || Boolean(existingPreauth?.blocking) || checkingExistingPreauth}
2422
+ >
2423
+ {polling ? (
2424
+ <InlineLoading description="Confirming submission…" />
2425
+ ) : submitting ? (
2426
+ <InlineLoading description="Submitting…" />
2427
+ ) : (
2428
+ t('submitPreauth', 'Submit preauth')
2429
+ )}
2430
+ </Button>
2431
+ </ButtonSet>
2432
+ </Form>
2433
+ </Workspace2>
2434
+ );
2435
+ };
2436
+
2437
+ const PreauthWorkspace: React.FC<Workspace2DefinitionProps<PreauthWorkspaceProps>> = ({
2438
+ workspaceProps,
2439
+ closeWorkspace,
2440
+ }) => {
2441
+ if (!workspaceProps) {
2442
+ return (
2443
+ <Workspace2 title="Raise Preauth">
2444
+ <div />
2445
+ </Workspace2>
2446
+ );
2447
+ }
2448
+ const props = workspaceProps ?? ({} as PreauthWorkspaceProps);
2449
+ return (
2450
+ <PreauthForm
2451
+ key={`${props.consentToken}::${props.intervention?.code ?? ''}`}
2452
+ {...props}
2453
+ closeWorkspace={closeWorkspace}
2454
+ />
2455
+ );
2456
+ };
2457
+
2458
+ export default PreauthWorkspace;