@ampath/esm-dha-workflow-app 4.0.0-next.33 → 4.0.0-next.331

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 (758) hide show
  1. package/README.md +19 -0
  2. package/dist/1149.js +1 -0
  3. package/dist/1149.js.map +1 -0
  4. package/dist/1197.js +1 -0
  5. package/dist/1362.js +1 -0
  6. package/dist/1362.js.map +1 -0
  7. package/dist/1551.js +1 -0
  8. package/dist/1551.js.map +1 -0
  9. package/dist/1925.js +1 -0
  10. package/dist/1925.js.map +1 -0
  11. package/dist/1927.js +1 -0
  12. package/dist/1927.js.map +1 -0
  13. package/dist/203.js +1 -0
  14. package/dist/203.js.map +1 -0
  15. package/dist/2054.js +1 -0
  16. package/dist/2054.js.map +1 -0
  17. package/dist/2093.js +1 -0
  18. package/dist/2093.js.map +1 -0
  19. package/dist/2177.js +2 -0
  20. package/dist/2177.js.map +1 -0
  21. package/dist/2200.js +1 -0
  22. package/dist/2200.js.map +1 -0
  23. package/dist/2230.js +1 -0
  24. package/dist/2230.js.map +1 -0
  25. package/dist/2493.js +1 -0
  26. package/dist/2493.js.map +1 -0
  27. package/dist/262.js +2 -0
  28. package/dist/262.js.map +1 -0
  29. package/dist/2914.js +1 -0
  30. package/dist/2914.js.map +1 -0
  31. package/dist/2936.js +1 -0
  32. package/dist/2936.js.map +1 -0
  33. package/dist/2988.js +1 -0
  34. package/dist/2988.js.map +1 -0
  35. package/dist/3041.js +1 -0
  36. package/dist/3041.js.map +1 -0
  37. package/dist/307.js +1 -0
  38. package/dist/307.js.map +1 -0
  39. package/dist/3099.js +1 -0
  40. package/dist/3184.js +2 -0
  41. package/dist/3184.js.map +1 -0
  42. package/dist/3202.js +1 -0
  43. package/dist/3202.js.map +1 -0
  44. package/dist/3222.js +1 -0
  45. package/dist/3222.js.map +1 -0
  46. package/dist/3406.js +1 -0
  47. package/dist/3406.js.map +1 -0
  48. package/dist/347.js +1 -0
  49. package/dist/347.js.map +1 -0
  50. package/dist/3654.js +1 -0
  51. package/dist/3654.js.map +1 -0
  52. package/dist/4003.js +1 -0
  53. package/dist/4003.js.map +1 -0
  54. package/dist/4008.js +1 -0
  55. package/dist/4008.js.map +1 -0
  56. package/dist/4055.js +1 -0
  57. package/dist/4205.js +1 -0
  58. package/dist/4205.js.map +1 -0
  59. package/dist/4225.js +1 -0
  60. package/dist/4225.js.map +1 -0
  61. package/dist/4231.js +1 -0
  62. package/dist/4231.js.map +1 -0
  63. package/dist/4300.js +1 -0
  64. package/dist/4335.js +1 -0
  65. package/dist/4353.js +1 -0
  66. package/dist/4353.js.map +1 -0
  67. package/dist/4431.js +1 -0
  68. package/dist/4431.js.map +1 -0
  69. package/dist/4454.js +1 -0
  70. package/dist/4454.js.map +1 -0
  71. package/dist/4457.js +2 -0
  72. package/dist/4457.js.LICENSE.txt +282 -0
  73. package/dist/4457.js.map +1 -0
  74. package/dist/446.js +1 -0
  75. package/dist/446.js.map +1 -0
  76. package/dist/4611.js +1 -0
  77. package/dist/4611.js.map +1 -0
  78. package/dist/4652.js +1 -0
  79. package/dist/4674.js +1 -0
  80. package/dist/4674.js.map +1 -0
  81. package/dist/4755.js +1 -0
  82. package/dist/4755.js.map +1 -0
  83. package/dist/4986.js +1 -0
  84. package/dist/4986.js.map +1 -0
  85. package/dist/5097.js +1 -0
  86. package/dist/5097.js.map +1 -0
  87. package/dist/5119.js +1 -0
  88. package/dist/5119.js.map +1 -0
  89. package/dist/5167.js +1 -0
  90. package/dist/5167.js.map +1 -0
  91. package/dist/5380.js +1 -0
  92. package/dist/5380.js.map +1 -0
  93. package/dist/5422.js +1 -0
  94. package/dist/5422.js.map +1 -0
  95. package/dist/5576.js +1 -0
  96. package/dist/5576.js.map +1 -0
  97. package/dist/5851.js +1 -0
  98. package/dist/5851.js.map +1 -0
  99. package/dist/5961.js +1 -0
  100. package/dist/5961.js.map +1 -0
  101. package/dist/6264.js +1 -0
  102. package/dist/6264.js.map +1 -0
  103. package/dist/6540.js +2 -0
  104. package/dist/6540.js.map +1 -0
  105. package/dist/6606.js +1 -0
  106. package/dist/6606.js.map +1 -0
  107. package/dist/6720.js +1 -0
  108. package/dist/6720.js.map +1 -0
  109. package/dist/6824.js +1 -0
  110. package/dist/6824.js.map +1 -0
  111. package/dist/6942.js +1 -0
  112. package/dist/6942.js.map +1 -0
  113. package/dist/71.js +1 -0
  114. package/dist/71.js.map +1 -0
  115. package/dist/7207.js +1 -0
  116. package/dist/7207.js.map +1 -0
  117. package/dist/7240.js +1 -0
  118. package/dist/7240.js.map +1 -0
  119. package/dist/7255.js +1 -0
  120. package/dist/7255.js.map +1 -0
  121. package/dist/7271.js +1 -0
  122. package/dist/7271.js.map +1 -0
  123. package/dist/7420.js +1 -0
  124. package/dist/7420.js.map +1 -0
  125. package/dist/7521.js +1 -0
  126. package/dist/7521.js.map +1 -0
  127. package/dist/7557.js +1 -0
  128. package/dist/7557.js.map +1 -0
  129. package/dist/7717.js +1 -0
  130. package/dist/7717.js.map +1 -0
  131. package/dist/7830.js +2 -0
  132. package/dist/7830.js.map +1 -0
  133. package/dist/7879.js +1 -0
  134. package/dist/7879.js.map +1 -0
  135. package/dist/7941.js +1 -0
  136. package/dist/7941.js.map +1 -0
  137. package/dist/8091.js +1 -0
  138. package/dist/8091.js.map +1 -0
  139. package/dist/810.js +1 -2
  140. package/dist/810.js.map +1 -1
  141. package/dist/8558.js +1 -0
  142. package/dist/8558.js.map +1 -0
  143. package/dist/8733.js +1 -0
  144. package/dist/8733.js.map +1 -0
  145. package/dist/874.js +1 -0
  146. package/dist/874.js.map +1 -0
  147. package/dist/8895.js +1 -0
  148. package/dist/8895.js.map +1 -0
  149. package/dist/9070.js +1 -0
  150. package/dist/9070.js.map +1 -0
  151. package/dist/9091.js +1 -0
  152. package/dist/9091.js.map +1 -0
  153. package/dist/9093.js +1 -0
  154. package/dist/9093.js.map +1 -0
  155. package/dist/9249.js +1 -0
  156. package/dist/9249.js.map +1 -0
  157. package/dist/9338.js +1 -0
  158. package/dist/9338.js.map +1 -0
  159. package/dist/9418.js +2 -0
  160. package/dist/9418.js.LICENSE.txt +1 -0
  161. package/dist/9418.js.map +1 -0
  162. package/dist/9428.js +1 -0
  163. package/dist/9428.js.map +1 -0
  164. package/dist/9721.js +1 -0
  165. package/dist/9721.js.map +1 -0
  166. package/dist/esm-dha-workflow-app.js +1 -1
  167. package/dist/esm-dha-workflow-app.js.buildmanifest.json +1675 -210
  168. package/dist/esm-dha-workflow-app.js.map +1 -1
  169. package/dist/main.js +1 -1
  170. package/dist/main.js.map +1 -1
  171. package/dist/routes.json +1 -1
  172. package/local-config.json +5 -0
  173. package/package.json +16 -6
  174. package/src/admissions/admission-request-list/admission-request-list.scss +0 -0
  175. package/src/admissions/admission-request-list/admission-request-list.tsx +263 -0
  176. package/src/admissions/admissions-dashboard.component.scss +15 -0
  177. package/src/admissions/admissions-dashboard.component.tsx +277 -0
  178. package/src/admissions/admissions.resource.ts +233 -0
  179. package/src/admissions/admitted-list/admitted-patients-list.tsx +206 -0
  180. package/src/admissions/awaiting-discharge-list/awaiting-discharge-list.tsx +197 -0
  181. package/src/admissions/bed-assigment-request/bed-assignment-request-list.tsx +134 -0
  182. package/src/admissions/constants/index.ts +33 -0
  183. package/src/admissions/discharged-list/discharged-list.scss +0 -0
  184. package/src/admissions/discharged-list/discharged-list.tsx +67 -0
  185. package/src/admissions/form-entry-workspace/form-entry-workspace.tsx +62 -0
  186. package/src/admissions/inpatient/admission-history/patient-admission-history.tsx +76 -0
  187. package/src/admissions/inpatient/admission-requests/patient-admission-requests.scss +19 -0
  188. package/src/admissions/inpatient/admission-requests/patient-admission-requests.tsx +72 -0
  189. package/src/admissions/inpatient/inpatient-admissions.component.scss +7 -0
  190. package/src/admissions/inpatient/inpatient-admissions.component.tsx +46 -0
  191. package/src/admissions/modal/add-bill-items/add-bill-items.modal.scss +17 -0
  192. package/src/admissions/modal/add-bill-items/add-bill-items.modal.tsx +233 -0
  193. package/src/admissions/modal/admit-elsewhere/admit-elsewhere.modal.scss +23 -0
  194. package/src/admissions/modal/admit-elsewhere/admit-elsewhere.modal.tsx +156 -0
  195. package/src/admissions/modal/admit-patient/admit-patient.modal.scss +0 -0
  196. package/src/admissions/modal/admit-patient/admit-patient.modal.tsx +111 -0
  197. package/src/admissions/modal/bed-swap/bed-swap.modal.scss +0 -0
  198. package/src/admissions/modal/bed-swap/bed-swap.modal.tsx +102 -0
  199. package/src/admissions/modal/cancel-admission-request/cancel-admission-request.scss +11 -0
  200. package/src/admissions/modal/cancel-admission-request/cancel-admission-request.tsx +105 -0
  201. package/src/admissions/modal/discharge/discharge-patient.modal.scss +13 -0
  202. package/src/admissions/modal/discharge/discharge-patient.modal.tsx +86 -0
  203. package/src/admissions/types/index.ts +263 -0
  204. package/src/appointments/appointments.component.scss +6 -0
  205. package/src/appointments/appointments.component.tsx +8 -1
  206. package/src/billing/api/billing.api.ts +139 -0
  207. package/src/billing/billing-claims.resource.ts +900 -0
  208. package/src/billing/billing-dashboard-link.component.tsx +31 -0
  209. package/src/billing/billing-dashboard-reset.ts +27 -0
  210. package/src/billing/billing-root.tsx +42 -0
  211. package/src/billing/dashboard/billingDashboard.component.scss +0 -0
  212. package/src/billing/dashboard/billingDashboard.component.tsx +25 -0
  213. package/src/billing/dashboard/v2/active-visits/active-visits.component.tsx +257 -0
  214. package/src/billing/dashboard/v2/active-visits/active-visits.resource.ts +85 -0
  215. package/src/billing/dashboard/v2/active-visits/active-visits.scss +15 -0
  216. package/src/billing/dashboard/v2/active-visits.component.tsx +102 -0
  217. package/src/billing/dashboard/v2/admissions/admission-requests-tab.component.tsx +79 -0
  218. package/src/billing/dashboard/v2/billing-claims-dashboard.component.scss +209 -0
  219. package/src/billing/dashboard/v2/billing-claims-dashboard.component.tsx +347 -0
  220. package/src/billing/dashboard/v2/cash-checklist/bill-document.component.scss +90 -0
  221. package/src/billing/dashboard/v2/cash-checklist/bill-document.component.tsx +101 -0
  222. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.component.scss +199 -0
  223. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.component.tsx +361 -0
  224. package/src/billing/dashboard/v2/cash-checklist/cash-checklist.resource.ts +239 -0
  225. package/src/billing/dashboard/v2/cash-checklist/payment-drawer.component.scss +246 -0
  226. package/src/billing/dashboard/v2/cash-checklist/payment-drawer.component.tsx +182 -0
  227. package/src/billing/dashboard/v2/claim-statuses.ts +143 -0
  228. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.scss +0 -0
  229. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.tsx +35 -0
  230. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-panel.component.scss +67 -0
  231. package/src/billing/dashboard/v2/claim-visits/claim-diagnosis-details/claim-diagnosis-panel.component.tsx +90 -0
  232. package/src/billing/dashboard/v2/claim-visits/claim-doctors/claim-doctors.scss +28 -0
  233. package/src/billing/dashboard/v2/claim-visits/claim-doctors/claim-doctors.tsx +36 -0
  234. package/src/billing/dashboard/v2/claim-visits/claim-history/claim-history.component.scss +119 -0
  235. package/src/billing/dashboard/v2/claim-visits/claim-history/claim-history.component.tsx +198 -0
  236. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-details.component.scss +5 -0
  237. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-details.component.tsx +160 -0
  238. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-panel.component.scss +105 -0
  239. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/claim-intervention-panel.component.tsx +184 -0
  240. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/intervention-attachments.component.scss +161 -0
  241. package/src/billing/dashboard/v2/claim-visits/claim-intervention-details/intervention-attachments.component.tsx +328 -0
  242. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-details.component.tsx +96 -0
  243. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-document.component.tsx +236 -0
  244. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-panel.component.scss +98 -0
  245. package/src/billing/dashboard/v2/claim-visits/claim-invoice-details/claim-invoice-panel.component.tsx +292 -0
  246. package/src/billing/dashboard/v2/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.scss +133 -0
  247. package/src/billing/dashboard/v2/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.tsx +217 -0
  248. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-by-token.component.tsx +150 -0
  249. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-page.component.scss +13 -0
  250. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-details-page.component.tsx +116 -0
  251. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-visit-details.component.scss +338 -0
  252. package/src/billing/dashboard/v2/claim-visits/claim-visit-details/claim-visit-details.component.tsx +616 -0
  253. package/src/billing/dashboard/v2/claim-visits/claim-visits.component.scss +5 -0
  254. package/src/billing/dashboard/v2/claim-visits/claim-visits.component.tsx +133 -0
  255. package/src/billing/dashboard/v2/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.scss +5 -0
  256. package/src/billing/dashboard/v2/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.tsx +49 -0
  257. package/src/billing/dashboard/v2/claim-visits/modal/claim-visit-details/claim-visit-details.modal.scss +17 -0
  258. package/src/billing/dashboard/v2/claim-visits/modal/claim-visit-details/claim-visit-details.modal.tsx +56 -0
  259. package/src/billing/dashboard/v2/claim-visits/modal/close-claim/close-claim.modal.scss +0 -0
  260. package/src/billing/dashboard/v2/claim-visits/modal/close-claim/close-claim.modal.tsx +129 -0
  261. package/src/billing/dashboard/v2/claim-visits/modal/submit-claim/submit-claim.modal.tsx +204 -0
  262. package/src/billing/dashboard/v2/claim-visits/shared/_empty-state.scss +28 -0
  263. package/src/billing/dashboard/v2/claim-visits/shared/record-cards.component.scss +298 -0
  264. package/src/billing/dashboard/v2/claim-visits/shared/record-cards.component.tsx +252 -0
  265. package/src/billing/dashboard/v2/claim-visits/shared/record-details.workspace.scss +42 -0
  266. package/src/billing/dashboard/v2/claim-visits/shared/record-details.workspace.tsx +54 -0
  267. package/src/billing/dashboard/v2/claim-visits/shared/record-table.component.scss +61 -0
  268. package/src/billing/dashboard/v2/claim-visits/shared/record-table.component.tsx +150 -0
  269. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.resource.ts +51 -0
  270. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.workspace.scss +191 -0
  271. package/src/billing/dashboard/v2/claim-visits/switch-intervention/switch-intervention.workspace.tsx +648 -0
  272. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.component.scss +595 -0
  273. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.component.tsx +810 -0
  274. package/src/billing/dashboard/v2/claim-workspace/claim-workspace.resource.ts +282 -0
  275. package/src/billing/dashboard/v2/claims-accounting/bill-utils.ts +134 -0
  276. package/src/billing/dashboard/v2/claims-accounting/claim-detail.component.tsx +346 -0
  277. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.component.scss +546 -0
  278. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.component.tsx +206 -0
  279. package/src/billing/dashboard/v2/claims-accounting/claims-accounting.resource.ts +337 -0
  280. package/src/billing/dashboard/v2/claims-accounting/invoice-document.component.scss +90 -0
  281. package/src/billing/dashboard/v2/claims-accounting/invoice-document.component.tsx +90 -0
  282. package/src/billing/dashboard/v2/claims-accounting/remittances.component.tsx +169 -0
  283. package/src/billing/dashboard/v2/claims-accounting/remittances.resource.ts +46 -0
  284. package/src/billing/dashboard/v2/claims-accounting/status-meta.ts +25 -0
  285. package/src/billing/dashboard/v2/clearance/cash-patients.scss +18 -0
  286. package/src/billing/dashboard/v2/clearance/cash.component.tsx +149 -0
  287. package/src/billing/dashboard/v2/clearance/clearance.component.scss +84 -0
  288. package/src/billing/dashboard/v2/clearance/clearance.component.tsx +225 -0
  289. package/src/billing/dashboard/v2/clearance/pay-cash.component.tsx +176 -0
  290. package/src/billing/dashboard/v2/clearance/pay-cash.scss +28 -0
  291. package/src/billing/dashboard/v2/clearance/prepaid-services.component.tsx +112 -0
  292. package/src/billing/dashboard/v2/facility-bills/claim-status.ts +249 -0
  293. package/src/billing/dashboard/v2/facility-bills/facility-bills.component.scss +140 -0
  294. package/src/billing/dashboard/v2/facility-bills/facility-bills.component.tsx +687 -0
  295. package/src/billing/dashboard/v2/facility-bills/preauths-datatables/pending-preauths.component.tsx +132 -0
  296. package/src/billing/dashboard/v2/facility-bills/preauths-datatables/preauth-preview-table.component.tsx +267 -0
  297. package/src/billing/dashboard/v2/facility-bills/preauths.component.tsx +124 -0
  298. package/src/billing/dashboard/v2/inpatient-requests/inpatient-requests.component.scss +22 -0
  299. package/src/billing/dashboard/v2/inpatient-requests/inpatient-requests.component.tsx +389 -0
  300. package/src/billing/dashboard/v2/inpatient-requests/modal/start-inpatient-claim/start-inpatient-claim.component.scss +0 -0
  301. package/src/billing/dashboard/v2/inpatient-requests/modal/start-inpatient-claim/start-inpatient-claim.component.tsx +0 -0
  302. package/src/billing/dashboard/v2/new-facility-bills/bills-table.component.tsx +78 -0
  303. package/src/billing/dashboard/v2/new-facility-bills/bills-table.scss +18 -0
  304. package/src/billing/dashboard/v2/new-facility-bills/new-facility-bills.component.tsx +64 -0
  305. package/src/billing/dashboard/v2/new-facility-bills/new-facility-bills.scss +146 -0
  306. package/src/billing/dashboard/v2/patient-bill-details/attachments/add-attachments.component.tsx +223 -0
  307. package/src/billing/dashboard/v2/patient-bill-details/attachments/attachment.component.tsx +157 -0
  308. package/src/billing/dashboard/v2/patient-bill-details/attachments/attachments.scss +92 -0
  309. package/src/billing/dashboard/v2/patient-bill-details/attachments/case-summary/case-summary.scss +295 -0
  310. package/src/billing/dashboard/v2/patient-bill-details/attachments/case-summary/case-summary.tsx +326 -0
  311. package/src/billing/dashboard/v2/patient-bill-details/attachments/dialysis/dialysis-chart.scss +238 -0
  312. package/src/billing/dashboard/v2/patient-bill-details/attachments/dialysis/dialysis-chart.tsx +269 -0
  313. package/src/billing/dashboard/v2/patient-bill-details/attachments/discharge-summary/discharge-summary.scss +96 -0
  314. package/src/billing/dashboard/v2/patient-bill-details/attachments/discharge-summary/discharge-summary.tsx +124 -0
  315. package/src/billing/dashboard/v2/patient-bill-details/attachments/final-bill.component.tsx +152 -0
  316. package/src/billing/dashboard/v2/patient-bill-details/attachments/final-bill.scss +225 -0
  317. package/src/billing/dashboard/v2/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.scss +182 -0
  318. package/src/billing/dashboard/v2/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.tsx +173 -0
  319. package/src/billing/dashboard/v2/patient-bill-details/attachments/generate-attachments.component.tsx +360 -0
  320. package/src/billing/dashboard/v2/patient-bill-details/attachments/invoice.component.tsx +151 -0
  321. package/src/billing/dashboard/v2/patient-bill-details/attachments/invoice.scss +225 -0
  322. package/src/billing/dashboard/v2/patient-bill-details/attachments/type.ts +44 -0
  323. package/src/billing/dashboard/v2/patient-bill-details/bill-details/bill-details.scss +107 -0
  324. package/src/billing/dashboard/v2/patient-bill-details/bill-details/bill-details.tsx +508 -0
  325. package/src/billing/dashboard/v2/patient-bill-details/bill-details-page.component.scss +30 -0
  326. package/src/billing/dashboard/v2/patient-bill-details/bill-details-page.component.tsx +94 -0
  327. package/src/billing/dashboard/v2/patient-bill-details/claim-details/claim-details-skeleton.component.scss +89 -0
  328. package/src/billing/dashboard/v2/patient-bill-details/claim-details/claim-details-skeleton.component.tsx +53 -0
  329. package/src/billing/dashboard/v2/patient-bill-details/claim-details/patient-claim-details.component.scss +32 -0
  330. package/src/billing/dashboard/v2/patient-bill-details/claim-details/patient-claim-details.component.tsx +215 -0
  331. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.scss +0 -0
  332. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.tsx +99 -0
  333. package/src/billing/dashboard/v2/patient-bill-details/modals/add-claim-line/add-claim-line.modal.tsx +186 -0
  334. package/src/billing/dashboard/v2/patient-bill-details/patient-bill-details.scss +153 -0
  335. package/src/billing/dashboard/v2/patient-bill-details/patient-bill-details.tsx +458 -0
  336. package/src/billing/dashboard/v2/patient-bill-details/payment-mode.ts +124 -0
  337. package/src/billing/dashboard/v2/patient-bill-details/workspaces/add-claim-line/add-claim-line.workspace.scss +27 -0
  338. package/src/billing/dashboard/v2/patient-bill-details/workspaces/add-claim-line/add-claim-line.workspace.tsx +222 -0
  339. package/src/billing/dashboard/v2/patient-bill-details/workspaces/bill-item-payment/bill-item-payment.workspace.scss +27 -0
  340. package/src/billing/dashboard/v2/patient-bill-details/workspaces/bill-item-payment/bill-item-payment.workspace.tsx +109 -0
  341. package/src/billing/dashboard/v2/preauth/preauth-attachments.component.tsx +389 -0
  342. package/src/billing/dashboard/v2/preauth/preauth-list.component.scss +38 -0
  343. package/src/billing/dashboard/v2/preauth/preauth-list.component.tsx +226 -0
  344. package/src/billing/dashboard/v2/preauth/preauth-status-tag.component.tsx +75 -0
  345. package/src/billing/dashboard/v2/preauth/preauth-typed-fields.md +125 -0
  346. package/src/billing/dashboard/v2/preauth/preauth.resource.ts +1067 -0
  347. package/src/billing/dashboard/v2/preauth/preauth.workspace.scss +91 -0
  348. package/src/billing/dashboard/v2/preauth/preauth.workspace.tsx +1802 -0
  349. package/src/billing/dashboard/v2/preauth/preauthorizations-tab.component.tsx +45 -0
  350. package/src/billing/dashboard/v2/sha-claims/sha-claims-table.component.tsx +36 -0
  351. package/src/billing/dashboard/v2/sha-claims/sha-claims.component.tsx +60 -0
  352. package/src/billing/dashboard/v2/sha-claims/sha-claims.scss +8 -0
  353. package/src/billing/dashboard/v2/shared/dash-board-card/dash-board-card.component.scss +17 -0
  354. package/src/billing/dashboard/v2/shared/dash-board-card/dash-board-card.component.tsx +15 -0
  355. package/src/billing/dashboard/v2/shared/empty-state.component.scss +24 -0
  356. package/src/billing/dashboard/v2/shared/empty-state.component.tsx +13 -0
  357. package/src/billing/dashboard/v2/shared/scroll-to-top.component.scss +54 -0
  358. package/src/billing/dashboard/v2/shared/scroll-to-top.component.tsx +54 -0
  359. package/src/billing/dashboard/v2/shared/table-toolbar.component.scss +77 -0
  360. package/src/billing/dashboard/v2/shared/table-toolbar.component.tsx +48 -0
  361. package/src/billing/dashboard/v2/types/index.ts +507 -0
  362. package/src/billing/dashboard/v3/active-visits/active-visits.component.tsx +256 -0
  363. package/src/billing/dashboard/v3/active-visits/active-visits.resource.ts +57 -0
  364. package/src/billing/dashboard/v3/active-visits/active-visits.scss +15 -0
  365. package/src/billing/dashboard/v3/cash-checklist/bill-document.component.scss +90 -0
  366. package/src/billing/dashboard/v3/cash-checklist/bill-document.component.tsx +101 -0
  367. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.component.scss +199 -0
  368. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.component.tsx +361 -0
  369. package/src/billing/dashboard/v3/cash-checklist/cash-checklist.resource.ts +240 -0
  370. package/src/billing/dashboard/v3/cash-checklist/payment-drawer.component.scss +246 -0
  371. package/src/billing/dashboard/v3/cash-checklist/payment-drawer.component.tsx +182 -0
  372. package/src/billing/dashboard/v3/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.scss +0 -0
  373. package/src/billing/dashboard/v3/claim-visits/claim-diagnosis-details/claim-diagnosis-details.component.tsx +44 -0
  374. package/src/billing/dashboard/v3/claim-visits/claim-doctors/claim-doctors.scss +5 -0
  375. package/src/billing/dashboard/v3/claim-visits/claim-doctors/claim-doctors.tsx +42 -0
  376. package/src/billing/dashboard/v3/claim-visits/claim-documents/claim-documents.scss +10 -0
  377. package/src/billing/dashboard/v3/claim-visits/claim-documents/claim-documents.tsx +25 -0
  378. package/src/billing/dashboard/v3/claim-visits/claim-intervention-details/claim-intervention-details.component.tsx +223 -0
  379. package/src/billing/dashboard/v3/claim-visits/claim-invoice-details/claim-invoice-details.component.scss +6 -0
  380. package/src/billing/dashboard/v3/claim-visits/claim-invoice-details/claim-invoice-details.component.tsx +85 -0
  381. package/src/billing/dashboard/v3/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.scss +0 -0
  382. package/src/billing/dashboard/v3/claim-visits/claim-invoice-line-details/claim-invoice-line-details.component.tsx +109 -0
  383. package/src/billing/dashboard/v3/claim-visits/claim-visit-details/claim-visit-details.component.scss +104 -0
  384. package/src/billing/dashboard/v3/claim-visits/claim-visit-details/claim-visit-details.component.tsx +336 -0
  385. package/src/billing/dashboard/v3/claim-visits/claim-visits.component.scss +5 -0
  386. package/src/billing/dashboard/v3/claim-visits/claim-visits.component.tsx +139 -0
  387. package/src/billing/dashboard/v3/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.scss +5 -0
  388. package/src/billing/dashboard/v3/claim-visits/modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal.tsx +49 -0
  389. package/src/billing/dashboard/v3/claim-visits/modal/claim-invoice-lines/claim-invoice-lines.modal.scss +7 -0
  390. package/src/billing/dashboard/v3/claim-visits/modal/claim-invoice-lines/claim-invoice-lines.modal.tsx +35 -0
  391. package/src/billing/dashboard/v3/claim-visits/modal/claim-visit-details/claim-visit-details.modal.scss +6 -0
  392. package/src/billing/dashboard/v3/claim-visits/modal/claim-visit-details/claim-visit-details.modal.tsx +33 -0
  393. package/src/billing/dashboard/v3/claim-visits/modal/close-claim/close-claim.modal.scss +0 -0
  394. package/src/billing/dashboard/v3/claim-visits/modal/close-claim/close-claim.modal.tsx +129 -0
  395. package/src/billing/dashboard/v3/claim-visits/modal/submit-claim/submit-claim.modal.tsx +204 -0
  396. package/src/billing/dashboard/v3/claim-visits/payer-preview/index.scss +140 -0
  397. package/src/billing/dashboard/v3/claim-visits/payer-preview/payer-preview-tile.component.tsx +55 -0
  398. package/src/billing/dashboard/v3/claim-visits/payer-preview/payer-preview-workspace.component.tsx +157 -0
  399. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-doctors.component.tsx +54 -0
  400. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-lines.component.tsx +48 -0
  401. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-claim-notes.component.tsx +47 -0
  402. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-diagnoses.component.tsx +44 -0
  403. package/src/billing/dashboard/v3/claim-visits/payer-preview/tables/payer-interventions.component.tsx +44 -0
  404. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.resource.ts +51 -0
  405. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.workspace.scss +191 -0
  406. package/src/billing/dashboard/v3/claim-visits/switch-intervention/switch-intervention.workspace.tsx +648 -0
  407. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.component.scss +595 -0
  408. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.component.tsx +810 -0
  409. package/src/billing/dashboard/v3/claim-workspace/claim-workspace.resource.ts +282 -0
  410. package/src/billing/dashboard/v3/claims-accounting/bill-utils.ts +134 -0
  411. package/src/billing/dashboard/v3/claims-accounting/claim-detail.component.tsx +346 -0
  412. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.component.scss +546 -0
  413. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.component.tsx +206 -0
  414. package/src/billing/dashboard/v3/claims-accounting/claims-accounting.resource.ts +337 -0
  415. package/src/billing/dashboard/v3/claims-accounting/invoice-document.component.scss +90 -0
  416. package/src/billing/dashboard/v3/claims-accounting/invoice-document.component.tsx +90 -0
  417. package/src/billing/dashboard/v3/claims-accounting/remittances.component.tsx +169 -0
  418. package/src/billing/dashboard/v3/claims-accounting/remittances.resource.ts +46 -0
  419. package/src/billing/dashboard/v3/claims-accounting/status-meta.ts +25 -0
  420. package/src/billing/dashboard/v3/clearance/clearance.component.scss +100 -0
  421. package/src/billing/dashboard/v3/clearance/clearance.component.tsx +0 -0
  422. package/src/billing/dashboard/v3/clearance/prepaid-services.component.tsx +112 -0
  423. package/src/billing/dashboard/v3/facility-bills/claim-status.ts +243 -0
  424. package/src/billing/dashboard/v3/facility-bills/facility-bills.component.scss +9 -0
  425. package/src/billing/dashboard/v3/facility-bills/facility-bills.component.tsx +172 -0
  426. package/src/billing/dashboard/v3/facility-bills/preauths-datatables/pending-preauths.component.tsx +132 -0
  427. package/src/billing/dashboard/v3/facility-bills/preauths-datatables/preauth-preview-table.component.tsx +232 -0
  428. package/src/billing/dashboard/v3/facility-bills/preauths.component.tsx +124 -0
  429. package/src/billing/dashboard/v3/patient-bill-details/attachments/add-attachments.component.tsx +223 -0
  430. package/src/billing/dashboard/v3/patient-bill-details/attachments/attachment.component.tsx +157 -0
  431. package/src/billing/dashboard/v3/patient-bill-details/attachments/attachments.scss +92 -0
  432. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary-helper.ts +58 -0
  433. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary.scss +295 -0
  434. package/src/billing/dashboard/v3/patient-bill-details/attachments/case-summary/case-summary.tsx +273 -0
  435. package/src/billing/dashboard/v3/patient-bill-details/attachments/dialysis/dialysis-chart.scss +238 -0
  436. package/src/billing/dashboard/v3/patient-bill-details/attachments/dialysis/dialysis-chart.tsx +314 -0
  437. package/src/billing/dashboard/v3/patient-bill-details/attachments/discharge-summary/discharge-summary.scss +96 -0
  438. package/src/billing/dashboard/v3/patient-bill-details/attachments/discharge-summary/discharge-summary.tsx +126 -0
  439. package/src/billing/dashboard/v3/patient-bill-details/attachments/final-bill.component.tsx +75 -0
  440. package/src/billing/dashboard/v3/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.scss +182 -0
  441. package/src/billing/dashboard/v3/patient-bill-details/attachments/general-discharge-summary/general-discharge-summary.tsx +253 -0
  442. package/src/billing/dashboard/v3/patient-bill-details/attachments/generate-attachments.component.tsx +343 -0
  443. package/src/billing/dashboard/v3/patient-bill-details/attachments/invoice.component.tsx +150 -0
  444. package/src/billing/dashboard/v3/patient-bill-details/attachments/invoice.scss +225 -0
  445. package/src/billing/dashboard/v3/patient-bill-details/attachments/type.ts +259 -0
  446. package/src/billing/dashboard/v3/patient-bill-details/bill-details/bill-details.scss +13 -0
  447. package/src/billing/dashboard/v3/patient-bill-details/bill-details/bill-details.tsx +205 -0
  448. package/src/billing/dashboard/v3/patient-bill-details/claim-details/patient-claim-details.component.scss +0 -0
  449. package/src/billing/dashboard/v3/patient-bill-details/claim-details/patient-claim-details.component.tsx +61 -0
  450. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.scss +0 -0
  451. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-diagnosis/add-claim-diagnosis.modal.tsx +99 -0
  452. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-line/add-claim-line.modal.scss +14 -0
  453. package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-line/add-claim-line.modal.tsx +111 -0
  454. package/src/billing/dashboard/v3/patient-bill-details/modals/bill-item-payment/bill-item-payment.modal.scss +6 -0
  455. package/src/billing/dashboard/v3/patient-bill-details/modals/bill-item-payment/bill-item-payment.modal.tsx +139 -0
  456. package/src/billing/dashboard/v3/patient-bill-details/patient-bill-details.scss +20 -0
  457. package/src/billing/dashboard/v3/patient-bill-details/patient-bill-details.tsx +254 -0
  458. package/src/billing/dashboard/v3/patient-bill-details/visit-diagnosis-details/visit-diagnosis-details.component.scss +0 -0
  459. package/src/billing/dashboard/v3/patient-bill-details/visit-diagnosis-details/visit-diagnosis-details.component.tsx +80 -0
  460. package/src/billing/dashboard/v3/preauth/preauth-attachments.component.tsx +389 -0
  461. package/src/billing/dashboard/v3/preauth/preauth-list.component.scss +34 -0
  462. package/src/billing/dashboard/v3/preauth/preauth-list.component.tsx +281 -0
  463. package/src/billing/dashboard/v3/preauth/preauth-status-tag.component.tsx +75 -0
  464. package/src/billing/dashboard/v3/preauth/preauth-typed-fields.md +125 -0
  465. package/src/billing/dashboard/v3/preauth/preauth.resource.ts +1072 -0
  466. package/src/billing/dashboard/v3/preauth/preauth.workspace.scss +91 -0
  467. package/src/billing/dashboard/v3/preauth/preauth.workspace.tsx +1806 -0
  468. package/src/billing/dashboard/v3/preauth/preauthorizations-tab.component.tsx +45 -0
  469. package/src/billing/dashboard/v3/shared/empty-state.component.scss +25 -0
  470. package/src/billing/dashboard/v3/shared/empty-state.component.tsx +13 -0
  471. package/src/billing/dashboard/v3/shared/table-toolbar.component.scss +64 -0
  472. package/src/billing/dashboard/v3/shared/table-toolbar.component.tsx +48 -0
  473. package/src/billing/dashboard/v3/types/index.ts +381 -0
  474. package/src/billing/extensions/generate-order-bill-button/generate-order-bill-button.extension.tsx +55 -0
  475. package/src/billing/extensions/generate-order-bill-button/generate-order-bill-button.scss +16 -0
  476. package/src/billing/extensions/visit-billing/visit-billing.extension.scss +0 -0
  477. package/src/billing/extensions/visit-billing/visit-billing.extension.tsx +509 -0
  478. package/src/billing/invoice/bill.resource.ts +47 -0
  479. package/src/billing/invoice/invoice-header/header-card/header-card.scss +17 -0
  480. package/src/billing/invoice/invoice-header/header-card/header-card.tsx +21 -0
  481. package/src/billing/invoice/invoice.scss +113 -0
  482. package/src/billing/invoice/invoice.tsx +1441 -0
  483. package/src/billing/invoice/line-items/line-items.scss +0 -0
  484. package/src/billing/invoice/line-items/line-items.tsx +120 -0
  485. package/src/billing/invoice/modal/delete-bill-item/delete-bill-item.modal.scss +23 -0
  486. package/src/billing/invoice/modal/delete-bill-item/delete-bill-item.modal.tsx +114 -0
  487. package/src/billing/invoice/modal/edit-bill-item/edit-bill-item.modal.scss +0 -0
  488. package/src/billing/invoice/modal/edit-bill-item/edit-bill-item.modal.tsx +122 -0
  489. package/src/billing/invoice/payment-details/payment-details.scss +0 -0
  490. package/src/billing/invoice/payment-details/payment-details.tsx +43 -0
  491. package/src/billing/invoice/print-invoice/print-receipt.component.tsx +44 -0
  492. package/src/billing/invoice/print-invoice/print-receipt.scss +14 -0
  493. package/src/billing/maternity-discharge.resource.ts +21 -0
  494. package/src/billing/types/index.ts +354 -0
  495. package/src/billing/utils/index.ts +17 -0
  496. package/src/billing/widgets/billingTotalsRow.component.scss +0 -0
  497. package/src/billing/widgets/billingTotalsRow.component.tsx +712 -0
  498. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.resource.ts +130 -0
  499. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.scss +58 -0
  500. package/src/billing/workspaces/create-order-bill-form-workspace/create-order-bill-form.workspace.tsx +645 -0
  501. package/src/billing/workspaces/create-order-bill-form-workspace/schema.ts +12 -0
  502. package/src/bookings/bookings.component.scss +7 -0
  503. package/src/bookings/bookings.component.tsx +35 -0
  504. package/src/bookings/daily/daily-bookings.resource.ts +2 -1
  505. package/src/case-summary/case-summary.extension.scss +13 -0
  506. package/src/case-summary/case-summary.extension.tsx +40 -0
  507. package/src/case-summary/case-summary.resource.test.ts +69 -0
  508. package/src/case-summary/case-summary.resource.ts +52 -0
  509. package/src/case-summary/components/case-summary-printable.component.scss +174 -0
  510. package/src/case-summary/components/case-summary-printable.component.tsx +288 -0
  511. package/src/case-summary/components/case-summary-printable.utils.ts +51 -0
  512. package/src/case-summary/types/case-summary.types.ts +152 -0
  513. package/src/claims/claims.component.scss +70 -0
  514. package/src/claims/claims.component.tsx +713 -0
  515. package/src/claims/claims.resource.ts +1274 -0
  516. package/src/claims/index.ts +340 -0
  517. package/src/claims/interventions.resource.ts +131 -0
  518. package/src/claims/utils.ts +64 -0
  519. package/src/config-schema.ts +114 -1
  520. package/src/context/patient-context.tsx +27 -0
  521. package/src/createDashboardLink.tsx +9 -0
  522. package/src/dashboard/charts/chart.component.scss +24 -0
  523. package/src/dashboard/charts/chart.component.tsx +56 -0
  524. package/src/dashboard/dashboard.component.scss +48 -3
  525. package/src/dashboard/dashboard.component.tsx +26 -36
  526. package/src/dashboard/overview/overview.component.scss +40 -59
  527. package/src/dashboard/overview/overview.component.tsx +53 -41
  528. package/src/dashboard-meta/accounting-dashboard.meta.ts +6 -0
  529. package/src/dashboard-meta/admissions-dashboard.meta.ts +6 -0
  530. package/src/dashboard-meta/billing-dashboard.meta.ts +6 -0
  531. package/src/dashboard-meta/bookings-dashboard.meta.ts +6 -0
  532. package/src/dashboard-meta/case-summary.meta.ts +6 -0
  533. package/src/dashboard-meta/consultation-dashboard.meta.ts +6 -0
  534. package/src/dashboard-meta/dha-workflow-dashboard.meta.ts +6 -0
  535. package/src/dashboard-meta/inpatient-admissions.meta.ts +6 -0
  536. package/src/dashboard-meta/maternity-dashboard.meta.ts +6 -0
  537. package/src/dashboard-meta/mch-dashboard.meta.ts +6 -0
  538. package/src/dashboard-meta/pharmacy-dashboard.meta.ts +6 -0
  539. package/src/dashboard-meta/queue-dashboard.meta.ts +6 -0
  540. package/src/dashboard-meta/registers-dashboard.meta.ts +6 -0
  541. package/src/dashboard-meta/registry-dashboard.meta.ts +6 -0
  542. package/src/dashboard-meta/service-queue-admin.meta.ts +6 -0
  543. package/src/dashboard-meta/specialized-clinics-dashboard.meta.ts +6 -0
  544. package/src/dashboard-meta/triage-dashboard.meta.ts +6 -0
  545. package/src/index.ts +177 -6
  546. package/src/mnch/maternity/maternity-queues.component.scss +7 -0
  547. package/src/mnch/maternity/maternity-queues.component.tsx +32 -0
  548. package/src/mnch/maternity/queues/triage/maternity-triage.tsx +15 -0
  549. package/src/mnch/mch/mch-queues.component.scss +10 -0
  550. package/src/mnch/mch/mch-queues.component.tsx +36 -0
  551. package/src/mnch/mch/queues/consultation/mch-consultation.tsx +18 -0
  552. package/src/mnch/mch/queues/triage/mch-triage.tsx +15 -0
  553. package/src/mnch/mnch-root.tsx +17 -0
  554. package/src/mortuary/mortuary.component.tsx +13 -0
  555. package/src/pharmacy/pharmacy.component.scss +16 -0
  556. package/src/pharmacy/pharmacy.component.tsx +11 -6
  557. package/src/registers/registers.component.tsx +8 -0
  558. package/src/registry/drawer/emr-compare.component.scss +263 -0
  559. package/src/registry/drawer/emr-compare.component.tsx +302 -0
  560. package/src/registry/drawer/emr-compare.resource.ts +181 -0
  561. package/src/registry/drawer/emr-create-preview.component.tsx +123 -0
  562. package/src/registry/drawer/otp-verification-step.component.tsx +398 -0
  563. package/src/registry/drawer/pomsf-balance.util.test.ts +177 -0
  564. package/src/registry/drawer/pomsf-balance.util.ts +79 -0
  565. package/src/registry/drawer/verification.resource.ts +60 -0
  566. package/src/registry/drawer/workflow-drawer.component.scss +1242 -0
  567. package/src/registry/drawer/workflow-drawer.component.tsx +1476 -0
  568. package/src/registry/eligibility/eligibility-details/eligibility-details.scss +38 -0
  569. package/src/registry/eligibility/eligibility-details/eligibility-details.tsx +101 -0
  570. package/src/registry/eligibility/eliigibility-tags/eligibility-tags.scss +16 -0
  571. package/src/registry/eligibility/eliigibility-tags/eligibility-tags.tsx +120 -0
  572. package/src/registry/eligibility/modal/eligibility-details.modal.scss +0 -0
  573. package/src/registry/eligibility/modal/eligibility-details.modal.tsx +45 -0
  574. package/src/registry/hie.resource.ts +408 -0
  575. package/src/registry/hie.types.ts +57 -0
  576. package/src/registry/modal/biometrics-verification-modal/biometrics-verification-modal.scss +277 -0
  577. package/src/registry/modal/biometrics-verification-modal/biometrics-verification-modal.tsx +218 -0
  578. package/src/registry/modal/biometrics-verification-modal/type.ts +39 -0
  579. package/src/registry/modal/client-details-modal/client-details-modal.tsx +65 -29
  580. package/src/registry/modal/otp-modal/otp-whitlisting-modal.component.tsx +815 -0
  581. package/src/registry/modal/otp-modal/otp-whitlisting-modal.scss +354 -0
  582. package/src/registry/modal/otp-modal/otp-whitlisting.scss +0 -0
  583. package/src/registry/modal/otp-verification-modal/claims-consent.scss +72 -0
  584. package/src/registry/modal/otp-verification-modal/claims-consent.tsx +135 -0
  585. package/src/registry/modal/otp-verification-modal/extension/claims-consent.extension.tsx +124 -0
  586. package/src/registry/modal/otp-verification-modal/otp-verification-modal.scss +30 -0
  587. package/src/registry/modal/otp-verification-modal/otp-verification-modal.tsx +154 -54
  588. package/src/registry/modal/send-to-triage/payment-details.tsx +120 -0
  589. package/src/registry/modal/send-to-triage/payment-method.component.tsx +54 -0
  590. package/src/registry/modal/send-to-triage/send-to-queue.modal.tsx +980 -0
  591. package/src/registry/modal/send-to-triage/send-to-triage.modal.scss +156 -3
  592. package/src/registry/modal/send-to-triage/send-to-triage.modal.tsx +1101 -131
  593. package/src/registry/modal/start-patient-visit/start-patient-visit.modal.scss +34 -0
  594. package/src/registry/modal/start-patient-visit/start-patient-visit.modal.tsx +231 -0
  595. package/src/registry/payment-details/payment-options/payment-options.scss +13 -0
  596. package/src/registry/payment-details/payment-options/payment-options.tsx +61 -14
  597. package/src/registry/registration-list/registration-list.component.scss +32 -0
  598. package/src/registry/registration-list/registration-list.component.tsx +103 -0
  599. package/src/registry/registry-entry.tsx +11 -0
  600. package/src/registry/registry.component.scss +402 -78
  601. package/src/registry/registry.component.tsx +547 -221
  602. package/src/registry/registry.resource.ts +22 -3
  603. package/src/registry/types/index.ts +117 -8
  604. package/src/registry/utils/error-handler.ts +54 -0
  605. package/src/registry/utils/format-dependant-display-data.ts +1 -1
  606. package/src/registry/utils/hie-client-adapter.ts +6 -3
  607. package/src/registry/utils/mask-data.ts +40 -0
  608. package/src/registry/utils/phone-number-formatter.ts +11 -0
  609. package/src/resources/dashboard.resource.ts +20 -0
  610. package/src/resources/identifier-types.ts +2 -0
  611. package/src/resources/patient-resource.ts +6 -1
  612. package/src/resources/queue.resource.ts +24 -1
  613. package/src/resources/superset.resource.ts +21 -0
  614. package/src/resources/visit.resource.ts +19 -1
  615. package/src/root.component.tsx +8 -5
  616. package/src/routes.json +417 -23
  617. package/src/service-queues/admin/queue/modal/create-queue/create-queue.modal.scss +31 -0
  618. package/src/service-queues/admin/queue/modal/create-queue/create-queue.modal.tsx +153 -0
  619. package/src/service-queues/admin/queue/modal/edit-queue/edit-queue.modal.scss +0 -0
  620. package/src/service-queues/admin/queue/modal/edit-queue/edit-queue.modal.tsx +182 -0
  621. package/src/service-queues/admin/queue/queue-list/queue-list.scss +33 -0
  622. package/src/service-queues/admin/queue/queue-list/queue-list.tsx +113 -0
  623. package/src/service-queues/admin/queue-entry/queue-entry-list.component.scss +6 -0
  624. package/src/service-queues/admin/queue-entry/queue-entry-list.component.tsx +137 -0
  625. package/src/service-queues/admin/queue-room/modal/create-queue-room/create-queue-room.modal.scss +31 -0
  626. package/src/service-queues/admin/queue-room/modal/create-queue-room/create-queue-room.modal.tsx +137 -0
  627. package/src/service-queues/admin/queue-room/modal/edit-queue-room/edit-queue-room.modal.scss +0 -0
  628. package/src/service-queues/admin/queue-room/modal/edit-queue-room/edit-queue-room.modal.tsx +146 -0
  629. package/src/service-queues/admin/queue-room/queue-room-list/queue-room-list.scss +22 -0
  630. package/src/service-queues/admin/queue-room/queue-room-list/queue-room-list.tsx +120 -0
  631. package/src/service-queues/admin/service-queue-admin-dashboard.component.scss +6 -0
  632. package/src/service-queues/admin/service-queue-admin-dashboard.component.tsx +34 -0
  633. package/src/service-queues/consultation/consultation.component.tsx +9 -0
  634. package/src/service-queues/extensions/service-queue-patient-banner/service-queue-patient-banner.scss +30 -0
  635. package/src/service-queues/extensions/service-queue-patient-banner/service-queue-patient-banner.tsx +108 -0
  636. package/src/service-queues/modals/daily-report-patient-list/daily-report-patient-list.scss +26 -0
  637. package/src/service-queues/modals/daily-report-patient-list/daily-report-patient-list.tsx +110 -0
  638. package/src/service-queues/modals/move/move-patient.component.scss +1 -1
  639. package/src/service-queues/modals/move/move-patient.component.tsx +31 -17
  640. package/src/service-queues/queue-list/check-in.service.ts +26 -0
  641. package/src/service-queues/queue-list/queue-list.component.scss +37 -0
  642. package/src/service-queues/queue-list/queue-list.component.tsx +256 -56
  643. package/src/service-queues/service-queue/service-queue.component.tsx +151 -8
  644. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.scss +5 -0
  645. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.tsx +36 -7
  646. package/src/service-queues/service-queue.tsx +22 -16
  647. package/src/service-queues/service-queues.resource.ts +197 -1
  648. package/src/service-queues/service.resource.ts +1 -1
  649. package/src/shared/constants/concepts.ts +50 -0
  650. package/src/shared/constants/patient-category.ts +6 -0
  651. package/src/shared/constants/patient-type.ts +10 -0
  652. package/src/shared/constants/visit-types.ts +7 -0
  653. package/src/shared/services/billing.resource.ts +75 -0
  654. package/src/shared/services/claims.resource.ts +47 -0
  655. package/src/shared/services/client-payment-mode.resource.ts +27 -0
  656. package/src/shared/services/client-payment.resource.ts +17 -0
  657. package/src/shared/services/consultation-clearance.resource.ts +210 -0
  658. package/src/shared/services/eligibility.resource.ts +20 -0
  659. package/src/shared/services/encounters.resource.ts +33 -0
  660. package/src/shared/services/location.resource.ts +9 -0
  661. package/src/shared/types/index.ts +156 -0
  662. package/src/shared/ui/aggregate-stat-card/aggregate-stat-card.scss +42 -0
  663. package/src/shared/ui/aggregate-stat-card/aggregate-stat-card.tsx +42 -0
  664. package/src/shared/ui/confirm-modal/confirm.modal.scss +18 -0
  665. package/src/shared/ui/confirm-modal/confirm.modal.tsx +38 -0
  666. package/src/shared/ui/facility-worker-slot/facility-worker.component-slot.component.scss +39 -0
  667. package/src/shared/ui/facility-worker-slot/facility-worker.component-slot.component.tsx +19 -0
  668. package/src/shared/ui/otp-input/otp-input.component.scss +14 -0
  669. package/src/shared/ui/otp-input/otp-input.component.tsx +97 -0
  670. package/src/{service-queues/service-queue/stats → shared/ui}/stat-card/stat-card.component.tsx +6 -3
  671. package/src/shared/ui/timer/timer.component.scss +5 -0
  672. package/src/shared/ui/timer/timer.component.tsx +40 -0
  673. package/src/shared/utils/get-base-url.ts +10 -0
  674. package/src/shared/utils/get-tag-type.ts +75 -0
  675. package/src/side-nav-menu/mnch-nav-link-config.ts +16 -0
  676. package/src/side-nav-menu/mnch-nav-links.tsx +42 -0
  677. package/src/side-nav-menu/nav-link-config.ts +1 -5
  678. package/src/side-nav-menu/specialized-clinics-nav-link-config.ts +36 -0
  679. package/src/side-nav-menu/specialized-clinics-nav-links.tsx +42 -0
  680. package/src/specialized-clinics/critital-care-unit/critical-care-unit-queues.component.scss +7 -0
  681. package/src/specialized-clinics/critital-care-unit/critical-care-unit-queues.component.tsx +36 -0
  682. package/src/specialized-clinics/critital-care-unit/queues/consultation/critical-care-unit-consultation.tsx +15 -0
  683. package/src/specialized-clinics/critital-care-unit/queues/triage/critical-care-unit-triage.tsx +15 -0
  684. package/src/specialized-clinics/dental/dental-queues.component.scss +7 -0
  685. package/src/specialized-clinics/dental/dental-queues.component.tsx +36 -0
  686. package/src/specialized-clinics/dental/queues/consultation/dental-consultation.tsx +15 -0
  687. package/src/specialized-clinics/dental/queues/triage/dental-triage.tsx +15 -0
  688. package/src/specialized-clinics/diagnostic-and-imaging/diagnostic-and-imaging.component.scss +7 -0
  689. package/src/specialized-clinics/diagnostic-and-imaging/diagnostic-and-imaging.component.tsx +36 -0
  690. package/src/specialized-clinics/diagnostic-and-imaging/queues/consultation/diagnosis-and-imaging-consultation.tsx +15 -0
  691. package/src/specialized-clinics/diagnostic-and-imaging/queues/triage/diagnosis-and-imaging-triage.tsx +15 -0
  692. package/src/specialized-clinics/oncology/oncology-queues.component.scss +7 -0
  693. package/src/specialized-clinics/oncology/oncology-queues.component.tsx +36 -0
  694. package/src/specialized-clinics/oncology/queues/consultation/oncology-consultation.tsx +15 -0
  695. package/src/specialized-clinics/oncology/queues/triage/oncology-triage.tsx +15 -0
  696. package/src/specialized-clinics/ophthalmology/ophthalmology-queues.component.scss +7 -0
  697. package/src/specialized-clinics/ophthalmology/ophthalmology-queues.component.tsx +36 -0
  698. package/src/specialized-clinics/ophthalmology/queues/consultation/ophthalmology-consultation.tsx +15 -0
  699. package/src/specialized-clinics/ophthalmology/queues/triage/ophthalmology-triage.tsx +15 -0
  700. package/src/specialized-clinics/psychiatry/psychiatry-queues.component.scss +7 -0
  701. package/src/specialized-clinics/psychiatry/psychiatry-queues.component.tsx +36 -0
  702. package/src/specialized-clinics/psychiatry/queues/consultation/psychiatry-consultation.tsx +15 -0
  703. package/src/specialized-clinics/psychiatry/queues/triage/psychiatry-triage.tsx +15 -0
  704. package/src/specialized-clinics/renal/queues/consultation/dialysis-consultation.tsx +15 -0
  705. package/src/specialized-clinics/renal/queues/triage/renal-triage.tsx +15 -0
  706. package/src/specialized-clinics/renal/renal-queues.component.scss +7 -0
  707. package/src/specialized-clinics/renal/renal-queues.component.tsx +36 -0
  708. package/src/specialized-clinics/specialized-clinics-root.tsx +27 -0
  709. package/src/triage/triage.component.scss +6 -0
  710. package/src/triage/triage.component.tsx +4 -0
  711. package/src/types/types.ts +56 -1
  712. package/webpack.config.js +54 -1
  713. package/dist/104.js +0 -2
  714. package/dist/104.js.map +0 -1
  715. package/dist/15.js +0 -1
  716. package/dist/15.js.map +0 -1
  717. package/dist/184.js +0 -2
  718. package/dist/184.js.map +0 -1
  719. package/dist/197.js +0 -1
  720. package/dist/255.js +0 -1
  721. package/dist/255.js.map +0 -1
  722. package/dist/300.js +0 -1
  723. package/dist/335.js +0 -1
  724. package/dist/339.js +0 -1
  725. package/dist/339.js.map +0 -1
  726. package/dist/353.js +0 -1
  727. package/dist/353.js.map +0 -1
  728. package/dist/420.js +0 -1
  729. package/dist/420.js.map +0 -1
  730. package/dist/540.js +0 -2
  731. package/dist/540.js.map +0 -1
  732. package/dist/55.js +0 -1
  733. package/dist/652.js +0 -1
  734. package/dist/709.js +0 -1
  735. package/dist/709.js.map +0 -1
  736. package/dist/710.js +0 -2
  737. package/dist/710.js.map +0 -1
  738. package/dist/729.js +0 -1
  739. package/dist/729.js.map +0 -1
  740. package/dist/752.js +0 -1
  741. package/dist/752.js.map +0 -1
  742. package/dist/833.js +0 -1
  743. package/dist/833.js.map +0 -1
  744. package/dist/907.js +0 -1
  745. package/dist/907.js.map +0 -1
  746. package/dist/91.js +0 -1
  747. package/dist/91.js.map +0 -1
  748. package/dist/93.js +0 -1
  749. package/dist/93.js.map +0 -1
  750. package/dist/943.js +0 -1
  751. package/dist/943.js.map +0 -1
  752. package/dist/99.js +0 -1
  753. /package/dist/{104.js.LICENSE.txt → 2177.js.LICENSE.txt} +0 -0
  754. /package/dist/{810.js.LICENSE.txt → 262.js.LICENSE.txt} +0 -0
  755. /package/dist/{184.js.LICENSE.txt → 3184.js.LICENSE.txt} +0 -0
  756. /package/dist/{540.js.LICENSE.txt → 6540.js.LICENSE.txt} +0 -0
  757. /package/dist/{710.js.LICENSE.txt → 7830.js.LICENSE.txt} +0 -0
  758. /package/src/{service-queues/service-queue/stats → shared/ui}/stat-card/stat-card.component.scss +0 -0
@@ -0,0 +1,1806 @@
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 { showSnackbar, useSession, type DefaultWorkspaceProps } from '@openmrs/esm-framework';
20
+ import { useTranslation } from 'react-i18next';
21
+ import dayjs from 'dayjs';
22
+ import {
23
+ createPreauth,
24
+ fetchShaInterventionByCode,
25
+ pollPreauthUntilSubmitted,
26
+ preauthAttachmentFieldName,
27
+ type PreauthFormPayload,
28
+ } from '../../../../claims/claims.resource';
29
+ import { cancelAllPendingAuthorizations, sendClaimsOTP, authorizeClaimsWithOtp } from '../../../../registry/hie.resource';
30
+ import { addClaimDiagnosis, fetchPatientDiagnosesForBilling, preferredDiagnosisForPreauth } from '../../../billing-claims.resource';
31
+ import { ensureInterventionOnVisit } from '../../../../claims/interventions.resource';
32
+ import { type AmrsVisitDiagnosis } from '../../../types';
33
+ import { type PatientFacilityBillDetails } from '../types';
34
+ import PreauthAttachments, { type PreauthAttachmentRow } from './preauth-attachments.component';
35
+ import {
36
+ billingDateToVisitDate,
37
+ dateToServiceIso,
38
+ fetchPreauthFormValues,
39
+ mergeSpecialtyFlags,
40
+ preauthFormLabel,
41
+ readSpecialtyFlags,
42
+ resolveUnitPriceFromPatientBills,
43
+ searchDiagnosisConcepts,
44
+ searchHealthWorkerRegistry,
45
+ searchOpenMrsProviders,
46
+ storePreauthCode,
47
+ type DiagnosisConceptHit,
48
+ type HwrSearchResult,
49
+ type OpenMrsProviderHit,
50
+ type PreauthFormFieldKey,
51
+ type PreauthInterventionProps,
52
+ } from './preauth.resource';
53
+ import styles from './preauth.workspace.scss';
54
+
55
+ export type { PreauthInterventionProps };
56
+
57
+ /** ComboBox row: visit diagnosis (ETL) or concept-dictionary hit. */
58
+ type DiagnosisPick =
59
+ | { kind: 'visit'; key: string; dx: AmrsVisitDiagnosis }
60
+ | { kind: 'concept'; key: string; hit: DiagnosisConceptHit };
61
+
62
+ const visitDxPick = (dx: AmrsVisitDiagnosis): DiagnosisPick => ({
63
+ kind: 'visit',
64
+ key: `visit-${dx.encounter_id}-${dx.icd11_code}-${dx.diagnosis_coded ?? dx.value_coded ?? ''}`,
65
+ dx,
66
+ });
67
+
68
+ const conceptDxPick = (hit: DiagnosisConceptHit): DiagnosisPick => ({
69
+ kind: 'concept',
70
+ key: `concept-${hit.uuid}-${hit.icd11Code}`,
71
+ hit,
72
+ });
73
+
74
+ const diagnosisPickLabel = (item: DiagnosisPick | null) => {
75
+ if (!item) return '';
76
+ if (item.kind === 'visit') {
77
+ const d = item.dx;
78
+ const rank =
79
+ d.dx_rank != null && Number.isFinite(Number(d.dx_rank)) ? ` · Rank ${Number(d.dx_rank)}` : '';
80
+ return `${d.icd11_code ?? '—'} · ${d.concept_source_name || d.encounter_type || 'Visit diagnosis'}${rank}`;
81
+ }
82
+ return `${item.hit.icd11Code} · ${item.hit.display}`;
83
+ };
84
+
85
+ const diagnosisPickCode = (item: DiagnosisPick | null) => {
86
+ if (!item) return '';
87
+ return item.kind === 'visit' ? item.dx.icd11_code ?? '' : item.hit.icd11Code;
88
+ };
89
+
90
+ const DEFAULT_DOCTOR_ID_TYPE = 'National ID' as const;
91
+
92
+ type FormFieldLoadStatus = 'idle' | 'loading' | 'from_form' | 'missing';
93
+
94
+ const FORM_MISSING_HINT =
95
+ 'Missing on the Pre-authorization form. Complete the form on the patient chart, then reopen Raise preauth.';
96
+
97
+ const SURGICAL_FORM_KEYS: PreauthFormFieldKey[] = [
98
+ 'chiefComplaint',
99
+ 'hpi',
100
+ 'physicalExam',
101
+ 'investigations',
102
+ 'anaesthesia',
103
+ 'surgeryDate',
104
+ 'relatedToEmployment',
105
+ 'relatedToAccident',
106
+ 'isCoInsured',
107
+ 'coInsuranceDetails',
108
+ ];
109
+
110
+ const RENAL_FORM_KEYS: PreauthFormFieldKey[] = [
111
+ 'clinicalIndications',
112
+ 'startDate',
113
+ 'sessionsRequired',
114
+ 'frequency',
115
+ 'isCoInsured',
116
+ 'coInsuranceDetails',
117
+ ];
118
+
119
+ interface PreauthWorkspaceProps extends DefaultWorkspaceProps {
120
+ consentToken: string;
121
+ patientUuid?: string;
122
+ locationUuid: string;
123
+ /** Elective (pre-visit) mode — uses authorize token + expected_service_start_date */
124
+ isElective?: boolean;
125
+ billItem: Partial<PatientFacilityBillDetails> & {
126
+ intervention_code: string;
127
+ patient_uuid?: string;
128
+ cr_no?: string;
129
+ service_type?: string;
130
+ };
131
+ intervention: PreauthInterventionProps;
132
+ onSuccess?: (result: { consentToken: string; preauthCode?: string; status: string }) => void;
133
+ }
134
+
135
+ const ANAESTHESIA = ['GENERAL', 'LOCAL', 'SPINAL', 'SEDATION'];
136
+ const FREQUENCY = ['TWICE_A_WEEK', 'ONCE_A_WEEK', 'ONCE_EVERY_2_WEEKS', 'ONCE_EVERY_3_WEEKS', 'ONCE_A_MONTH'];
137
+ const STAGING = ['STAGE_1', 'STAGE_2', 'STAGE_3', 'STAGE_4'];
138
+ const METASTASES = ['LUNG', 'BRAIN', 'LIVER', 'OTHER'];
139
+ const TREATMENT = ['DAY_WARD', 'RECLINING_CHAIR', 'SIDE_ROOM'];
140
+ const LENS = ['FRAMES_LENSES', 'FRAMED', 'CONTACT'];
141
+ const NEW_OR_REPL = ['NEW', 'REPLACEMENT'];
142
+
143
+ const DOC_TYPE_OPTIONS = [
144
+ 'LAB_TESTS',
145
+ 'LAB_RESULTS',
146
+ 'DISCHARGE_SUMMARY',
147
+ 'INVOICE',
148
+ 'FINAL_BILL',
149
+ 'CLINICAL_DOCUMENTATION',
150
+ 'MEDICAL_REPORT',
151
+ 'IMAGING_RESULT',
152
+ 'RADIOLOGICAL_EXAM',
153
+ 'STAGING_RESULTS',
154
+ 'TREATMENT_PLAN',
155
+ 'THEATRE_LIST',
156
+ 'DIALYSIS_CHART',
157
+ 'PREAUTH_FORM',
158
+ 'OTHER',
159
+ ];
160
+
161
+ const toIsoLocal = (d: Date = new Date()) => dayjs(d).format('YYYY-MM-DDTHH:mm:ssZ');
162
+
163
+ /** HIE regulation bodies (abbreviated): COC = Clinical Officers Council, NCK = Nursing Council of Kenya */
164
+ const REGULATION_BODIES = ['KMPDC', 'COC', 'NCK'] as const;
165
+ type RegulationBody = (typeof REGULATION_BODIES)[number];
166
+
167
+ const normalizeRegulationBody = (value?: string | null): RegulationBody => {
168
+ if (!value) return 'KMPDC';
169
+ const raw = value.trim();
170
+ const exact = REGULATION_BODIES.find((b) => b.toLowerCase() === raw.toLowerCase());
171
+ if (exact) return exact;
172
+ const upper = raw.toUpperCase();
173
+ if (upper.includes('KMPDC') || upper.includes('MEDICAL PRACTITIONER') || upper.includes('DOCTOR')) {
174
+ return 'KMPDC';
175
+ }
176
+ if (
177
+ upper.includes('CLINICAL OFFICER') ||
178
+ upper === 'COC' ||
179
+ upper.includes('CLINICAL OFFICERS COUNCIL')
180
+ ) {
181
+ return 'COC';
182
+ }
183
+ if (upper.includes('NURS') || upper === 'NCK' || upper.includes('NURSING COUNCIL')) {
184
+ return 'NCK';
185
+ }
186
+ return 'KMPDC';
187
+ };
188
+
189
+ const PreauthForm: React.FC<PreauthWorkspaceProps> = ({
190
+ closeWorkspace,
191
+ promptBeforeClosing,
192
+ consentToken: consentTokenProp,
193
+ patientUuid,
194
+ locationUuid,
195
+ isElective = false,
196
+ billItem,
197
+ intervention,
198
+ onSuccess,
199
+ }) => {
200
+ const { t } = useTranslation();
201
+ const session = useSession();
202
+ const [dirty, setDirty] = useState(false);
203
+ const [submitting, setSubmitting] = useState(false);
204
+ const [polling, setPolling] = useState(false);
205
+ const [consentMethod, setConsentMethod] = useState<'biometric' | 'otp'>('otp');
206
+ const [consentDone, setConsentDone] = useState(Boolean(consentTokenProp) && !isElective);
207
+ const [otpSent, setOtpSent] = useState(false);
208
+ const [otp, setOtp] = useState('');
209
+ const [sendingOtp, setSendingOtp] = useState(false);
210
+ const [activeConsentToken, setActiveConsentToken] = useState(consentTokenProp || '');
211
+ const [expectedServiceStartDate, setExpectedServiceStartDate] = useState(toIsoLocal());
212
+ const abortRef = useRef<AbortController | null>(null);
213
+
214
+ // Specialty from launch props + bill item; SHA coverage may enrich after mount
215
+ // (visit/claim payloads often omit requires_*_preauth even for oncology codes).
216
+ const [specialty, setSpecialty] = useState(() =>
217
+ mergeSpecialtyFlags(readSpecialtyFlags(intervention), readSpecialtyFlags(billItem)),
218
+ );
219
+ const specialtyLabel = preauthFormLabel(specialty);
220
+ const interventionForSubmit = useMemo(
221
+ () => ({
222
+ ...intervention,
223
+ ...specialty,
224
+ }),
225
+ [intervention, specialty],
226
+ );
227
+
228
+ const [serviceStart, setServiceStart] = useState(toIsoLocal());
229
+ const [serviceEnd, setServiceEnd] = useState(toIsoLocal(dayjs().add(30, 'minute').toDate()));
230
+ const [providerEmail, setProviderEmail] = useState(session?.user?.username?.includes('@') ? session.user.username : '');
231
+ const [unitPrice, setUnitPrice] = useState(() =>
232
+ String(billItem.item_price ?? billItem.item_total_price ?? '').trim(),
233
+ );
234
+
235
+ // Diagnosis: prefill from ETL encounter-diagnosis; search uses concept dictionary (ICD-11).
236
+ const [visitDiagnoses, setVisitDiagnoses] = useState<AmrsVisitDiagnosis[]>([]);
237
+ const [conceptDxHits, setConceptDxHits] = useState<DiagnosisConceptHit[]>([]);
238
+ const [loadingDx, setLoadingDx] = useState(false);
239
+ const [searchingDx, setSearchingDx] = useState(false);
240
+ const [selectedDx, setSelectedDx] = useState<DiagnosisPick | null>(null);
241
+ const [icdCode, setIcdCode] = useState('');
242
+ const dxSearchTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
243
+
244
+ // Provider — National ID for doctor; HWR for regulation body
245
+ const [providerHits, setProviderHits] = useState<OpenMrsProviderHit[]>([]);
246
+ const [searchingProviders, setSearchingProviders] = useState(false);
247
+ const [selectedProvider, setSelectedProvider] = useState<OpenMrsProviderHit | null>(null);
248
+ const providerSearchTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
249
+ const [searchingHwr, setSearchingHwr] = useState(false);
250
+ const [hwrHit, setHwrHit] = useState<HwrSearchResult | null>(null);
251
+ const [doctorId, setDoctorId] = useState('');
252
+ const [regulationBody, setRegulationBody] = useState<RegulationBody>('KMPDC');
253
+
254
+ // Specialty fields — empty until Pre-authorization form obs (or bill unit price) loads.
255
+ const [clinicalIndications, setClinicalIndications] = useState('');
256
+ const [formLoadState, setFormLoadState] = useState<'idle' | 'loading' | 'done'>('idle');
257
+ const [formFound, setFormFound] = useState<Set<PreauthFormFieldKey>>(() => new Set());
258
+ const [formRelevant, setFormRelevant] = useState<Set<PreauthFormFieldKey>>(() => new Set());
259
+ const [chiefComplaint, setChiefComplaint] = useState('');
260
+ const [vitalSigns, setVitalSigns] = useState('');
261
+ const [hpi, setHpi] = useState('');
262
+ const [physicalExam, setPhysicalExam] = useState('');
263
+ const [investigations, setInvestigations] = useState('');
264
+ const [anaesthesia, setAnaesthesia] = useState('');
265
+ const [surgeryDate, setSurgeryDate] = useState('');
266
+ const [sessionsRequired, setSessionsRequired] = useState('');
267
+ const [costPerSession, setCostPerSession] = useState('');
268
+ const [frequency, setFrequency] = useState('');
269
+ const [startDate, setStartDate] = useState('');
270
+ const [isCoInsured, setIsCoInsured] = useState(false);
271
+ const [necessity, setNecessity] = useState('');
272
+ const [lensPrescription, setLensPrescription] = useState('');
273
+ const [lensAmount, setLensAmount] = useState('');
274
+ const [eyeExamAmount, setEyeExamAmount] = useState('');
275
+ const [frameAmount, setFrameAmount] = useState('');
276
+ const [newOrReplacement, setNewOrReplacement] = useState('');
277
+ const [carcinomaStaging, setCarcinomaStaging] = useState('');
278
+ const [comorbidity, setComorbidity] = useState('');
279
+ const [metastases, setMetastases] = useState('');
280
+ const [treatmentSetting, setTreatmentSetting] = useState('');
281
+ const [progressReport, setProgressReport] = useState('');
282
+ const [relatedToEmployment, setRelatedToEmployment] = useState(false);
283
+ const [relatedToAccident, setRelatedToAccident] = useState(false);
284
+ const [coInsuranceDetails, setCoInsuranceDetails] = useState('');
285
+
286
+ const formFieldStatus = (key: PreauthFormFieldKey): FormFieldLoadStatus => {
287
+ if (formLoadState === 'idle') return 'idle';
288
+ if (formLoadState === 'loading') return 'loading';
289
+ if (!formRelevant.has(key)) return 'idle';
290
+ return formFound.has(key) ? 'from_form' : 'missing';
291
+ };
292
+
293
+ const formFieldLocked = (key: PreauthFormFieldKey) => {
294
+ const s = formFieldStatus(key);
295
+ return s === 'from_form' || s === 'missing' || s === 'loading';
296
+ };
297
+
298
+ const formFieldInvalid = (key: PreauthFormFieldKey) => formFieldStatus(key) === 'missing';
299
+
300
+ const patientName = billItem.patient_name ?? '';
301
+ const crNo = billItem.cr_no ?? '';
302
+ const billableService = billItem.billable_service ?? intervention.name ?? intervention.code;
303
+ const requiredDocs = useMemo(
304
+ () => [...new Set(intervention.requiredPreauthDocumentTypes ?? [])],
305
+ [intervention.requiredPreauthDocumentTypes],
306
+ );
307
+ const optionalDocs = useMemo(() => {
308
+ const required = new Set(requiredDocs);
309
+ return [...new Set(intervention.applicableDocumentTypes ?? [])].filter((d) => !required.has(d));
310
+ }, [intervention.applicableDocumentTypes, requiredDocs]);
311
+
312
+ const [attachments, setAttachments] = useState<PreauthAttachmentRow[]>(() => {
313
+ const required = requiredDocs.map((document_type) => ({
314
+ id: crypto.randomUUID(),
315
+ document_type,
316
+ document_title: document_type.replace(/_/g, ' '),
317
+ required: true,
318
+ }));
319
+ if (required.length === 0) {
320
+ return [
321
+ {
322
+ id: crypto.randomUUID(),
323
+ document_type: 'LAB_TESTS',
324
+ document_title: 'Lab Results',
325
+ required: false,
326
+ },
327
+ ];
328
+ }
329
+ return required;
330
+ });
331
+
332
+ useEffect(() => {
333
+ // Normal preauth requires an existing claim token. Elective obtains one via authorize.
334
+ if (!isElective && !consentTokenProp) {
335
+ showSnackbar({
336
+ kind: 'error',
337
+ title: t('missingConsentToken', 'Missing claim token'),
338
+ subtitle: t('missingConsentTokenDetail', 'A preexisting visit claim token is required to raise preauth.'),
339
+ });
340
+ closeWorkspace?.();
341
+ }
342
+ }, [consentTokenProp, isElective, closeWorkspace, t]);
343
+
344
+ const consentToken = activeConsentToken;
345
+
346
+ // Enrich specialty flags from SHA interventions coverage when launch props lack them.
347
+ useEffect(() => {
348
+ const patientId = (billItem.cr_no ?? '').trim();
349
+ const code = (intervention.code || billItem.intervention_code || '').trim();
350
+ if (!patientId || !locationUuid || !code) return;
351
+
352
+ let cancelled = false;
353
+ (async () => {
354
+ try {
355
+ const sha = await fetchShaInterventionByCode(patientId, locationUuid, code);
356
+ if (cancelled || !sha) return;
357
+ const fromSha = readSpecialtyFlags(sha);
358
+ setSpecialty((prev) => {
359
+ const next = mergeSpecialtyFlags(prev, fromSha);
360
+ if (
361
+ next.requiresSurgicalPreauth === prev.requiresSurgicalPreauth &&
362
+ next.requiresRenalPreauth === prev.requiresRenalPreauth &&
363
+ next.requiresOncologyPreauth === prev.requiresOncologyPreauth &&
364
+ next.requiresRadiologyPreauth === prev.requiresRadiologyPreauth &&
365
+ next.requiresOpticalPreauth === prev.requiresOpticalPreauth
366
+ ) {
367
+ return prev;
368
+ }
369
+ return next;
370
+ });
371
+ // Do not seed specialty field defaults — obs / bill loaders fill real values.
372
+ } catch {
373
+ // Keep launch-prop flags if coverage lookup fails
374
+ }
375
+ })();
376
+
377
+ return () => {
378
+ cancelled = true;
379
+ };
380
+ }, [billItem.cr_no, billItem.intervention_code, intervention.code, locationUuid]);
381
+
382
+ useEffect(() => {
383
+ promptBeforeClosing?.(() => dirty || submitting || polling);
384
+ }, [dirty, submitting, polling, promptBeforeClosing]);
385
+
386
+ useEffect(() => () => {
387
+ abortRef.current?.abort();
388
+ if (providerSearchTimer.current) clearTimeout(providerSearchTimer.current);
389
+ if (dxSearchTimer.current) clearTimeout(dxSearchTimer.current);
390
+ }, []);
391
+
392
+ const markDirty = () => setDirty(true);
393
+
394
+ const applyDiagnosisPick = (pick: DiagnosisPick | null, opts?: { fromUser?: boolean }) => {
395
+ // Prefill from visit load must not trip "unsaved changes" on close.
396
+ if (opts?.fromUser !== false) {
397
+ markDirty();
398
+ }
399
+ setSelectedDx(pick);
400
+ const code = diagnosisPickCode(pick);
401
+ if (code) {
402
+ setIcdCode(code);
403
+ }
404
+ if (pick?.kind === 'visit') {
405
+ const dx = pick.dx;
406
+ if (dx.practioner_nat_id) {
407
+ setDoctorId(dx.practioner_nat_id);
408
+ }
409
+ if (dx.practitioner_body) {
410
+ setRegulationBody(normalizeRegulationBody(dx.practitioner_body));
411
+ }
412
+ }
413
+ };
414
+
415
+ // Prefill from visit + maternity + encounter diagnoses (same three ETL sources as bill details).
416
+ useEffect(() => {
417
+ const uuid = patientUuid || billItem.patient_uuid;
418
+ if (!uuid || !locationUuid) return;
419
+ let cancelled = false;
420
+ const run = async () => {
421
+ setLoadingDx(true);
422
+ try {
423
+ const visitDate = billingDateToVisitDate(billItem.bill_date);
424
+ const billingDate = visitDate;
425
+ const results = await fetchPatientDiagnosesForBilling({
426
+ visitDate,
427
+ billingDate,
428
+ patientUuid: uuid,
429
+ locationUuid,
430
+ });
431
+ if (!cancelled) {
432
+ setVisitDiagnoses(results ?? []);
433
+ // Prefer dx_rank === 1; otherwise best-ranked ICD-coded row. Multiple options
434
+ // stay available in the ComboBox (already ordered by rank from the fetch).
435
+ const preferred = preferredDiagnosisForPreauth(results ?? []);
436
+ if (preferred) {
437
+ applyDiagnosisPick(visitDxPick(preferred), { fromUser: false });
438
+ }
439
+ }
440
+ } catch {
441
+ if (!cancelled) {
442
+ showSnackbar({
443
+ kind: 'warning',
444
+ title: 'Could not load diagnoses',
445
+ subtitle: 'Search the concept dictionary, or retry after the visit has ICD-11 coded diagnoses.',
446
+ });
447
+ }
448
+ } finally {
449
+ if (!cancelled) setLoadingDx(false);
450
+ }
451
+ };
452
+ run();
453
+ return () => {
454
+ cancelled = true;
455
+ };
456
+ // eslint-disable-next-line react-hooks/exhaustive-deps
457
+ }, [patientUuid, billItem.patient_uuid, billItem.bill_date, locationUuid]);
458
+
459
+ const diagnosisItems = useMemo((): DiagnosisPick[] => {
460
+ const base =
461
+ conceptDxHits.length > 0
462
+ ? conceptDxHits.map(conceptDxPick)
463
+ : visitDiagnoses.filter((d) => d.icd11_code).map(visitDxPick);
464
+ if (!selectedDx) return base;
465
+ if (!base.some((i) => i.key === selectedDx.key)) {
466
+ return [selectedDx, ...base];
467
+ }
468
+ return base.map((i) => (i.key === selectedDx.key ? selectedDx : i));
469
+ }, [conceptDxHits, visitDiagnoses, selectedDx]);
470
+
471
+ const handleDiagnosisInputChange = (inputValue: string) => {
472
+ const selectedLabel = diagnosisPickLabel(selectedDx);
473
+ if (inputValue === selectedLabel) {
474
+ return;
475
+ }
476
+ if (selectedDx) {
477
+ setSelectedDx(null);
478
+ }
479
+ if (dxSearchTimer.current) {
480
+ clearTimeout(dxSearchTimer.current);
481
+ }
482
+ const q = (inputValue ?? '').trim();
483
+ if (q.length < 2) {
484
+ setConceptDxHits([]);
485
+ setSearchingDx(false);
486
+ return;
487
+ }
488
+ dxSearchTimer.current = setTimeout(async () => {
489
+ setSearchingDx(true);
490
+ try {
491
+ const hits = await searchDiagnosisConcepts(q);
492
+ setConceptDxHits(hits);
493
+ } catch {
494
+ setConceptDxHits([]);
495
+ } finally {
496
+ setSearchingDx(false);
497
+ }
498
+ }, 300);
499
+ };
500
+ // Resolve unit_price from patient facility bill lines (match intervention + service name).
501
+ useEffect(() => {
502
+ const uuid = patientUuid || billItem.patient_uuid;
503
+ const code = (intervention.code || billItem.intervention_code || '').trim();
504
+ if (!uuid || !locationUuid || !code) return;
505
+
506
+ let cancelled = false;
507
+ (async () => {
508
+ const { unitPrice: fromBills, billLine } = await resolveUnitPriceFromPatientBills({
509
+ patientUuid: uuid,
510
+ locationUuid,
511
+ billingDate: billItem.bill_date,
512
+ interventionCode: code,
513
+ serviceHint: billItem.billable_service || intervention.name || code,
514
+ });
515
+ if (cancelled || !fromBills) return;
516
+ setUnitPrice(fromBills);
517
+ setCostPerSession((prev) => (prev.trim() ? prev : fromBills));
518
+ // Prefer matched billable_service label when launch used intervention name only
519
+ if (billLine?.billable_service && !(billItem.billable_service || '').trim()) {
520
+ // billItem is a prop — display uses billableService derived from it; unit price is enough
521
+ }
522
+ })();
523
+
524
+ return () => {
525
+ cancelled = true;
526
+ };
527
+ }, [
528
+ patientUuid,
529
+ billItem.patient_uuid,
530
+ billItem.bill_date,
531
+ billItem.intervention_code,
532
+ billItem.billable_service,
533
+ intervention.code,
534
+ intervention.name,
535
+ locationUuid,
536
+ specialty.requiresRenalPreauth,
537
+ ]);
538
+
539
+ // Prefill specialty fields from POC Pre-authorization form (encounter, else latest obs).
540
+ useEffect(() => {
541
+ const needsForm =
542
+ specialty.requiresSurgicalPreauth ||
543
+ specialty.requiresRenalPreauth ||
544
+ specialty.requiresRadiologyPreauth ||
545
+ specialty.requiresOpticalPreauth;
546
+ const uuid = patientUuid || billItem.patient_uuid;
547
+ if (!needsForm || !uuid) {
548
+ setFormLoadState('idle');
549
+ setFormFound(new Set());
550
+ setFormRelevant(new Set());
551
+ return;
552
+ }
553
+
554
+ let cancelled = false;
555
+ setFormLoadState('loading');
556
+ (async () => {
557
+ const values = await fetchPreauthFormValues(uuid);
558
+ if (cancelled) return;
559
+
560
+ // Apply every mapped value found on the form — do not gate on specialty flags here.
561
+ // Specialty only controls which keys are required / shown as missing below.
562
+ // (Gating on flags raced with SHA enrichment and skipped renal fields.)
563
+ if (values.found.has('clinicalIndications')) {
564
+ setClinicalIndications(values.clinicalIndications);
565
+ }
566
+ if (values.found.has('startDate')) setStartDate(values.startDate);
567
+ if (values.found.has('sessionsRequired')) setSessionsRequired(values.sessionsRequired);
568
+ if (values.found.has('frequency')) setFrequency(values.frequency);
569
+ if (values.found.has('chiefComplaint')) setChiefComplaint(values.chiefComplaint);
570
+ if (values.found.has('hpi')) setHpi(values.hpi);
571
+ if (values.found.has('physicalExam')) setPhysicalExam(values.physicalExam);
572
+ if (values.found.has('investigations')) setInvestigations(values.investigations);
573
+ if (values.found.has('anaesthesia')) setAnaesthesia(values.anaesthesia);
574
+ if (values.found.has('surgeryDate')) setSurgeryDate(values.surgeryDate);
575
+ if (values.found.has('relatedToEmployment') && values.relatedToEmployment !== null) {
576
+ setRelatedToEmployment(values.relatedToEmployment);
577
+ }
578
+ if (values.found.has('relatedToAccident') && values.relatedToAccident !== null) {
579
+ setRelatedToAccident(values.relatedToAccident);
580
+ }
581
+ if (values.found.has('isCoInsured') && values.isCoInsured !== null) {
582
+ setIsCoInsured(values.isCoInsured);
583
+ }
584
+ if (values.found.has('coInsuranceDetails')) {
585
+ setCoInsuranceDetails(values.coInsuranceDetails);
586
+ }
587
+
588
+ // Always prefer bill line price resolved from facility patient bills (see resolve effect).
589
+ // Do not overwrite with launch billItem.item_price (often keph tariff / wrong line).
590
+
591
+ const relevant = new Set<PreauthFormFieldKey>();
592
+ if (
593
+ specialty.requiresRadiologyPreauth ||
594
+ specialty.requiresOpticalPreauth ||
595
+ specialty.requiresRenalPreauth
596
+ ) {
597
+ relevant.add('clinicalIndications');
598
+ }
599
+ if (specialty.requiresRenalPreauth) {
600
+ RENAL_FORM_KEYS.forEach((k) => relevant.add(k));
601
+ }
602
+ if (specialty.requiresSurgicalPreauth) {
603
+ SURGICAL_FORM_KEYS.forEach((k) => relevant.add(k));
604
+ }
605
+ // coInsuranceDetails only required when patient is co-insured
606
+ if (values.isCoInsured !== true) {
607
+ relevant.delete('coInsuranceDetails');
608
+ }
609
+
610
+ setFormRelevant(relevant);
611
+ setFormFound(new Set([...relevant].filter((k) => values.found.has(k))));
612
+ setFormLoadState('done');
613
+ })();
614
+
615
+ return () => {
616
+ cancelled = true;
617
+ };
618
+ }, [
619
+ patientUuid,
620
+ billItem.patient_uuid,
621
+ specialty.requiresSurgicalPreauth,
622
+ specialty.requiresRenalPreauth,
623
+ specialty.requiresRadiologyPreauth,
624
+ specialty.requiresOpticalPreauth,
625
+ ]);
626
+
627
+ const clinicalIndicationsFieldProps = {
628
+ labelText: 'Clinical indications',
629
+ value: formFieldStatus('clinicalIndications') === 'loading' ? '' : clinicalIndications,
630
+ readOnly: formFieldLocked('clinicalIndications'),
631
+ placeholder: formFieldStatus('clinicalIndications') === 'loading' ? 'Loading clinical notes…' : undefined,
632
+ invalid: formFieldInvalid('clinicalIndications'),
633
+ invalidText: formFieldInvalid('clinicalIndications') ? FORM_MISSING_HINT : undefined,
634
+ onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => {
635
+ if (formFieldLocked('clinicalIndications')) return;
636
+ markDirty();
637
+ setClinicalIndications(e.target.value);
638
+ },
639
+ };
640
+
641
+ const providerItemLabel = (item: OpenMrsProviderHit | null) =>
642
+ item ? (item.nationalId ? `${item.display} · ${item.nationalId}` : item.display) : '';
643
+
644
+ const applyProviderSelection = (hit: OpenMrsProviderHit | null) => {
645
+ setSelectedProvider(hit);
646
+ if (!hit) return;
647
+ markDirty();
648
+ if (hit.nationalId) {
649
+ setDoctorId(hit.nationalId);
650
+ void handleSearchHwr(hit.nationalId);
651
+ } else {
652
+ setDoctorId('');
653
+ setHwrHit(null);
654
+ showSnackbar({
655
+ kind: 'warning',
656
+ title: 'No National ID on provider',
657
+ subtitle: 'Enter the doctor National ID, then Search HWR for the regulation body.',
658
+ });
659
+ }
660
+ };
661
+
662
+ const handleSearchHwr = async (idOverride?: string) => {
663
+ const idValue = (idOverride ?? doctorId).trim();
664
+ if (!idValue) {
665
+ showSnackbar({
666
+ kind: 'error',
667
+ title: 'Enter National ID',
668
+ subtitle: 'Doctor National ID is required to look up the regulation body in HWR.',
669
+ });
670
+ return;
671
+ }
672
+ setSearchingHwr(true);
673
+ try {
674
+ const results = await searchHealthWorkerRegistry({
675
+ identifierType: DEFAULT_DOCTOR_ID_TYPE,
676
+ identifierValue: idValue,
677
+ locationUuid,
678
+ });
679
+ const hit = results[0];
680
+ if (!hit) {
681
+ setHwrHit(null);
682
+ showSnackbar({ kind: 'warning', title: 'No health worker found' });
683
+ return;
684
+ }
685
+ setHwrHit(hit);
686
+ // Keep doctor ID as National ID; only take regulation body (and email) from HWR
687
+ const body = normalizeRegulationBody(hit.membership?.licensing_body);
688
+ setRegulationBody(body);
689
+ if (hit.contacts?.email) {
690
+ setProviderEmail(hit.contacts.email);
691
+ }
692
+ markDirty();
693
+ showSnackbar({
694
+ kind: 'success',
695
+ title: 'Regulation body from HWR',
696
+ subtitle: `${hit.membership?.full_name || 'Match'} · ${body}`,
697
+ });
698
+ } catch (e: any) {
699
+ showSnackbar({ kind: 'error', title: 'HWR search failed', subtitle: String(e?.message ?? e) });
700
+ } finally {
701
+ setSearchingHwr(false);
702
+ }
703
+ };
704
+
705
+ const handleProviderInputChange = (inputValue: string) => {
706
+ const selectedLabel = providerItemLabel(selectedProvider);
707
+ if (inputValue === selectedLabel) {
708
+ return;
709
+ }
710
+ if (selectedProvider) {
711
+ setSelectedProvider(null);
712
+ }
713
+ if (providerSearchTimer.current) {
714
+ clearTimeout(providerSearchTimer.current);
715
+ }
716
+ if (!inputValue || inputValue.trim().length < 2) {
717
+ setProviderHits([]);
718
+ setSearchingProviders(false);
719
+ return;
720
+ }
721
+ providerSearchTimer.current = setTimeout(async () => {
722
+ setSearchingProviders(true);
723
+ try {
724
+ const hits = await searchOpenMrsProviders(inputValue);
725
+ setProviderHits(hits);
726
+ } catch (e: any) {
727
+ setProviderHits([]);
728
+ showSnackbar({ kind: 'error', title: 'Provider search failed', subtitle: String(e?.message ?? e) });
729
+ } finally {
730
+ setSearchingProviders(false);
731
+ }
732
+ }, 300);
733
+ };
734
+
735
+ const requiredAttachmentsReady = useMemo(() => {
736
+ return attachments.filter((a) => a.required).every((a) => Boolean(a.file));
737
+ }, [attachments]);
738
+
739
+ const handleSendOtp = async () => {
740
+ if (!crNo) {
741
+ showSnackbar({ kind: 'error', title: 'Missing CR number', subtitle: 'Cannot send OTP without patient CR id.' });
742
+ return;
743
+ }
744
+ setSendingOtp(true);
745
+ try {
746
+ await cancelAllPendingAuthorizations(locationUuid, crNo);
747
+ const response = await sendClaimsOTP(crNo, locationUuid, intervention.code);
748
+ if (response?.message?.includes('OTP') || response) {
749
+ setOtpSent(true);
750
+ showSnackbar({ kind: 'success', title: 'OTP sent' });
751
+ }
752
+ } catch (e: any) {
753
+ showSnackbar({ kind: 'error', title: 'Failed to send OTP', subtitle: String(e?.message ?? e) });
754
+ } finally {
755
+ setSendingOtp(false);
756
+ }
757
+ };
758
+
759
+ const handleVerifyOtp = async () => {
760
+ if (!otp || otp.length < 4) {
761
+ showSnackbar({ kind: 'error', title: 'Enter OTP' });
762
+ return;
763
+ }
764
+ if (isElective) {
765
+ if (!crNo) {
766
+ showSnackbar({ kind: 'error', title: 'Missing CR number', subtitle: 'Cannot authorize without patient CR id.' });
767
+ return;
768
+ }
769
+ setSendingOtp(true);
770
+ try {
771
+ const auth = await authorizeClaimsWithOtp({
772
+ patientId: crNo,
773
+ otp: otp.trim(),
774
+ interventions: [intervention.code],
775
+ serviceType: (billItem.service_type as string) || 'OUTPATIENT',
776
+ locationUuid,
777
+ });
778
+ const token = String(auth?.token ?? auth?.consent_token ?? '').trim();
779
+ if (!token) {
780
+ throw new Error('Authorize succeeded but no token was returned.');
781
+ }
782
+ setActiveConsentToken(token);
783
+ setConsentDone(true);
784
+ showSnackbar({ kind: 'success', title: 'Pre-visit authorization complete' });
785
+ } catch (e: any) {
786
+ showSnackbar({ kind: 'error', title: 'Authorize failed', subtitle: String(e?.message ?? e) });
787
+ } finally {
788
+ setSendingOtp(false);
789
+ }
790
+ return;
791
+ }
792
+ setConsentDone(true);
793
+ showSnackbar({ kind: 'success', title: 'OTP verified' });
794
+ };
795
+
796
+ const handleConfirmBiometric = () => {
797
+ if (isElective && !activeConsentToken) {
798
+ showSnackbar({
799
+ kind: 'info',
800
+ title: 'Use OTP for elective',
801
+ subtitle: 'Elective pre-visit authorize currently uses OTP. Biometrics authorize is available via the Claims widget.',
802
+ });
803
+ return;
804
+ }
805
+ setConsentDone(true);
806
+ showSnackbar({ kind: 'success', title: 'Biometric consent recorded' });
807
+ };
808
+
809
+ const handleAttachmentsChange = (updater: (prev: PreauthAttachmentRow[]) => PreauthAttachmentRow[]) => {
810
+ markDirty();
811
+ setAttachments(updater);
812
+ };
813
+
814
+ const addableDocTypes = useMemo(() => {
815
+ const attached = new Set(attachments.map((a) => a.document_type));
816
+ const base = optionalDocs.length > 0 ? optionalDocs : DOC_TYPE_OPTIONS;
817
+ return [...new Set(base)].filter((d) => !attached.has(d));
818
+ }, [attachments, optionalDocs]);
819
+
820
+ useEffect(
821
+ () => () => {
822
+ attachments.forEach((a) => {
823
+ if (a.previewUrl) URL.revokeObjectURL(a.previewUrl);
824
+ });
825
+ },
826
+ // eslint-disable-next-line react-hooks/exhaustive-deps
827
+ [],
828
+ );
829
+
830
+ const buildPayload = (): PreauthFormPayload => {
831
+ // Contiguous indexes: attachments[i] → attachments_i_file_blob
832
+ const withFiles = attachments.filter((a) => a.file);
833
+ const files: Record<string, File> = {};
834
+ const attachmentMeta = withFiles.map((a, index) => {
835
+ const field = preauthAttachmentFieldName(index);
836
+ files[field] = a.file!;
837
+ return {
838
+ document_title: a.document_title,
839
+ document_type: a.document_type,
840
+ file_field_name: field,
841
+ };
842
+ });
843
+
844
+ const billUnitPrice = String(billItem.item_price ?? billItem.item_total_price ?? unitPrice ?? '').trim();
845
+ const resolvedUnitPrice = billUnitPrice;
846
+
847
+ const payload: PreauthFormPayload = {
848
+ service_start: serviceStart,
849
+ service_end: serviceEnd,
850
+ items: [{ unit_price: resolvedUnitPrice || '0' }],
851
+ diagnoses: [{ consent_token: consentToken, icd_code: icdCode.trim() }],
852
+ doctors: [
853
+ {
854
+ identification_number: doctorId.trim(),
855
+ identification_type: DEFAULT_DOCTOR_ID_TYPE,
856
+ regulation_body: normalizeRegulationBody(regulationBody),
857
+ intervention_code: intervention.code,
858
+ is_primary: true,
859
+ },
860
+ ],
861
+ attachments: attachmentMeta,
862
+ provider_notification_email: providerEmail.trim(),
863
+ locationUuid,
864
+ files,
865
+ };
866
+
867
+ if (specialty.requiresSurgicalPreauth) {
868
+ payload.chief_complaint = chiefComplaint.trim();
869
+ payload.vital_signs = vitalSigns.trim();
870
+ payload.history_of_present_illness = hpi.trim();
871
+ payload.physical_examination = physicalExam.trim();
872
+ payload.investigation_report_details = investigations.trim();
873
+ payload.type_of_anaesthesia = anaesthesia;
874
+ payload.surgery_date = surgeryDate;
875
+ payload.is_condition_related_to_employment = relatedToEmployment;
876
+ payload.is_condition_related_to_auto_or_other_accident = relatedToAccident;
877
+ payload.is_co_insured = isCoInsured;
878
+ if (isCoInsured && coInsuranceDetails.trim()) {
879
+ payload.co_insurance_details = coInsuranceDetails.trim();
880
+ }
881
+ }
882
+
883
+ if (specialty.requiresRenalPreauth) {
884
+ const sessionsNum = Number(sessionsRequired);
885
+ payload.number_of_sessions_required = Number.isFinite(sessionsNum) ? sessionsNum : sessionsRequired;
886
+ payload.cost_per_session = String(costPerSession || billUnitPrice || '').trim();
887
+ payload.frequency_of_sessions = frequency;
888
+ payload.clinical_indications = clinicalIndications.trim();
889
+ payload.start_date = startDate;
890
+ payload.is_co_insured = isCoInsured;
891
+ if (isCoInsured && coInsuranceDetails.trim()) {
892
+ payload.co_insurance_details = coInsuranceDetails.trim();
893
+ }
894
+ }
895
+
896
+ if (specialty.requiresOpticalPreauth) {
897
+ payload.necessity_of_service = necessity.trim();
898
+ payload.lens_prescription = lensPrescription;
899
+ payload.lens_amount = lensAmount;
900
+ payload.eye_examination_amount = eyeExamAmount;
901
+ payload.frame_amount = frameAmount;
902
+ payload.new_or_replacement = newOrReplacement;
903
+ payload.clinical_indications = clinicalIndications.trim();
904
+ }
905
+
906
+ if (specialty.requiresOncologyPreauth) {
907
+ payload.carcinoma_staging = carcinomaStaging;
908
+ payload.comorbidity = comorbidity.trim();
909
+ // Always arrays — HIE: "Expected a JSON list for metastases and treatment_setting"
910
+ payload.metastases = [metastases];
911
+ payload.treatment_setting = [treatmentSetting];
912
+ {
913
+ const sessionsNum = Number(sessionsRequired);
914
+ payload.number_of_sessions_required = Number.isFinite(sessionsNum) ? sessionsNum : sessionsRequired;
915
+ }
916
+ payload.cost_per_session = costPerSession;
917
+ payload.is_co_insured = isCoInsured;
918
+ payload.start_date = startDate;
919
+ if (progressReport.trim()) {
920
+ payload.progress_report = progressReport.trim();
921
+ }
922
+ }
923
+
924
+ if (specialty.requiresRadiologyPreauth) {
925
+ payload.clinical_indications = clinicalIndications.trim();
926
+ }
927
+
928
+ if (isElective) {
929
+ payload.expected_service_start_date = expectedServiceStartDate;
930
+ }
931
+
932
+ return payload;
933
+ };
934
+
935
+ const handleSubmit = async () => {
936
+ if (!consentToken) {
937
+ showSnackbar({
938
+ kind: 'error',
939
+ title: 'Missing authorization',
940
+ subtitle: isElective
941
+ ? 'Complete pre-visit OTP authorize before submitting the elective preauth.'
942
+ : 'A claim token is required.',
943
+ });
944
+ return;
945
+ }
946
+ if (!consentDone) {
947
+ showSnackbar({ kind: 'error', title: 'Consent required', subtitle: 'Complete OTP or biometric consent first.' });
948
+ return;
949
+ }
950
+ const billUnitPrice = String(billItem.item_price ?? billItem.item_total_price ?? unitPrice ?? '').trim();
951
+ const resolvedUnitPrice = billUnitPrice;
952
+ const needsClinicalIndications =
953
+ specialty.requiresRadiologyPreauth ||
954
+ specialty.requiresRenalPreauth ||
955
+ specialty.requiresOpticalPreauth;
956
+ const missingFormFields = [...formRelevant].filter((k) => !formFound.has(k));
957
+ const missingRequired = [
958
+ !icdCode.trim() && 'ICD-11 diagnosis',
959
+ !doctorId.trim() && 'Doctor National ID',
960
+ !providerEmail.trim() && 'Provider notification email',
961
+ !resolvedUnitPrice && 'Unit price (from bill)',
962
+ isElective && !expectedServiceStartDate && 'Expected service start date',
963
+ needsClinicalIndications &&
964
+ !clinicalIndications.trim() &&
965
+ 'Clinical indications (complete Pre-authorization form on the patient chart)',
966
+ missingFormFields.length > 0 &&
967
+ `Pre-authorization form fields (${missingFormFields.join(', ')})`,
968
+ ].filter(Boolean);
969
+ if (missingRequired.length) {
970
+ showSnackbar({
971
+ kind: 'error',
972
+ title: 'Missing required fields',
973
+ subtitle: `Fill: ${missingRequired.join(', ')}`,
974
+ });
975
+ return;
976
+ }
977
+ if (!requiredAttachmentsReady) {
978
+ showSnackbar({
979
+ kind: 'error',
980
+ title: 'Attachments required',
981
+ subtitle: 'Generate or add a file for every required document, then Submit preauth.',
982
+ });
983
+ return;
984
+ }
985
+
986
+ setSubmitting(true);
987
+ abortRef.current = new AbortController();
988
+ try {
989
+ if (!isElective) {
990
+ await ensureInterventionOnVisit(consentToken, intervention.code, locationUuid);
991
+ }
992
+ const payload = buildPayload();
993
+ await createPreauth(
994
+ payload,
995
+ {
996
+ code: interventionForSubmit.code,
997
+ requiresRadiologyPreauth: interventionForSubmit.requiresRadiologyPreauth,
998
+ requiresOncologyPreauth: interventionForSubmit.requiresOncologyPreauth,
999
+ requiresOpticalPreauth: interventionForSubmit.requiresOpticalPreauth,
1000
+ requiresRenalPreauth: interventionForSubmit.requiresRenalPreauth,
1001
+ requiresSurgicalPreauth: interventionForSubmit.requiresSurgicalPreauth,
1002
+ },
1003
+ consentToken,
1004
+ );
1005
+
1006
+ setPolling(true);
1007
+ const polled = await pollPreauthUntilSubmitted(
1008
+ consentToken,
1009
+ locationUuid,
1010
+ intervention.code,
1011
+ { signal: abortRef.current.signal },
1012
+ );
1013
+ const status = polled.status;
1014
+ const preauthCode = polled.preauthCode;
1015
+
1016
+ if (preauthCode) {
1017
+ storePreauthCode(consentToken, intervention.code, preauthCode);
1018
+ }
1019
+
1020
+ // Sync selected ICD onto the claim (normal / post-claim only).
1021
+ if (!isElective) {
1022
+ try {
1023
+ const visitDx = selectedDx?.kind === 'visit' ? selectedDx.dx : null;
1024
+ await addClaimDiagnosis({
1025
+ consentToken,
1026
+ interventionCode: intervention.code,
1027
+ icdCode: icdCode.trim(),
1028
+ locationUuid,
1029
+ practitionerIdentificationNumber: (visitDx?.practioner_nat_id || doctorId || '').trim(),
1030
+ practitionerIdentificationType: DEFAULT_DOCTOR_ID_TYPE,
1031
+ practitionerRegulationBody: normalizeRegulationBody(
1032
+ visitDx?.practitioner_body || regulationBody,
1033
+ ),
1034
+ });
1035
+ } catch {
1036
+ // Preauth succeeded; claim diagnosis can still be added from bill details.
1037
+ }
1038
+ }
1039
+
1040
+ const awaitingDoctor = status === 'PENDING_DOCTOR_APPROVAL';
1041
+ showSnackbar({
1042
+ kind: 'success',
1043
+ title: awaitingDoctor
1044
+ ? isElective
1045
+ ? 'Elective preauth submitted'
1046
+ : 'Preauth submitted'
1047
+ : status === 'FINALISED' || status === 'FINALIZED'
1048
+ ? 'Preauth finalised'
1049
+ : 'Preauth submitted',
1050
+ subtitle: awaitingDoctor
1051
+ ? 'Awaiting doctor approval. Track progress on the Preauthorizations Status tab.'
1052
+ : preauthCode
1053
+ ? `Code: ${preauthCode}`
1054
+ : `Status: ${status}`,
1055
+ });
1056
+ onSuccess?.({ consentToken, preauthCode, status });
1057
+ setDirty(false);
1058
+ closeWorkspace?.();
1059
+ } catch (e: any) {
1060
+ showSnackbar({
1061
+ kind: 'error',
1062
+ title: 'Preauth failed',
1063
+ subtitle: String(e?.message ?? e),
1064
+ });
1065
+ } finally {
1066
+ setSubmitting(false);
1067
+ setPolling(false);
1068
+ }
1069
+ };
1070
+
1071
+ if (!isElective && !consentToken) {
1072
+ return null;
1073
+ }
1074
+
1075
+ return (
1076
+ <Form className={styles.form}>
1077
+ <div className={styles.body}>
1078
+ <div className={styles.header}>
1079
+ <div>
1080
+ <h4>{t('raisePreauth', 'Raise preauth')}</h4>
1081
+ <p className={styles.muted}>
1082
+ {patientName} · {intervention.code} · {billableService}
1083
+ </p>
1084
+ </div>
1085
+ <Tag type={isElective ? 'magenta' : 'blue'} size="md">
1086
+ {isElective ? 'Elective' : specialtyLabel} preauth
1087
+ </Tag>
1088
+ </div>
1089
+
1090
+ {isElective ? (
1091
+ <section className={styles.section}>
1092
+ <h5>Expected service start</h5>
1093
+ <DatePicker
1094
+ datePickerType="single"
1095
+ dateFormat="Y-m-d"
1096
+ value={expectedServiceStartDate ? dayjs(expectedServiceStartDate).toDate() : undefined}
1097
+ onChange={(dates: Date[]) => {
1098
+ markDirty();
1099
+ if (dates?.[0]) setExpectedServiceStartDate(dateToServiceIso(dates[0]));
1100
+ }}
1101
+ >
1102
+ <DatePickerInput
1103
+ id="expected-service-start"
1104
+ labelText="Expected service start date"
1105
+ placeholder="yyyy-mm-dd"
1106
+ />
1107
+ </DatePicker>
1108
+ </section>
1109
+ ) : null}
1110
+
1111
+ <InlineNotification
1112
+ kind="info"
1113
+ lowContrast
1114
+ hideCloseButton
1115
+ title={isElective ? 'Pre-visit authorization token' : 'Claim token'}
1116
+ subtitle={
1117
+ consentToken
1118
+ ? `${consentToken.slice(0, 8)}…${consentToken.slice(-4)}`
1119
+ : isElective
1120
+ ? 'Complete OTP authorize below to obtain a pre-visit token.'
1121
+ : '—'
1122
+ }
1123
+ />
1124
+
1125
+ <section className={styles.section}>
1126
+ <h5>Consent</h5>
1127
+ <RadioButtonGroup
1128
+ legendText="Consent method"
1129
+ name="consent-method"
1130
+ valueSelected={consentMethod}
1131
+ onChange={(v) => {
1132
+ setConsentMethod(v as 'biometric' | 'otp');
1133
+ setConsentDone(false);
1134
+ }}
1135
+ >
1136
+ <RadioButton labelText="OTP" value="otp" id="preauth-otp" />
1137
+ <RadioButton labelText="Biometrics" value="biometric" id="preauth-bio" />
1138
+ </RadioButtonGroup>
1139
+ {consentMethod === 'otp' ? (
1140
+ <div className={styles.row}>
1141
+ <Button kind="tertiary" size="sm" onClick={handleSendOtp} disabled={sendingOtp || consentDone}>
1142
+ {sendingOtp ? <InlineLoading description="Sending…" /> : 'Send OTP'}
1143
+ </Button>
1144
+ <TextInput
1145
+ id="preauth-otp-input"
1146
+ labelText="OTP"
1147
+ value={otp}
1148
+ disabled={!otpSent || consentDone}
1149
+ onChange={(e) => setOtp(e.target.value)}
1150
+ />
1151
+ <Button kind="primary" size="sm" onClick={handleVerifyOtp} disabled={!otpSent || consentDone}>
1152
+ Verify
1153
+ </Button>
1154
+ </div>
1155
+ ) : (
1156
+ <div className={styles.row}>
1157
+ <p className={styles.muted}>
1158
+ Complete biometric capture on the patient device, then confirm below.
1159
+ </p>
1160
+ <Button kind="primary" size="sm" onClick={handleConfirmBiometric} disabled={consentDone}>
1161
+ Confirm biometric consent
1162
+ </Button>
1163
+ </div>
1164
+ )}
1165
+ {consentDone ? <Tag type="green" size="sm">Consent complete</Tag> : null}
1166
+ </section>
1167
+
1168
+ <section className={styles.section}>
1169
+ <h5>Service &amp; provider</h5>
1170
+ <div className={styles.row}>
1171
+ <DatePicker
1172
+ datePickerType="single"
1173
+ dateFormat="Y-m-d"
1174
+ value={serviceStart ? dayjs(serviceStart).toDate() : undefined}
1175
+ onChange={([date]) => {
1176
+ if (!date) return;
1177
+ markDirty();
1178
+ setServiceStart(dateToServiceIso(date, dayjs(serviceStart).format('HH:mm:ss')));
1179
+ }}
1180
+ >
1181
+ <DatePickerInput id="preauth-service-start" labelText="Service start" placeholder="yyyy-mm-dd" />
1182
+ </DatePicker>
1183
+ <TextInput
1184
+ id="preauth-service-start-time"
1185
+ type="time"
1186
+ labelText="Start time"
1187
+ value={dayjs(serviceStart).format('HH:mm')}
1188
+ onChange={(e) => {
1189
+ markDirty();
1190
+ setServiceStart(dateToServiceIso(dayjs(serviceStart).toDate(), `${e.target.value}:00`));
1191
+ }}
1192
+ />
1193
+ </div>
1194
+ <div className={styles.row}>
1195
+ <DatePicker
1196
+ datePickerType="single"
1197
+ dateFormat="Y-m-d"
1198
+ value={serviceEnd ? dayjs(serviceEnd).toDate() : undefined}
1199
+ onChange={([date]) => {
1200
+ if (!date) return;
1201
+ markDirty();
1202
+ setServiceEnd(dateToServiceIso(date, dayjs(serviceEnd).format('HH:mm:ss')));
1203
+ }}
1204
+ >
1205
+ <DatePickerInput id="preauth-service-end" labelText="Service end" placeholder="yyyy-mm-dd" />
1206
+ </DatePicker>
1207
+ <TextInput
1208
+ id="preauth-service-end-time"
1209
+ type="time"
1210
+ labelText="End time"
1211
+ value={dayjs(serviceEnd).format('HH:mm')}
1212
+ onChange={(e) => {
1213
+ markDirty();
1214
+ setServiceEnd(dateToServiceIso(dayjs(serviceEnd).toDate(), `${e.target.value}:00`));
1215
+ }}
1216
+ />
1217
+ </div>
1218
+
1219
+ <TextInput
1220
+ id="provider-email"
1221
+ labelText="Provider notification email"
1222
+ value={providerEmail}
1223
+ onChange={(e) => {
1224
+ markDirty();
1225
+ setProviderEmail(e.target.value);
1226
+ }}
1227
+ />
1228
+ <TextInput
1229
+ id="unit-price"
1230
+ labelText="Unit price (from bill)"
1231
+ type="number"
1232
+ value={unitPrice}
1233
+ readOnly
1234
+ />
1235
+
1236
+ <div className={styles.searchBlock}>
1237
+ <p className={styles.fieldHint}>
1238
+ Diagnosis (ICD-11). Prefills rank 1 when available; choose another if needed.
1239
+ </p>
1240
+ {loadingDx ? (
1241
+ <InlineLoading description="Loading patient diagnoses…" />
1242
+ ) : (
1243
+ <ComboBox
1244
+ id="preauth-diagnosis"
1245
+ titleText="Select diagnosis"
1246
+ placeholder="Search diagnosis / ICD-11 code"
1247
+ items={diagnosisItems}
1248
+ itemToString={diagnosisPickLabel}
1249
+ selectedItem={selectedDx}
1250
+ shouldFilterItem={() => true}
1251
+ onInputChange={handleDiagnosisInputChange}
1252
+ onChange={({ selectedItem }) => {
1253
+ applyDiagnosisPick(selectedItem as DiagnosisPick | null, { fromUser: true });
1254
+ if (selectedItem) {
1255
+ setConceptDxHits([]);
1256
+ }
1257
+ }}
1258
+ />
1259
+ )}
1260
+ {searchingDx ? <InlineLoading description="Searching concepts…" /> : null}
1261
+ <TextInput
1262
+ id="preauth-icd11"
1263
+ labelText="ICD-11 code"
1264
+ placeholder="Filled from selection (or type manually)"
1265
+ value={icdCode}
1266
+ onChange={(e) => {
1267
+ markDirty();
1268
+ setIcdCode(e.target.value.trim());
1269
+ }}
1270
+ />
1271
+ </div>
1272
+
1273
+ <div className={styles.searchBlock}>
1274
+ <p className={styles.fieldHint}>Search OpenMRS providers</p>
1275
+ <ComboBox
1276
+ id="preauth-provider"
1277
+ titleText="Provider"
1278
+ placeholder="Type at least 2 characters to search"
1279
+ items={providerHits}
1280
+ itemToString={providerItemLabel}
1281
+ selectedItem={selectedProvider}
1282
+ shouldFilterItem={() => true}
1283
+ onInputChange={handleProviderInputChange}
1284
+ onChange={({ selectedItem }) => applyProviderSelection(selectedItem as OpenMrsProviderHit | null)}
1285
+ />
1286
+ {searchingProviders ? <InlineLoading description="Searching providers…" /> : null}
1287
+ </div>
1288
+
1289
+ <div className={styles.row}>
1290
+ <TextInput
1291
+ id="doctor-id"
1292
+ labelText="Doctor National ID"
1293
+ value={doctorId}
1294
+ onChange={(e) => {
1295
+ markDirty();
1296
+ setDoctorId(e.target.value);
1297
+ setHwrHit(null);
1298
+ }}
1299
+ />
1300
+ <TextInput
1301
+ id="doctor-id-type"
1302
+ labelText="Doctor ID type"
1303
+ value={DEFAULT_DOCTOR_ID_TYPE}
1304
+ readOnly
1305
+ />
1306
+ <Button kind="tertiary" size="md" onClick={() => handleSearchHwr()} disabled={searchingHwr || !doctorId.trim()}>
1307
+ {searchingHwr ? 'Searching HWR…' : 'Search HWR (body)'}
1308
+ </Button>
1309
+ </div>
1310
+ {hwrHit ? (
1311
+ <Tag type="green" size="sm">
1312
+ {hwrHit.membership?.full_name || 'Match'} · {normalizeRegulationBody(hwrHit.membership?.licensing_body)}
1313
+ </Tag>
1314
+ ) : null}
1315
+ <div className={styles.row}>
1316
+ <Dropdown
1317
+ id="reg-body"
1318
+ titleText="Regulation body"
1319
+ label="Select regulation body"
1320
+ items={[...REGULATION_BODIES]}
1321
+ selectedItem={normalizeRegulationBody(regulationBody)}
1322
+ onChange={({ selectedItem }) => {
1323
+ markDirty();
1324
+ setRegulationBody(normalizeRegulationBody(selectedItem));
1325
+ }}
1326
+ />
1327
+ <p className={styles.fieldHint}>COC = Clinical Officers Council · NCK = Nursing Council of Kenya</p>
1328
+ </div>
1329
+ </section>
1330
+
1331
+ {specialty.requiresSurgicalPreauth ? (
1332
+ <section className={styles.section}>
1333
+ <h5>Surgical preauth</h5>
1334
+ <TextArea
1335
+ id="chief-complaint"
1336
+ labelText="Chief complaint"
1337
+ value={formFieldStatus('chiefComplaint') === 'loading' ? '' : chiefComplaint}
1338
+ readOnly={formFieldLocked('chiefComplaint')}
1339
+ invalid={formFieldInvalid('chiefComplaint')}
1340
+ invalidText={formFieldInvalid('chiefComplaint') ? FORM_MISSING_HINT : undefined}
1341
+ onChange={(e) => {
1342
+ if (formFieldLocked('chiefComplaint')) return;
1343
+ markDirty();
1344
+ setChiefComplaint(e.target.value);
1345
+ }}
1346
+ />
1347
+ <TextInput
1348
+ id="vital-signs"
1349
+ labelText="Vital signs"
1350
+ value={vitalSigns}
1351
+ onChange={(e) => {
1352
+ markDirty();
1353
+ setVitalSigns(e.target.value);
1354
+ }}
1355
+ />
1356
+ <TextArea
1357
+ id="hpi"
1358
+ labelText="History of present illness"
1359
+ value={formFieldStatus('hpi') === 'loading' ? '' : hpi}
1360
+ readOnly={formFieldLocked('hpi')}
1361
+ invalid={formFieldInvalid('hpi')}
1362
+ invalidText={formFieldInvalid('hpi') ? FORM_MISSING_HINT : undefined}
1363
+ onChange={(e) => {
1364
+ if (formFieldLocked('hpi')) return;
1365
+ markDirty();
1366
+ setHpi(e.target.value);
1367
+ }}
1368
+ />
1369
+ <TextArea
1370
+ id="physical-exam"
1371
+ labelText="Physical examination"
1372
+ value={formFieldStatus('physicalExam') === 'loading' ? '' : physicalExam}
1373
+ readOnly={formFieldLocked('physicalExam')}
1374
+ invalid={formFieldInvalid('physicalExam')}
1375
+ invalidText={formFieldInvalid('physicalExam') ? FORM_MISSING_HINT : undefined}
1376
+ onChange={(e) => {
1377
+ if (formFieldLocked('physicalExam')) return;
1378
+ markDirty();
1379
+ setPhysicalExam(e.target.value);
1380
+ }}
1381
+ />
1382
+ <TextArea
1383
+ id="investigations"
1384
+ labelText="Investigation report details"
1385
+ value={formFieldStatus('investigations') === 'loading' ? '' : investigations}
1386
+ readOnly={formFieldLocked('investigations')}
1387
+ invalid={formFieldInvalid('investigations')}
1388
+ invalidText={formFieldInvalid('investigations') ? FORM_MISSING_HINT : undefined}
1389
+ onChange={(e) => {
1390
+ if (formFieldLocked('investigations')) return;
1391
+ markDirty();
1392
+ setInvestigations(e.target.value);
1393
+ }}
1394
+ />
1395
+ <div className={styles.row}>
1396
+ <Dropdown
1397
+ id="anaesthesia"
1398
+ titleText="Type of anaesthesia"
1399
+ label="Select"
1400
+ items={ANAESTHESIA}
1401
+ selectedItem={anaesthesia || null}
1402
+ disabled={formFieldLocked('anaesthesia')}
1403
+ invalid={formFieldInvalid('anaesthesia')}
1404
+ invalidText={formFieldInvalid('anaesthesia') ? FORM_MISSING_HINT : undefined}
1405
+ onChange={({ selectedItem }) => {
1406
+ if (formFieldLocked('anaesthesia')) return;
1407
+ markDirty();
1408
+ setAnaesthesia(selectedItem ?? '');
1409
+ }}
1410
+ />
1411
+ <DatePicker
1412
+ datePickerType="single"
1413
+ dateFormat="Y-m-d"
1414
+ value={surgeryDate ? dayjs(surgeryDate).toDate() : undefined}
1415
+ onChange={(dates: Date[]) => {
1416
+ if (formFieldLocked('surgeryDate')) return;
1417
+ markDirty();
1418
+ if (dates?.[0]) setSurgeryDate(dateToServiceIso(dates[0]));
1419
+ }}
1420
+ >
1421
+ <DatePickerInput
1422
+ id="surgery-date"
1423
+ labelText="Surgery date"
1424
+ placeholder="yyyy-mm-dd"
1425
+ readOnly={formFieldLocked('surgeryDate')}
1426
+ invalid={formFieldInvalid('surgeryDate')}
1427
+ invalidText={formFieldInvalid('surgeryDate') ? FORM_MISSING_HINT : undefined}
1428
+ />
1429
+ </DatePicker>
1430
+ </div>
1431
+ <div className={styles.row}>
1432
+ <Checkbox
1433
+ id="related-employment"
1434
+ labelText="Related to employment"
1435
+ checked={relatedToEmployment}
1436
+ readOnly={formFieldLocked('relatedToEmployment')}
1437
+ onChange={(_, { checked }) => {
1438
+ if (formFieldLocked('relatedToEmployment')) return;
1439
+ markDirty();
1440
+ setRelatedToEmployment(checked);
1441
+ }}
1442
+ />
1443
+ <Checkbox
1444
+ id="related-accident"
1445
+ labelText="Related to auto/other accident"
1446
+ checked={relatedToAccident}
1447
+ readOnly={formFieldLocked('relatedToAccident')}
1448
+ onChange={(_, { checked }) => {
1449
+ if (formFieldLocked('relatedToAccident')) return;
1450
+ markDirty();
1451
+ setRelatedToAccident(checked);
1452
+ }}
1453
+ />
1454
+ <Checkbox
1455
+ id="surgical-co-insured"
1456
+ labelText="Is co-insured"
1457
+ checked={isCoInsured}
1458
+ readOnly={formFieldLocked('isCoInsured')}
1459
+ onChange={(_, { checked }) => {
1460
+ if (formFieldLocked('isCoInsured')) return;
1461
+ markDirty();
1462
+ setIsCoInsured(checked);
1463
+ }}
1464
+ />
1465
+ </div>
1466
+ {formFieldInvalid('relatedToEmployment') ||
1467
+ formFieldInvalid('relatedToAccident') ||
1468
+ formFieldInvalid('isCoInsured') ? (
1469
+ <InlineNotification
1470
+ kind="error"
1471
+ lowContrast
1472
+ hideCloseButton
1473
+ title="Missing Pre-authorization form answers"
1474
+ subtitle={FORM_MISSING_HINT}
1475
+ />
1476
+ ) : null}
1477
+ {isCoInsured ? (
1478
+ <TextArea
1479
+ id="co-insurance-details"
1480
+ labelText="Co-insurance details"
1481
+ value={formFieldStatus('coInsuranceDetails') === 'loading' ? '' : coInsuranceDetails}
1482
+ readOnly={formFieldLocked('coInsuranceDetails')}
1483
+ invalid={formFieldInvalid('coInsuranceDetails')}
1484
+ invalidText={formFieldInvalid('coInsuranceDetails') ? FORM_MISSING_HINT : undefined}
1485
+ onChange={(e) => {
1486
+ if (formFieldLocked('coInsuranceDetails')) return;
1487
+ markDirty();
1488
+ setCoInsuranceDetails(e.target.value);
1489
+ }}
1490
+ />
1491
+ ) : null}
1492
+ </section>
1493
+ ) : null}
1494
+
1495
+ {specialty.requiresRenalPreauth ? (
1496
+ <section className={styles.section}>
1497
+ <h5>Renal preauth</h5>
1498
+ <div className={styles.row}>
1499
+ <TextInput
1500
+ id="sessions-required"
1501
+ labelText="Number of sessions required"
1502
+ value={formFieldStatus('sessionsRequired') === 'loading' ? '' : sessionsRequired}
1503
+ readOnly={formFieldLocked('sessionsRequired')}
1504
+ invalid={formFieldInvalid('sessionsRequired')}
1505
+ invalidText={formFieldInvalid('sessionsRequired') ? FORM_MISSING_HINT : undefined}
1506
+ onChange={(e) => {
1507
+ if (formFieldLocked('sessionsRequired')) return;
1508
+ markDirty();
1509
+ setSessionsRequired(e.target.value);
1510
+ }}
1511
+ />
1512
+ <TextInput
1513
+ id="cost-per-session"
1514
+ labelText="Cost per session"
1515
+ value={costPerSession}
1516
+ onChange={(e) => {
1517
+ markDirty();
1518
+ setCostPerSession(e.target.value);
1519
+ }}
1520
+ />
1521
+ <Dropdown
1522
+ id="frequency"
1523
+ titleText="Frequency of sessions"
1524
+ label="Select"
1525
+ items={FREQUENCY}
1526
+ selectedItem={frequency || null}
1527
+ disabled={formFieldLocked('frequency')}
1528
+ invalid={formFieldInvalid('frequency')}
1529
+ invalidText={formFieldInvalid('frequency') ? FORM_MISSING_HINT : undefined}
1530
+ onChange={({ selectedItem }) => {
1531
+ if (formFieldLocked('frequency')) return;
1532
+ markDirty();
1533
+ setFrequency(selectedItem ?? '');
1534
+ }}
1535
+ />
1536
+ </div>
1537
+ <TextArea id="renal-indications" {...clinicalIndicationsFieldProps} />
1538
+ <div className={styles.row}>
1539
+ <DatePicker
1540
+ datePickerType="single"
1541
+ dateFormat="Y-m-d"
1542
+ value={startDate ? dayjs(startDate).toDate() : undefined}
1543
+ onChange={(dates: Date[]) => {
1544
+ if (formFieldLocked('startDate')) return;
1545
+ markDirty();
1546
+ if (dates?.[0]) setStartDate(dateToServiceIso(dates[0]));
1547
+ }}
1548
+ >
1549
+ <DatePickerInput
1550
+ id="renal-start"
1551
+ labelText="Start date"
1552
+ placeholder="yyyy-mm-dd"
1553
+ readOnly={formFieldLocked('startDate')}
1554
+ invalid={formFieldInvalid('startDate')}
1555
+ invalidText={formFieldInvalid('startDate') ? FORM_MISSING_HINT : undefined}
1556
+ />
1557
+ </DatePicker>
1558
+ <Checkbox
1559
+ id="renal-co-insured"
1560
+ labelText="Is co-insured"
1561
+ checked={isCoInsured}
1562
+ readOnly={formFieldLocked('isCoInsured')}
1563
+ onChange={(_, { checked }) => {
1564
+ if (formFieldLocked('isCoInsured')) return;
1565
+ markDirty();
1566
+ setIsCoInsured(checked);
1567
+ }}
1568
+ />
1569
+ </div>
1570
+ {formFieldInvalid('isCoInsured') ? (
1571
+ <InlineNotification
1572
+ kind="error"
1573
+ lowContrast
1574
+ hideCloseButton
1575
+ title="Missing co-insured answer"
1576
+ subtitle={FORM_MISSING_HINT}
1577
+ />
1578
+ ) : null}
1579
+ {isCoInsured ? (
1580
+ <TextArea
1581
+ id="renal-co-insurance-details"
1582
+ labelText="Co-insurance details"
1583
+ value={formFieldStatus('coInsuranceDetails') === 'loading' ? '' : coInsuranceDetails}
1584
+ readOnly={formFieldLocked('coInsuranceDetails')}
1585
+ invalid={formFieldInvalid('coInsuranceDetails')}
1586
+ invalidText={formFieldInvalid('coInsuranceDetails') ? FORM_MISSING_HINT : undefined}
1587
+ onChange={(e) => {
1588
+ if (formFieldLocked('coInsuranceDetails')) return;
1589
+ markDirty();
1590
+ setCoInsuranceDetails(e.target.value);
1591
+ }}
1592
+ />
1593
+ ) : null}
1594
+ </section>
1595
+ ) : null}
1596
+
1597
+ {specialty.requiresOpticalPreauth ? (
1598
+ <section className={styles.section}>
1599
+ <h5>Optical preauth</h5>
1600
+ <TextArea id="optical-indications" {...clinicalIndicationsFieldProps} />
1601
+ <TextArea
1602
+ id="necessity"
1603
+ labelText="Necessity of service"
1604
+ value={necessity}
1605
+ onChange={(e) => {
1606
+ markDirty();
1607
+ setNecessity(e.target.value);
1608
+ }}
1609
+ />
1610
+ <div className={styles.row}>
1611
+ <Dropdown
1612
+ id="lens-rx"
1613
+ titleText="Lens prescription"
1614
+ label="Select"
1615
+ items={LENS}
1616
+ selectedItem={lensPrescription || null}
1617
+ onChange={({ selectedItem }) => {
1618
+ markDirty();
1619
+ setLensPrescription(selectedItem ?? '');
1620
+ }}
1621
+ />
1622
+ <Dropdown
1623
+ id="new-or-repl"
1624
+ titleText="New or replacement"
1625
+ label="Select"
1626
+ items={NEW_OR_REPL}
1627
+ selectedItem={newOrReplacement || null}
1628
+ onChange={({ selectedItem }) => {
1629
+ markDirty();
1630
+ setNewOrReplacement(selectedItem ?? '');
1631
+ }}
1632
+ />
1633
+ </div>
1634
+ <div className={styles.row}>
1635
+ <TextInput
1636
+ id="lens-amount"
1637
+ labelText="Lens amount"
1638
+ value={lensAmount}
1639
+ onChange={(e) => {
1640
+ markDirty();
1641
+ setLensAmount(e.target.value);
1642
+ }}
1643
+ />
1644
+ <TextInput
1645
+ id="eye-exam-amount"
1646
+ labelText="Eye examination amount"
1647
+ value={eyeExamAmount}
1648
+ onChange={(e) => {
1649
+ markDirty();
1650
+ setEyeExamAmount(e.target.value);
1651
+ }}
1652
+ />
1653
+ <TextInput
1654
+ id="frame-amount"
1655
+ labelText="Frame amount"
1656
+ value={frameAmount}
1657
+ onChange={(e) => {
1658
+ markDirty();
1659
+ setFrameAmount(e.target.value);
1660
+ }}
1661
+ />
1662
+ </div>
1663
+ </section>
1664
+ ) : null}
1665
+
1666
+ {specialty.requiresOncologyPreauth ? (
1667
+ <section className={styles.section}>
1668
+ <h5>Oncology preauth</h5>
1669
+ <div className={styles.row}>
1670
+ <Dropdown
1671
+ id="carcinoma-staging"
1672
+ titleText="Carcinoma staging"
1673
+ label="Select"
1674
+ items={STAGING}
1675
+ selectedItem={carcinomaStaging || null}
1676
+ onChange={({ selectedItem }) => {
1677
+ markDirty();
1678
+ setCarcinomaStaging(selectedItem ?? '');
1679
+ }}
1680
+ />
1681
+ <Dropdown
1682
+ id="metastases"
1683
+ titleText="Metastases"
1684
+ label="Select"
1685
+ items={METASTASES}
1686
+ selectedItem={metastases || null}
1687
+ onChange={({ selectedItem }) => {
1688
+ markDirty();
1689
+ setMetastases(selectedItem ?? '');
1690
+ }}
1691
+ />
1692
+ <Dropdown
1693
+ id="treatment-setting"
1694
+ titleText="Treatment setting"
1695
+ label="Select"
1696
+ items={TREATMENT}
1697
+ selectedItem={treatmentSetting || null}
1698
+ onChange={({ selectedItem }) => {
1699
+ markDirty();
1700
+ setTreatmentSetting(selectedItem ?? '');
1701
+ }}
1702
+ />
1703
+ </div>
1704
+ <TextArea
1705
+ id="comorbidity"
1706
+ labelText="Comorbidity"
1707
+ value={comorbidity}
1708
+ onChange={(e) => {
1709
+ markDirty();
1710
+ setComorbidity(e.target.value);
1711
+ }}
1712
+ />
1713
+ <TextArea
1714
+ id="progress-report"
1715
+ labelText="Progress report"
1716
+ value={progressReport}
1717
+ onChange={(e) => {
1718
+ markDirty();
1719
+ setProgressReport(e.target.value);
1720
+ }}
1721
+ />
1722
+ <div className={styles.row}>
1723
+ <DatePicker
1724
+ datePickerType="single"
1725
+ dateFormat="Y-m-d"
1726
+ value={startDate ? dayjs(startDate).toDate() : undefined}
1727
+ onChange={(dates: Date[]) => {
1728
+ markDirty();
1729
+ if (dates?.[0]) setStartDate(dateToServiceIso(dates[0]));
1730
+ }}
1731
+ >
1732
+ <DatePickerInput id="oncology-start" labelText="Start date" placeholder="yyyy-mm-dd" />
1733
+ </DatePicker>
1734
+ </div>
1735
+ <div className={styles.row}>
1736
+ <TextInput
1737
+ id="onc-sessions"
1738
+ labelText="Number of sessions required"
1739
+ value={sessionsRequired}
1740
+ onChange={(e) => {
1741
+ markDirty();
1742
+ setSessionsRequired(e.target.value);
1743
+ }}
1744
+ />
1745
+ <TextInput
1746
+ id="onc-cost"
1747
+ labelText="Cost per session"
1748
+ value={costPerSession}
1749
+ onChange={(e) => {
1750
+ markDirty();
1751
+ setCostPerSession(e.target.value);
1752
+ }}
1753
+ />
1754
+ <Checkbox
1755
+ id="onc-co-insured"
1756
+ labelText="Is co-insured"
1757
+ checked={isCoInsured}
1758
+ onChange={(_, { checked }) => {
1759
+ markDirty();
1760
+ setIsCoInsured(checked);
1761
+ }}
1762
+ />
1763
+ </div>
1764
+ </section>
1765
+ ) : null}
1766
+
1767
+ {specialty.requiresRadiologyPreauth ? (
1768
+ <section className={styles.section}>
1769
+ <h5>Imaging / radiology preauth</h5>
1770
+ <TextArea id="imaging-indications" {...clinicalIndicationsFieldProps} />
1771
+ </section>
1772
+ ) : null}
1773
+
1774
+ <PreauthAttachments
1775
+ attachments={attachments}
1776
+ onChange={handleAttachmentsChange}
1777
+ addableDocTypes={addableDocTypes}
1778
+ billItem={billItem as Record<string, unknown>}
1779
+ intervention={interventionForSubmit}
1780
+ disabled={submitting || polling}
1781
+ />
1782
+ </div>
1783
+
1784
+ <ButtonSet className={styles.buttonSet}>
1785
+ <Button kind="secondary" onClick={() => closeWorkspace()} disabled={submitting || polling}>
1786
+ Cancel
1787
+ </Button>
1788
+ <Button kind="primary" onClick={handleSubmit} disabled={!consentDone || submitting || polling}>
1789
+ {polling ? (
1790
+ <InlineLoading description="Confirming submission…" />
1791
+ ) : submitting ? (
1792
+ <InlineLoading description="Submitting…" />
1793
+ ) : (
1794
+ t('submitPreauth', 'Submit preauth')
1795
+ )}
1796
+ </Button>
1797
+ </ButtonSet>
1798
+ </Form>
1799
+ );
1800
+ };
1801
+
1802
+ const PreauthWorkspace: React.FC<PreauthWorkspaceProps> = (props) => (
1803
+ <PreauthForm key={`${props.consentToken}::${props.intervention?.code ?? ''}`} {...props} />
1804
+ );
1805
+
1806
+ export default PreauthWorkspace;