@kenyaemr/esm-express-workflow-app 5.4.4-pre.43 → 5.4.4-pre.430

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 (627) hide show
  1. package/.turbo/turbo-build.log +14 -7
  2. package/dist/1084.js +1 -0
  3. package/dist/1084.js.map +1 -0
  4. package/dist/1278.js +1 -0
  5. package/dist/1278.js.map +1 -0
  6. package/dist/1324.js +1 -0
  7. package/dist/1324.js.map +1 -0
  8. package/dist/1375.js +66 -0
  9. package/dist/1375.js.map +1 -0
  10. package/dist/1402.js +1 -0
  11. package/dist/1402.js.map +1 -0
  12. package/dist/1442.js +1 -0
  13. package/dist/1442.js.map +1 -0
  14. package/dist/1520.js +1 -0
  15. package/dist/1520.js.map +1 -0
  16. package/dist/1559.js +1 -0
  17. package/dist/1559.js.map +1 -0
  18. package/dist/1593.js +1 -0
  19. package/dist/1593.js.map +1 -0
  20. package/dist/162.js +1 -0
  21. package/dist/162.js.map +1 -0
  22. package/dist/1620.js +1 -0
  23. package/dist/1620.js.map +1 -0
  24. package/dist/1658.js +1 -0
  25. package/dist/1658.js.map +1 -0
  26. package/dist/1659.js +1 -0
  27. package/dist/1659.js.map +1 -0
  28. package/dist/1789.js +1 -0
  29. package/dist/1789.js.map +1 -0
  30. package/dist/1827.js +1 -0
  31. package/dist/1827.js.map +1 -0
  32. package/dist/1831.js +1 -0
  33. package/dist/1831.js.map +1 -0
  34. package/dist/1854.js +1 -0
  35. package/dist/1854.js.map +1 -0
  36. package/dist/196.js +1 -0
  37. package/dist/196.js.map +1 -0
  38. package/dist/2127.js +1 -0
  39. package/dist/2127.js.map +1 -0
  40. package/dist/2152.js +1 -0
  41. package/dist/2152.js.map +1 -0
  42. package/dist/2202.js +1 -0
  43. package/dist/2202.js.map +1 -0
  44. package/dist/221.js +1 -0
  45. package/dist/221.js.map +1 -0
  46. package/dist/2269.js +1 -0
  47. package/dist/2269.js.map +1 -0
  48. package/dist/2293.js +1 -0
  49. package/dist/2293.js.map +1 -0
  50. package/dist/234.js +1 -0
  51. package/dist/234.js.map +1 -0
  52. package/dist/2412.js +1 -1
  53. package/dist/2412.js.map +1 -1
  54. package/dist/2466.js +1 -0
  55. package/dist/2466.js.map +1 -0
  56. package/dist/2534.js +1 -1
  57. package/dist/2534.js.map +1 -1
  58. package/dist/2553.js +1 -0
  59. package/dist/2553.js.map +1 -0
  60. package/dist/2556.js +1 -0
  61. package/dist/2556.js.map +1 -0
  62. package/dist/2648.js +1 -0
  63. package/dist/2648.js.map +1 -0
  64. package/dist/274.js +1 -0
  65. package/dist/274.js.map +1 -0
  66. package/dist/2788.js +1 -0
  67. package/dist/2788.js.map +1 -0
  68. package/dist/2842.js +1 -0
  69. package/dist/2842.js.map +1 -0
  70. package/dist/2874.js +1 -0
  71. package/dist/2874.js.map +1 -0
  72. package/dist/2916.js +1 -0
  73. package/dist/2916.js.map +1 -0
  74. package/dist/2947.js +1 -1
  75. package/dist/2947.js.map +1 -1
  76. package/dist/3012.js +1 -0
  77. package/dist/3012.js.map +1 -0
  78. package/dist/3087.js +1 -0
  79. package/dist/3087.js.map +1 -0
  80. package/dist/3335.js +1 -0
  81. package/dist/3335.js.map +1 -0
  82. package/dist/3378.js +1 -0
  83. package/dist/3378.js.map +1 -0
  84. package/dist/3504.js +1 -0
  85. package/dist/3504.js.map +1 -0
  86. package/dist/3509.js +1 -1
  87. package/dist/3509.js.map +1 -1
  88. package/dist/356.js +1 -0
  89. package/dist/356.js.map +1 -0
  90. package/dist/3690.js +1 -0
  91. package/dist/3690.js.map +1 -0
  92. package/dist/371.js +1 -0
  93. package/dist/371.js.map +1 -0
  94. package/dist/3747.js +1 -0
  95. package/dist/3747.js.map +1 -0
  96. package/dist/3819.js +1 -0
  97. package/dist/3819.js.map +1 -0
  98. package/dist/3820.js +1 -0
  99. package/dist/3820.js.map +1 -0
  100. package/dist/3910.js +1 -0
  101. package/dist/3910.js.map +1 -0
  102. package/dist/393.js +6 -0
  103. package/dist/393.js.map +1 -0
  104. package/dist/3933.js +1 -0
  105. package/dist/3933.js.map +1 -0
  106. package/dist/3989.js +1 -0
  107. package/dist/3989.js.map +1 -0
  108. package/dist/3995.js +1 -0
  109. package/dist/3995.js.map +1 -0
  110. package/dist/4032.js +1 -0
  111. package/dist/4032.js.map +1 -0
  112. package/dist/4145.js +1 -1
  113. package/dist/4145.js.map +1 -1
  114. package/dist/4178.js +1 -1
  115. package/dist/4178.js.map +1 -1
  116. package/dist/4191.js +1 -0
  117. package/dist/4191.js.map +1 -0
  118. package/dist/4212.js +1 -0
  119. package/dist/4212.js.map +1 -0
  120. package/dist/4215.js +1 -0
  121. package/dist/4215.js.map +1 -0
  122. package/dist/4523.js +1 -0
  123. package/dist/4523.js.map +1 -0
  124. package/dist/4588.js +1 -0
  125. package/dist/4588.js.map +1 -0
  126. package/dist/4617.js +1 -0
  127. package/dist/4617.js.map +1 -0
  128. package/dist/466.js +1 -1
  129. package/dist/466.js.map +1 -1
  130. package/dist/4688.js +1 -0
  131. package/dist/{7288.js.map → 4688.js.map} +1 -1
  132. package/dist/470.js +1 -0
  133. package/dist/470.js.map +1 -0
  134. package/dist/4759.js +1 -0
  135. package/dist/4759.js.map +1 -0
  136. package/dist/4818.js +1 -1
  137. package/dist/4818.js.map +1 -1
  138. package/dist/5086.js +1 -1
  139. package/dist/5086.js.map +1 -1
  140. package/dist/5093.js +1 -0
  141. package/dist/5093.js.map +1 -0
  142. package/dist/5097.js +1 -0
  143. package/dist/5097.js.map +1 -0
  144. package/dist/510.js +1 -0
  145. package/dist/510.js.map +1 -0
  146. package/dist/5117.js +1 -0
  147. package/dist/5117.js.map +1 -0
  148. package/dist/5279.js +1 -0
  149. package/dist/5279.js.map +1 -0
  150. package/dist/5434.js +1 -0
  151. package/dist/5434.js.map +1 -0
  152. package/dist/5514.js +1 -0
  153. package/dist/5514.js.map +1 -0
  154. package/dist/5568.js +1 -0
  155. package/dist/5568.js.map +1 -0
  156. package/dist/5576.js +1 -1
  157. package/dist/5576.js.map +1 -1
  158. package/dist/5630.js +1 -0
  159. package/dist/5630.js.map +1 -0
  160. package/dist/5676.js +1 -1
  161. package/dist/5676.js.map +1 -1
  162. package/dist/5695.js +1 -0
  163. package/dist/5695.js.map +1 -0
  164. package/dist/5697.js +1 -1
  165. package/dist/5697.js.map +1 -1
  166. package/dist/5728.js +1 -0
  167. package/dist/5728.js.map +1 -0
  168. package/dist/5809.js +1 -1
  169. package/dist/5809.js.map +1 -1
  170. package/dist/585.js +1 -0
  171. package/dist/585.js.map +1 -0
  172. package/dist/5887.js +1 -0
  173. package/dist/5887.js.map +1 -0
  174. package/dist/5958.js +1 -0
  175. package/dist/5958.js.map +1 -0
  176. package/dist/5964.js +1 -0
  177. package/dist/5964.js.map +1 -0
  178. package/dist/6008.js +1 -0
  179. package/dist/602.js +1 -0
  180. package/dist/602.js.map +1 -0
  181. package/dist/6020.js +1 -0
  182. package/dist/6020.js.map +1 -0
  183. package/dist/6161.js +1 -0
  184. package/dist/6161.js.map +1 -0
  185. package/dist/6273.js +1 -0
  186. package/dist/6273.js.map +1 -0
  187. package/dist/6337.js +1 -0
  188. package/dist/6337.js.map +1 -0
  189. package/dist/6427.js +1 -1
  190. package/dist/6427.js.map +1 -1
  191. package/dist/6429.js +1 -0
  192. package/dist/6429.js.map +1 -0
  193. package/dist/6478.js +7 -0
  194. package/dist/6478.js.map +1 -0
  195. package/dist/6508.js +1 -0
  196. package/dist/6508.js.map +1 -0
  197. package/dist/6634.js +1 -0
  198. package/dist/6634.js.map +1 -0
  199. package/dist/6767.js +1 -0
  200. package/dist/6767.js.map +1 -0
  201. package/dist/6783.js +1 -0
  202. package/dist/6783.js.map +1 -0
  203. package/dist/6868.js +1 -1
  204. package/dist/6868.js.map +1 -1
  205. package/dist/688.js +1 -0
  206. package/dist/688.js.map +1 -0
  207. package/dist/689.js +1 -1
  208. package/dist/689.js.map +1 -1
  209. package/dist/694.js +1 -0
  210. package/dist/694.js.map +1 -0
  211. package/dist/6987.js +1 -0
  212. package/dist/6987.js.map +1 -0
  213. package/dist/7061.js +1 -0
  214. package/dist/7061.js.map +1 -0
  215. package/dist/7078.js +1 -0
  216. package/dist/7078.js.map +1 -0
  217. package/dist/710.js +1 -0
  218. package/dist/710.js.map +1 -0
  219. package/dist/7128.js +1 -0
  220. package/dist/7128.js.map +1 -0
  221. package/dist/7209.js +1 -0
  222. package/dist/7209.js.map +1 -0
  223. package/dist/7424.js +1 -0
  224. package/dist/7424.js.map +1 -0
  225. package/dist/770.js +1 -0
  226. package/dist/770.js.map +1 -0
  227. package/dist/7707.js +1 -0
  228. package/dist/7707.js.map +1 -0
  229. package/dist/7784.js +1 -0
  230. package/dist/7784.js.map +1 -0
  231. package/dist/781.js +1 -1
  232. package/dist/781.js.map +1 -1
  233. package/dist/7824.js +1 -0
  234. package/dist/7824.js.map +1 -0
  235. package/dist/7832.js +1 -0
  236. package/dist/7832.js.map +1 -0
  237. package/dist/8178.js +1 -0
  238. package/dist/8178.js.map +1 -0
  239. package/dist/820.js +1 -0
  240. package/dist/820.js.map +1 -0
  241. package/dist/8224.js +1 -0
  242. package/dist/8224.js.map +1 -0
  243. package/dist/8225.js +1 -0
  244. package/dist/8225.js.map +1 -0
  245. package/dist/8240.js +1 -1
  246. package/dist/8240.js.map +1 -1
  247. package/dist/8258.js +1 -0
  248. package/dist/8258.js.map +1 -0
  249. package/dist/8702.js +1 -0
  250. package/dist/8702.js.map +1 -0
  251. package/dist/8725.js +1 -0
  252. package/dist/8725.js.map +1 -0
  253. package/dist/8762.js +1 -0
  254. package/dist/8762.js.map +1 -0
  255. package/dist/8763.js +1 -0
  256. package/dist/8763.js.map +1 -0
  257. package/dist/8815.js +1 -0
  258. package/dist/8815.js.map +1 -0
  259. package/dist/8882.js +1 -0
  260. package/dist/8882.js.map +1 -0
  261. package/dist/8924.js +1 -1
  262. package/dist/8924.js.map +1 -1
  263. package/dist/8937.js +1 -0
  264. package/dist/8937.js.map +1 -0
  265. package/dist/9.js +1 -1
  266. package/dist/9.js.map +1 -1
  267. package/dist/9061.js +1 -0
  268. package/dist/9061.js.map +1 -0
  269. package/dist/9087.js +1 -0
  270. package/dist/9087.js.map +1 -0
  271. package/dist/9301.js +1 -0
  272. package/dist/9301.js.map +1 -0
  273. package/dist/9324.js +1 -0
  274. package/dist/9324.js.map +1 -0
  275. package/dist/9497.js +1 -0
  276. package/dist/9497.js.map +1 -0
  277. package/dist/9520.js +1 -1
  278. package/dist/9520.js.map +1 -1
  279. package/dist/9526.js +1 -0
  280. package/dist/9526.js.map +1 -0
  281. package/dist/9621.js +1 -0
  282. package/dist/9621.js.map +1 -0
  283. package/dist/9676.js +17 -0
  284. package/dist/9676.js.map +1 -0
  285. package/dist/977.js +1 -0
  286. package/dist/977.js.map +1 -0
  287. package/dist/9771.js +1 -0
  288. package/dist/9771.js.map +1 -0
  289. package/dist/9806.js +1 -0
  290. package/dist/9806.js.map +1 -0
  291. package/dist/989.js +1 -0
  292. package/dist/989.js.map +1 -0
  293. package/dist/kenyaemr-esm-express-workflow-app.js +6 -5
  294. package/dist/kenyaemr-esm-express-workflow-app.js.buildmanifest.json +1407 -809
  295. package/dist/kenyaemr-esm-express-workflow-app.js.map +1 -1
  296. package/dist/main.js +22 -5
  297. package/dist/main.js.map +1 -1
  298. package/dist/routes.json +1 -1
  299. package/package.json +4 -6
  300. package/src/components/admissions/admissions-dashboard.component.tsx +2 -2
  301. package/src/components/anaesthetic/anaesthetic-dashboard.meta.ts +8 -0
  302. package/src/components/anaesthetic/anaesthetic-data-form.component.tsx +442 -0
  303. package/src/components/anaesthetic/anaesthetic-data-form.scss +278 -0
  304. package/src/components/anaesthetic/anaesthetic-link.component.tsx +21 -0
  305. package/src/components/anaesthetic/anaesthetic.component.tsx +618 -0
  306. package/src/components/anaesthetic/anaesthetic.resource.ts +1503 -0
  307. package/src/components/anaesthetic/anaesthetic.scss +1885 -0
  308. package/src/components/anaesthetic/forms/anaesthetic-form.component.tsx +304 -0
  309. package/src/components/anaesthetic/forms/anaesthetic-record-form.component.tsx +707 -0
  310. package/src/components/anaesthetic/forms/icd11-diagnosis-search.component.tsx +178 -0
  311. package/src/components/anaesthetic/forms/icd11-diagnosis-search.scss +126 -0
  312. package/src/components/anaesthetic/forms/index.ts +2 -0
  313. package/src/components/anaesthetic/forms/interoperative-record-drug-given-form.component.tsx +231 -0
  314. package/src/components/anaesthetic/forms/post-operative-summary-form.component.tsx +171 -0
  315. package/src/components/anaesthetic/forms/time-picker-dropdown.component.tsx +202 -0
  316. package/src/components/anaesthetic/forms/time-picker-dropdown.scss +107 -0
  317. package/src/components/anaesthetic/forms/time-picker-with-clock.component.tsx +174 -0
  318. package/src/components/anaesthetic/forms/time-picker-with-clock.scss +178 -0
  319. package/src/components/anaesthetic/forms/useAnaestheticData.ts +16 -0
  320. package/src/components/anaesthetic/graphs/anaesthetic-graph-wrapper.component.tsx +266 -0
  321. package/src/components/anaesthetic/graphs/anaesthetic-graph.component.tsx +185 -0
  322. package/src/components/anaesthetic/graphs/index.ts +2 -0
  323. package/src/components/anaesthetic/graphs/interoperative-record-drug-given-graph-wrapper.component.tsx +197 -0
  324. package/src/components/anaesthetic/graphs/interoperative-record-drug-given-graph.component.tsx +93 -0
  325. package/src/components/anaesthetic/resources/anaesthetic-amniotic-fluid.resource.ts +277 -0
  326. package/src/components/anaesthetic/resources/anaesthetic-form.resource.ts +716 -0
  327. package/src/components/anaesthetic/resources/anaesthetic.resource.ts +378 -0
  328. package/src/components/anaesthetic/types/index.ts +1349 -0
  329. package/src/components/consultation/clinical-encounter/clinical-encounter.component.tsx +4 -20
  330. package/src/components/consultation/clinical-encounter/encounter-details.component.tsx +9 -9
  331. package/src/components/consultation/clinical-encounter/encounter-details.test.tsx +19 -18
  332. package/src/components/consultation/consultation.utils.tsx +1 -1
  333. package/src/components/consultation/dashboard.component.tsx +0 -2
  334. package/src/components/consultation/index.ts +1 -1
  335. package/src/components/consultation/tabs/index.ts +67 -0
  336. package/src/components/facility-dashboard/components/header/home-header.component.tsx +8 -13
  337. package/src/components/laboratory/index.ts +11 -0
  338. package/src/components/laboratory/lab-table.component.tsx +46 -12
  339. package/src/components/laboratory/laboratory-tabs.component.tsx +3 -17
  340. package/src/components/mch/dashboard.component.tsx +0 -2
  341. package/src/components/mch/mch.component.tsx +1 -3
  342. package/src/components/pharmacy/index.ts +1 -1
  343. package/src/components/pharmacy/orders/pharmacy-orders.component.tsx +44 -6
  344. package/src/components/pharmacy/orders/pharmacy-orders.test.tsx +8 -7
  345. package/src/components/pharmacy/pharmacy-tabs.component.tsx +4 -20
  346. package/src/components/pharmacy/tabs/index.ts +21 -0
  347. package/src/components/preauth/index.ts +22 -0
  348. package/src/components/preauth/preauth-dashboard.component.tsx +20 -0
  349. package/src/components/procedures/index.ts +16 -0
  350. package/src/components/procedures/procedure-queues/index.ts +13 -0
  351. package/src/components/procedures/procedure-queues/procedure-form-extras.component.tsx +33 -0
  352. package/src/components/procedures/procedure-queues/procedure-form-extras.scss +5 -0
  353. package/src/components/procedures/procedure-queues/procedure-queues.component.tsx +35 -0
  354. package/src/components/procedures/procedure-queues/procedure-queues.resources.ts +37 -0
  355. package/src/components/procedures/procedure-queues/procedure-room-tabs.component.tsx +80 -0
  356. package/src/components/procedures/procedure-queues/procedure-rooms.scss +13 -0
  357. package/src/components/procedures/procedure-queues/queue-procedure-tabs.component.tsx +34 -0
  358. package/src/components/procedures/procedure-queues/summary-cards.component.tsx +81 -0
  359. package/src/components/procedures/procedure-queues/summary-cards.scss +35 -0
  360. package/src/components/procedures/procedures-table.component.tsx +77 -19
  361. package/src/components/procedures/procedures-tabs.component.test.tsx +57 -0
  362. package/src/components/procedures/procedures-tabs.component.tsx +3 -18
  363. package/src/components/radiology-and-imaging/index.ts +11 -0
  364. package/src/components/radiology-and-imaging/radiology-and-imaging-table.component.tsx +73 -21
  365. package/src/components/radiology-and-imaging/radiology-and-imaging.component.tsx +3 -19
  366. package/src/components/registration/card/HIE-card/hie-card.component.tsx +32 -44
  367. package/src/components/registration/card/Local-card/local-card.component.tsx +22 -24
  368. package/src/components/registration/checkin-form-extra/checkin-form-extra.extension.tsx +8 -2
  369. package/src/components/registration/checkin-form-extra/queue-fields.component.tsx +18 -19
  370. package/src/components/registration/dependants/dependants.component.tsx +37 -60
  371. package/src/components/registration/dependants/dependants.resource.ts +75 -46
  372. package/src/components/registration/end-visit-modal/end-visit-dialog.modal.tsx +320 -0
  373. package/src/components/registration/end-visit-modal/end-visit-dialog.scss +12 -0
  374. package/src/components/registration/end-visit-modal/end-visit.resource.tsx +59 -0
  375. package/src/components/registration/end-visit-modal/sha-end-visit.resource.ts +285 -0
  376. package/src/components/registration/search-bar/search-bar.resource.ts +32 -93
  377. package/src/components/registration/start-visit-form/hooks/useDefaultFacilityLocation.tsx +15 -0
  378. package/src/components/registration/start-visit-form/hooks/useDefaultVisitLocation.tsx +24 -0
  379. package/src/components/registration/start-visit-form/hooks/useOfflineVisitType.tsx +18 -0
  380. package/src/components/registration/start-visit-form/hooks/useRecommendedVisitTypes.tsx +36 -0
  381. package/src/components/registration/start-visit-form/hooks/useVisitAttributeType.tsx +102 -0
  382. package/src/components/registration/start-visit-form/overflow-menu-extension/custom-end-active-visit.extension.tsx +44 -0
  383. package/src/components/registration/start-visit-form/overflow-menu-extension/overflow-menu-item.extension.tsx +67 -0
  384. package/src/components/registration/start-visit-form/overflow-menu-extension/overflow-menu-item.scss +3 -0
  385. package/src/components/registration/start-visit-form/start-visit-workspace/base-visit-type.component.tsx +126 -0
  386. package/src/components/registration/start-visit-form/start-visit-workspace/base-visit-type.scss +75 -0
  387. package/src/components/registration/start-visit-form/start-visit-workspace/exported-visit-form.workspace.tsx +778 -0
  388. package/src/components/registration/start-visit-form/start-visit-workspace/location-selector.component.tsx +86 -0
  389. package/src/components/registration/start-visit-form/start-visit-workspace/recommended-visit-type.component.tsx +32 -0
  390. package/src/components/registration/start-visit-form/start-visit-workspace/visit-attribute-type.component.tsx +257 -0
  391. package/src/components/registration/start-visit-form/start-visit-workspace/visit-attribute-type.scss +5 -0
  392. package/src/components/registration/start-visit-form/start-visit-workspace/visit-date-time.component.tsx +193 -0
  393. package/src/components/registration/start-visit-form/start-visit-workspace/visit-form.resource.ts +390 -0
  394. package/src/components/registration/start-visit-form/start-visit-workspace/visit-form.scss +144 -0
  395. package/src/components/registration/start-visit-form/visit-form-workspace/visit-form.workspace.tsx +48 -0
  396. package/src/components/registration/type/index.ts +101 -0
  397. package/src/components/reports/index.ts +1 -0
  398. package/src/components/triage/dashboard.component.tsx +0 -2
  399. package/src/config-schema.ts +476 -0
  400. package/src/hooks/useOrders.tsx +2 -2
  401. package/src/hooks/useServiceQueues.tsx +1 -1
  402. package/src/index.ts +81 -15
  403. package/src/routes.json +298 -32
  404. package/src/shared/dashboard-link/dashboard-link.component.tsx +11 -8
  405. package/src/shared/orders/OrderTable.scss +7 -0
  406. package/src/shared/orders/OrderTable.tsx +68 -8
  407. package/src/shared/orders/print-order/print-order.component.tsx +158 -0
  408. package/src/shared/orders/print-order/print-order.scss +225 -0
  409. package/src/shared/orders/print-prescription/print-prescription.component.tsx +65 -0
  410. package/src/shared/orders/print-prescription/print-prescription.resource.ts +45 -0
  411. package/src/shared/orders/print-prescription/print-prescription.scss +25 -0
  412. package/src/shared/otp-verification/index.ts +112 -29
  413. package/src/shared/otp-verification/otp-verification.modal.tsx +1110 -122
  414. package/src/shared/otp-verification/otp-verification.scss +374 -0
  415. package/src/shared/patient-chart/patient-summary-dashboard/patient-summary-dashboard.component.tsx +5 -84
  416. package/src/shared/pin-put/pinput.component.test.tsx +7 -6
  417. package/src/shared/tabs/create-tab-extension.tsx +33 -0
  418. package/src/shared/tabs/extension-tabs.component.tsx +51 -33
  419. package/src/shared/utils/index.ts +140 -5
  420. package/src/types/index.ts +12 -0
  421. package/translations/am.json +443 -131
  422. package/translations/en.json +327 -15
  423. package/translations/fr.json +372 -63
  424. package/translations/sw.json +347 -35
  425. package/tsconfig.json +1 -0
  426. package/dist/1049.js +0 -1
  427. package/dist/1049.js.map +0 -1
  428. package/dist/1072.js +0 -1
  429. package/dist/1072.js.map +0 -1
  430. package/dist/1091.js +0 -1
  431. package/dist/1091.js.map +0 -1
  432. package/dist/1172.js +0 -1
  433. package/dist/1172.js.map +0 -1
  434. package/dist/132.js +0 -1
  435. package/dist/132.js.map +0 -1
  436. package/dist/1354.js +0 -1
  437. package/dist/1354.js.map +0 -1
  438. package/dist/1704.js +0 -1
  439. package/dist/1704.js.map +0 -1
  440. package/dist/1729.js +0 -17
  441. package/dist/1729.js.map +0 -1
  442. package/dist/1757.js +0 -1
  443. package/dist/1757.js.map +0 -1
  444. package/dist/1761.js +0 -1
  445. package/dist/1761.js.map +0 -1
  446. package/dist/1809.js +0 -7
  447. package/dist/1809.js.map +0 -1
  448. package/dist/1842.js +0 -1
  449. package/dist/1874.js +0 -1
  450. package/dist/1874.js.map +0 -1
  451. package/dist/1962.js +0 -1
  452. package/dist/1962.js.map +0 -1
  453. package/dist/2007.js +0 -1
  454. package/dist/2007.js.map +0 -1
  455. package/dist/2024.js +0 -1
  456. package/dist/2024.js.map +0 -1
  457. package/dist/2045.js +0 -1
  458. package/dist/2045.js.map +0 -1
  459. package/dist/2163.js +0 -1
  460. package/dist/2163.js.map +0 -1
  461. package/dist/2191.js +0 -1
  462. package/dist/2191.js.map +0 -1
  463. package/dist/2267.js +0 -1
  464. package/dist/2267.js.map +0 -1
  465. package/dist/231.js +0 -1
  466. package/dist/231.js.map +0 -1
  467. package/dist/236.js +0 -1
  468. package/dist/236.js.map +0 -1
  469. package/dist/2367.js +0 -1
  470. package/dist/2367.js.map +0 -1
  471. package/dist/2463.js +0 -1
  472. package/dist/2463.js.map +0 -1
  473. package/dist/2561.js +0 -1
  474. package/dist/2561.js.map +0 -1
  475. package/dist/2810.js +0 -2
  476. package/dist/2810.js.map +0 -1
  477. package/dist/2867.js +0 -1
  478. package/dist/2867.js.map +0 -1
  479. package/dist/2909.js +0 -1
  480. package/dist/2909.js.map +0 -1
  481. package/dist/2949.js +0 -1
  482. package/dist/2949.js.map +0 -1
  483. package/dist/3040.js +0 -1
  484. package/dist/3119.js +0 -1
  485. package/dist/3119.js.map +0 -1
  486. package/dist/3215.js +0 -1
  487. package/dist/3215.js.map +0 -1
  488. package/dist/322.js +0 -1
  489. package/dist/322.js.map +0 -1
  490. package/dist/3228.js +0 -1
  491. package/dist/3228.js.map +0 -1
  492. package/dist/330.js +0 -1
  493. package/dist/330.js.map +0 -1
  494. package/dist/3472.js +0 -1
  495. package/dist/3472.js.map +0 -1
  496. package/dist/351.js +0 -1
  497. package/dist/351.js.map +0 -1
  498. package/dist/3576.js +0 -1
  499. package/dist/3576.js.map +0 -1
  500. package/dist/397.js +0 -1
  501. package/dist/397.js.map +0 -1
  502. package/dist/4007.js +0 -66
  503. package/dist/4007.js.map +0 -1
  504. package/dist/4200.js +0 -1
  505. package/dist/4200.js.map +0 -1
  506. package/dist/4224.js +0 -1
  507. package/dist/4224.js.map +0 -1
  508. package/dist/43.js +0 -1
  509. package/dist/43.js.map +0 -1
  510. package/dist/4308.js +0 -1
  511. package/dist/4308.js.map +0 -1
  512. package/dist/4399.js +0 -1
  513. package/dist/4399.js.map +0 -1
  514. package/dist/4505.js +0 -1
  515. package/dist/4505.js.map +0 -1
  516. package/dist/4724.js +0 -1
  517. package/dist/4724.js.map +0 -1
  518. package/dist/498.js +0 -1
  519. package/dist/498.js.map +0 -1
  520. package/dist/509.js +0 -1
  521. package/dist/509.js.map +0 -1
  522. package/dist/5096.js +0 -1
  523. package/dist/5096.js.map +0 -1
  524. package/dist/5159.js +0 -13
  525. package/dist/5159.js.map +0 -1
  526. package/dist/5184.js +0 -1
  527. package/dist/5184.js.map +0 -1
  528. package/dist/5270.js +0 -1
  529. package/dist/5270.js.map +0 -1
  530. package/dist/5361.js +0 -1
  531. package/dist/5361.js.map +0 -1
  532. package/dist/5537.js +0 -1
  533. package/dist/5537.js.map +0 -1
  534. package/dist/566.js +0 -1
  535. package/dist/566.js.map +0 -1
  536. package/dist/5733.js +0 -1
  537. package/dist/5733.js.map +0 -1
  538. package/dist/5854.js +0 -1
  539. package/dist/5854.js.map +0 -1
  540. package/dist/5882.js +0 -1
  541. package/dist/6004.js +0 -1
  542. package/dist/6004.js.map +0 -1
  543. package/dist/6121.js +0 -3
  544. package/dist/6121.js.map +0 -1
  545. package/dist/6137.js +0 -1
  546. package/dist/6137.js.map +0 -1
  547. package/dist/6356.js +0 -1
  548. package/dist/6356.js.map +0 -1
  549. package/dist/6571.js +0 -1
  550. package/dist/6571.js.map +0 -1
  551. package/dist/6721.js +0 -1
  552. package/dist/6721.js.map +0 -1
  553. package/dist/6858.js +0 -1
  554. package/dist/6858.js.map +0 -1
  555. package/dist/6925.js +0 -1
  556. package/dist/6925.js.map +0 -1
  557. package/dist/6960.js +0 -1
  558. package/dist/6960.js.map +0 -1
  559. package/dist/7085.js +0 -1
  560. package/dist/7085.js.map +0 -1
  561. package/dist/7127.js +0 -1
  562. package/dist/7176.js +0 -1
  563. package/dist/7176.js.map +0 -1
  564. package/dist/7237.js +0 -1
  565. package/dist/7237.js.map +0 -1
  566. package/dist/725.js +0 -1
  567. package/dist/725.js.map +0 -1
  568. package/dist/7288.js +0 -1
  569. package/dist/7329.js +0 -1
  570. package/dist/7329.js.map +0 -1
  571. package/dist/7334.js +0 -1
  572. package/dist/7334.js.map +0 -1
  573. package/dist/7461.js +0 -1
  574. package/dist/7461.js.map +0 -1
  575. package/dist/7517.js +0 -1
  576. package/dist/7517.js.map +0 -1
  577. package/dist/7837.js +0 -1
  578. package/dist/7837.js.map +0 -1
  579. package/dist/8103.js +0 -1
  580. package/dist/8103.js.map +0 -1
  581. package/dist/8110.js +0 -1
  582. package/dist/8110.js.map +0 -1
  583. package/dist/8179.js +0 -6
  584. package/dist/8179.js.map +0 -1
  585. package/dist/8189.js +0 -1
  586. package/dist/8189.js.map +0 -1
  587. package/dist/8209.js +0 -1
  588. package/dist/8209.js.map +0 -1
  589. package/dist/8249.js +0 -1
  590. package/dist/8249.js.map +0 -1
  591. package/dist/8285.js +0 -1
  592. package/dist/8285.js.map +0 -1
  593. package/dist/8470.js +0 -1
  594. package/dist/8470.js.map +0 -1
  595. package/dist/8502.js +0 -1
  596. package/dist/8502.js.map +0 -1
  597. package/dist/866.js +0 -1
  598. package/dist/866.js.map +0 -1
  599. package/dist/8889.js +0 -11
  600. package/dist/8889.js.map +0 -1
  601. package/dist/8990.js +0 -1
  602. package/dist/8990.js.map +0 -1
  603. package/dist/8994.js +0 -1
  604. package/dist/8994.js.map +0 -1
  605. package/dist/9049.js +0 -1
  606. package/dist/9049.js.map +0 -1
  607. package/dist/9054.js +0 -1
  608. package/dist/9054.js.map +0 -1
  609. package/dist/916.js +0 -1
  610. package/dist/9231.js +0 -1
  611. package/dist/9231.js.map +0 -1
  612. package/dist/9408.js +0 -1
  613. package/dist/9408.js.map +0 -1
  614. package/dist/9425.js +0 -1
  615. package/dist/9466.js +0 -1
  616. package/dist/9466.js.map +0 -1
  617. package/dist/9919.js +0 -1
  618. package/dist/9919.js.map +0 -1
  619. package/dist/9931.js +0 -1
  620. package/dist/9931.js.map +0 -1
  621. package/jest.config.js +0 -3
  622. package/src/shared/orders/OrdersTabs.tsx +0 -58
  623. package/src/shared/patient-chart/patient-chart.component.tsx +0 -61
  624. package/src/shared/patient-chart/patient-chart.resources.ts +0 -180
  625. package/src/shared/patient-chart/patient-chart.scss +0 -15
  626. package/src/shared/patient-chart/useInitialize.ts +0 -24
  627. /package/src/shared/{patient-chart/patient-summary-dashboard → tabs}/patient-summary-dashboard.scss +0 -0
@@ -0,0 +1,320 @@
1
+ import React, { useState, useCallback, useRef } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button, Dropdown, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
4
+ import { showModal, showSnackbar, useSession, useVisit } from '@openmrs/esm-framework';
5
+ import { extractFetchError, extractUpstreamError } from '../../../shared/utils';
6
+ import styles from './end-visit-dialog.scss';
7
+ import { processVisitInsuranceClaim, sendDischargeOtp, submitVisitClaim } from './end-visit.resource';
8
+ import {
9
+ checkBiometricAuthorizationStatus,
10
+ createSHABiometricAuthorize,
11
+ detectAuthorizingDeviceOS,
12
+ fetchWhitelistStatus,
13
+ rejectBiometricAuthorization,
14
+ submitOtpWhitelist,
15
+ useBiometricAgentStatus,
16
+ useBiometricConfig,
17
+ useOtpWhitelistReasons,
18
+ usePatientCRId,
19
+ usePatientPhone,
20
+ useSHAEligibility,
21
+ useProviderNationalId,
22
+ } from './sha-end-visit.resource';
23
+ import { DISCHARGE_REASONS } from '../type';
24
+
25
+ interface EndVisitDialogProps {
26
+ patientUuid: string;
27
+ closeModal: () => void;
28
+ }
29
+
30
+ const EndVisitDialog: React.FC<EndVisitDialogProps> = ({ patientUuid, closeModal }) => {
31
+ const { t } = useTranslation();
32
+ const { activeVisit } = useVisit(patientUuid);
33
+ const [step, setStep] = useState<'confirm' | 'discharge-reason'>('confirm');
34
+ const [isProcessingClaim, setIsProcessingClaim] = useState(false);
35
+ const [reason, setReason] = useState('');
36
+ const processingClaimRef = useRef(false);
37
+ const serviceTypeRef = useRef('OUTPATIENT');
38
+ const consentTokenRef = useRef<string>('');
39
+ const invoiceNumberRef = useRef<string>('');
40
+ const interventionsRef = useRef<string[]>([]);
41
+ const phoneNumber = usePatientPhone(patientUuid);
42
+ const patientCRId = usePatientCRId(patientUuid);
43
+ const { isPatientWhiteListed, facilityBiometricsEnforced } = useSHAEligibility(patientUuid);
44
+ const { currentProvider } = useSession();
45
+ const { providerNationalid } = useProviderNationalId(currentProvider?.uuid ?? '');
46
+ const { agentUrl } = useBiometricConfig();
47
+ const { workstationId } = useBiometricAgentStatus(agentUrl);
48
+ const deviceOs = detectAuthorizingDeviceOS();
49
+ const { reasons: whitelistReasons } = useOtpWhitelistReasons();
50
+
51
+ const buildBiometricStarter = useCallback(
52
+ (crId: string) => {
53
+ return async () => {
54
+ if (!providerNationalid) {
55
+ throw new Error(
56
+ t(
57
+ 'biometricMissingNationalId',
58
+ 'Provider National ID not configured. Please add it to your provider profile.',
59
+ ),
60
+ );
61
+ }
62
+ if (!workstationId) {
63
+ throw new Error(
64
+ t(
65
+ 'biometricAgentNotReachable',
66
+ 'Biometric agent not running. Please start the agent on this workstation and try again.',
67
+ ),
68
+ );
69
+ }
70
+
71
+ const res = await createSHABiometricAuthorize({
72
+ agent_id: providerNationalid,
73
+ patient_id: crId,
74
+ interventions: interventionsRef.current,
75
+ service_type: serviceTypeRef.current,
76
+ workstation_id: workstationId,
77
+ authorizing_device_os: deviceOs,
78
+ patient_uuid: patientUuid,
79
+ is_biometrics_discharge_authorization: true,
80
+ });
81
+ if (!res.success || !res.embed_url || !res.token || !res.guid) {
82
+ throw new Error(
83
+ extractUpstreamError(res as any, t('biometricStartFailed', 'Could not start biometric session.')),
84
+ );
85
+ }
86
+ return {
87
+ embed_url: res.embed_url,
88
+ authorization_code: res.authorization_code ?? '',
89
+ consent_token: res.consent_token ?? res.token,
90
+ token: res.token,
91
+ guid: res.guid,
92
+ };
93
+ };
94
+ },
95
+ [providerNationalid, workstationId, deviceOs, patientUuid, t],
96
+ );
97
+
98
+ const handleSubmitWhitelist = useCallback(
99
+ async (params: { reasonType: string; reason: string; biometricAttempts: number; attachment: File | null }) => {
100
+ if (!patientCRId) {
101
+ return { success: false, error: t('noCRNumber', 'Patient has no SHA CR number.') };
102
+ }
103
+ return submitOtpWhitelist({
104
+ beneficiaryCrId: patientCRId,
105
+ reasonType: params.reasonType,
106
+ reason: params.reason,
107
+ biometricAttempts: params.biometricAttempts,
108
+ attachment: params.attachment,
109
+ });
110
+ },
111
+ [patientCRId, t],
112
+ );
113
+
114
+ const handleCheckWhitelistStatus = useCallback(async (crId: string) => {
115
+ const status = await fetchWhitelistStatus(crId);
116
+ return {
117
+ is_whitelisted: status.is_whitelisted,
118
+ has_pending: status.has_pending,
119
+ is_rejected: status.is_rejected,
120
+ latest_status: status.latest_status,
121
+ reviewer_note: status.requests?.[0]?.reviewer_note ?? null,
122
+ };
123
+ }, []);
124
+
125
+ const handleEndVisit = async () => {
126
+ if (!activeVisit || processingClaimRef.current) {
127
+ return;
128
+ }
129
+ processingClaimRef.current = true;
130
+ setIsProcessingClaim(true);
131
+
132
+ try {
133
+ const response = await processVisitInsuranceClaim(activeVisit.uuid);
134
+ serviceTypeRef.current = response?.data?.service_type ?? 'OUTPATIENT';
135
+ consentTokenRef.current = String(response?.data?.consentToken ?? '');
136
+ invoiceNumberRef.current = String(response?.data?.invoiceNumber ?? '');
137
+ interventionsRef.current = Array.isArray(response?.data?.intervention_codes)
138
+ ? response?.data?.intervention_codes
139
+ : [];
140
+ setStep('discharge-reason');
141
+ } catch (error) {
142
+ showSnackbar({
143
+ isLowContrast: true,
144
+ kind: 'error',
145
+ title: t('claimProcessingError', 'Error'),
146
+ subtitle: extractFetchError(error, t('insuranceClaimProcessingFailed', 'Insurance claim processing failed')),
147
+ });
148
+ closeModal();
149
+ } finally {
150
+ processingClaimRef.current = false;
151
+ setIsProcessingClaim(false);
152
+ }
153
+ };
154
+
155
+ const handleContinue = useCallback(() => {
156
+ if (!reason || !patientCRId || !activeVisit) {
157
+ return;
158
+ }
159
+
160
+ closeModal();
161
+
162
+ const crId = patientCRId;
163
+ const visitUuid = activeVisit.uuid;
164
+ const dischargeReason = reason;
165
+ const invoiceNumber = invoiceNumberRef.current;
166
+ let settled = false;
167
+
168
+ const settle = (fn?: () => void) => {
169
+ if (!settled) {
170
+ settled = true;
171
+ fn?.();
172
+ }
173
+ };
174
+
175
+ setTimeout(() => {
176
+ const dispose = showModal('otp-verification-modal', {
177
+ onClose: () => {
178
+ settle();
179
+ dispose();
180
+ },
181
+ phoneNumber,
182
+ otpLength: 6,
183
+ expiryMinutes: 5,
184
+ centerBoxes: true,
185
+ authMode: 'multi',
186
+ whitelistedForOTP: isPatientWhiteListed,
187
+ facilityBiometricsEnforced,
188
+ patientCRId: crId,
189
+ visitAction: 'end',
190
+
191
+ onRequestOtp: async () => {
192
+ const res = await sendDischargeOtp(crId, consentTokenRef.current);
193
+ if (res.success === false) {
194
+ throw new Error(res.error ?? t('otpRequestFailed', 'Failed to send OTP. Please try again.'));
195
+ }
196
+ },
197
+
198
+ onVerify: async (otp: string) => {
199
+ const res = await submitVisitClaim({ visitUuid, otp, dischargeReason, invoiceNumber });
200
+ showSnackbar({
201
+ isLowContrast: true,
202
+ kind: res?.success === true ? 'success' : 'error',
203
+ title: t('visitEnded', 'Visit ended'),
204
+ subtitle: res?.message ?? res?.error ?? '',
205
+ });
206
+ },
207
+
208
+ onVerificationSuccess: () => {
209
+ settle(() => {
210
+ dispose();
211
+ });
212
+ },
213
+
214
+ onCleanup: () => {},
215
+
216
+ onStartBiometric: buildBiometricStarter(crId),
217
+ onCheckBiometricStatus: checkBiometricAuthorizationStatus,
218
+
219
+ onBiometricSuccess: async (result: { authorization_code: string; consent_token: string; guid: string }) => {
220
+ const res = await submitVisitClaim({
221
+ visitUuid,
222
+ dischargeAuthGuid: result.guid,
223
+ dischargeReason,
224
+ invoiceNumber,
225
+ });
226
+ showSnackbar({
227
+ isLowContrast: true,
228
+ kind: res?.success === true ? 'success' : 'error',
229
+ title: t('visitEnded', 'Visit ended'),
230
+ subtitle: res?.message ?? res?.error ?? '',
231
+ });
232
+ },
233
+
234
+ onBiometricCancel: async (biometricConsentToken: string | null) => {
235
+ if (biometricConsentToken) {
236
+ try {
237
+ await rejectBiometricAuthorization(biometricConsentToken);
238
+ } catch (err) {
239
+ console.warn('Failed to reject biometric auth:', err);
240
+ }
241
+ }
242
+ },
243
+
244
+ whitelistReasons,
245
+ onSubmitWhitelist: handleSubmitWhitelist,
246
+ onCheckWhitelistStatus: handleCheckWhitelistStatus,
247
+ });
248
+ }, 300);
249
+ }, [
250
+ reason,
251
+ patientCRId,
252
+ activeVisit,
253
+ closeModal,
254
+ phoneNumber,
255
+ isPatientWhiteListed,
256
+ facilityBiometricsEnforced,
257
+ buildBiometricStarter,
258
+ whitelistReasons,
259
+ handleSubmitWhitelist,
260
+ handleCheckWhitelistStatus,
261
+ t,
262
+ ]);
263
+
264
+ if (step === 'discharge-reason') {
265
+ return (
266
+ <div>
267
+ <ModalHeader closeModal={closeModal} title={t('endVisitTitle', 'End Visit')} />
268
+ <ModalBody className={styles.dischargeModalBody}>
269
+ <p className={styles.bodyShort02}>
270
+ {t(
271
+ 'dischargeReasonIntro',
272
+ 'Select the reason for ending this visit. You will then be asked to verify your identity.',
273
+ )}
274
+ </p>
275
+ <Dropdown
276
+ id="discharge-reason-dropdown"
277
+ titleText={t('dischargeReason', 'Discharge reason')}
278
+ label={t('selectDischargeReason', 'Select a reason')}
279
+ items={[...DISCHARGE_REASONS]}
280
+ itemToString={(item) => (item ? item.label : '')}
281
+ selectedItem={DISCHARGE_REASONS.find((r) => r.id === reason) ?? null}
282
+ onChange={({ selectedItem }) => setReason(selectedItem?.id ?? '')}
283
+ />
284
+ </ModalBody>
285
+ <ModalFooter>
286
+ <Button kind="secondary" onClick={closeModal}>
287
+ {t('cancel', 'Cancel')}
288
+ </Button>
289
+ <Button kind="primary" disabled={!reason} onClick={handleContinue}>
290
+ {t('continue', 'Continue')}
291
+ </Button>
292
+ </ModalFooter>
293
+ </div>
294
+ );
295
+ }
296
+
297
+ return (
298
+ <div>
299
+ <ModalHeader
300
+ closeModal={closeModal}
301
+ title={t('endActiveVisitConfirmation', 'Are you sure you want to end this active visit?')}
302
+ />
303
+ <ModalBody>
304
+ <p className={styles.bodyShort02}>
305
+ {t('youWillProcessTheClaim', 'You will process the insurance claim for this visit.')}
306
+ </p>
307
+ </ModalBody>
308
+ <ModalFooter>
309
+ <Button kind="secondary" onClick={closeModal}>
310
+ {t('cancel', 'Cancel')}
311
+ </Button>
312
+ <Button kind="danger" disabled={!activeVisit || isProcessingClaim} onClick={handleEndVisit}>
313
+ {t('endVisit_title', 'End Visit')}
314
+ </Button>
315
+ </ModalFooter>
316
+ </div>
317
+ );
318
+ };
319
+
320
+ export default EndVisitDialog;
@@ -0,0 +1,12 @@
1
+ @use '@carbon/type';
2
+ @use '@carbon/colors';
3
+
4
+ .bodyShort02 {
5
+ @include type.type-style('body-compact-02');
6
+ color: colors.$gray-70;
7
+ }
8
+
9
+ .dischargeModalBody {
10
+ overflow: visible;
11
+ min-height: 14rem;
12
+ }
@@ -0,0 +1,59 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+
3
+ export type ProcessVisitResponse = {
4
+ service_type: string;
5
+ consentToken?: string;
6
+ invoiceNumber?: string | null;
7
+ interventions?: string[];
8
+ message?: string;
9
+ [key: string]: unknown;
10
+ };
11
+
12
+ export type SubmitVisitResponse = {
13
+ success?: boolean;
14
+ message?: string;
15
+ error?: string;
16
+ };
17
+
18
+ export function processVisitInsuranceClaim(visitUuid: string) {
19
+ return openmrsFetch<ProcessVisitResponse>(`${restBaseUrl}/insuranceclaims/phc/processVisit?visitUuid=${visitUuid}`, {
20
+ method: 'POST',
21
+ headers: { 'Content-Type': 'application/json' },
22
+ });
23
+ }
24
+
25
+ export async function sendDischargeOtp(
26
+ patientCRId: string,
27
+ consentToken: string,
28
+ ): Promise<{ success?: boolean; error?: string }> {
29
+ const params = new URLSearchParams({ patientId: patientCRId, consentToken });
30
+ const response = await openmrsFetch<{ success?: boolean; error?: string }>(
31
+ `${restBaseUrl}/insuranceclaims/phc/sendDischargeOtp?${params.toString()}`,
32
+ { method: 'POST' },
33
+ );
34
+ return response.data;
35
+ }
36
+
37
+ export async function submitVisitClaim(params: {
38
+ visitUuid: string;
39
+ otp?: string;
40
+ dischargeReason?: string;
41
+ dischargeAuthGuid?: string;
42
+ invoiceNumber?: string;
43
+ }): Promise<SubmitVisitResponse> {
44
+ const query = new URLSearchParams({ visitUuid: params.visitUuid, invoiceNumber: params.invoiceNumber ?? '' });
45
+ if (params.otp) {
46
+ query.set('otp', params.otp);
47
+ }
48
+ if (params.dischargeReason) {
49
+ query.set('dischargeReason', params.dischargeReason);
50
+ }
51
+ if (params.dischargeAuthGuid) {
52
+ query.set('dischargeAuthGuid', params.dischargeAuthGuid);
53
+ }
54
+ const response = await openmrsFetch<SubmitVisitResponse>(
55
+ `${restBaseUrl}/insuranceclaims/phc/submitVisit?${query.toString()}`,
56
+ { method: 'POST', headers: { 'Content-Type': 'application/json' } },
57
+ );
58
+ return response.data;
59
+ }
@@ -0,0 +1,285 @@
1
+ import { openmrsFetch, restBaseUrl, useConfig, usePatient, type FetchResponse } from '@openmrs/esm-framework';
2
+ import useSWR from 'swr';
3
+ import { type ExpressWorkflowConfig } from '../../../config-schema';
4
+ import {
5
+ AuthorizingDeviceOS,
6
+ BiometricAuthorizationStatus,
7
+ BiometricAuthorizeRequest,
8
+ BiometricAuthorizeResponse,
9
+ BiometricConfigResponse,
10
+ OTPResponse,
11
+ ProviderAttributesResponse,
12
+ WhitelistReason,
13
+ WhitelistStatusPoll,
14
+ WhitelistSubmitResponse,
15
+ } from '../type';
16
+
17
+ const virtualClaimBaseUrl = `${restBaseUrl}/virtualclaims`;
18
+
19
+ export const usePatientPhone = (patientUuid: string): string => {
20
+ const { data } = useSWR<
21
+ FetchResponse<{ person: { attributes: Array<{ attributeType: { display: string }; value: string }> } }>
22
+ >(
23
+ patientUuid
24
+ ? `${restBaseUrl}/patient/${patientUuid}?v=custom:(person:(attributes:(attributeType:(display),value)))`
25
+ : null,
26
+ openmrsFetch,
27
+ );
28
+ return (
29
+ data?.data?.person?.attributes?.find(
30
+ (attr) =>
31
+ attr.attributeType?.display?.toLowerCase().includes('phone') ||
32
+ attr.attributeType?.display?.toLowerCase().includes('telephone'),
33
+ )?.value ?? ''
34
+ );
35
+ };
36
+
37
+ export const usePatientCRId = (patientUuid: string): string | null => {
38
+ const { crIdentificationNumberUUID } = useConfig<ExpressWorkflowConfig>();
39
+ const { data } = useSWR<
40
+ FetchResponse<{ identifiers: Array<{ identifierType: { uuid: string }; identifier: string }> }>
41
+ >(
42
+ patientUuid
43
+ ? `${restBaseUrl}/patient/${patientUuid}?v=custom:(identifiers:(identifierType:(uuid),identifier))`
44
+ : null,
45
+ openmrsFetch,
46
+ );
47
+ return (
48
+ data?.data?.identifiers?.find((id) => id.identifierType?.uuid === crIdentificationNumberUUID)?.identifier ?? null
49
+ );
50
+ };
51
+
52
+ export interface EligibilityResponse {
53
+ requestIdType: number;
54
+ requestIdNumber: string;
55
+ memberCrNumber: string;
56
+ whitelistedForOTP: boolean;
57
+ facilityBiometricsEnforced: boolean;
58
+ fullName: string;
59
+ statusCode: string;
60
+ statusDesc: string;
61
+ schemes: Array<any>;
62
+ dateOfBirth?: string;
63
+ gender?: string;
64
+ age?: number;
65
+ }
66
+
67
+ export const useSHAEligibility = (patientUuid: string) => {
68
+ const { patient } = usePatient(patientUuid);
69
+ const { nationalIdUUID } = useConfig<ExpressWorkflowConfig>();
70
+
71
+ const nationalId = patient?.identifier?.find((id: any) =>
72
+ id?.type?.coding?.some((c: any) => c?.code === nationalIdUUID),
73
+ )?.value;
74
+
75
+ const url = nationalId
76
+ ? `${virtualClaimBaseUrl}/eligibility?identification_number=${encodeURIComponent(
77
+ nationalId,
78
+ )}&identification_type=${encodeURIComponent('National ID')}`
79
+ : null;
80
+
81
+ const { data, error, isLoading, mutate } = useSWR<{ data: EligibilityResponse }>(url, openmrsFetch, {
82
+ errorRetryCount: 0,
83
+ revalidateOnFocus: false,
84
+ dedupingInterval: 60_000,
85
+ });
86
+
87
+ return {
88
+ data: data?.data,
89
+ isPatientWhiteListed: data?.data?.whitelistedForOTP ?? false,
90
+ facilityBiometricsEnforced: data?.data?.facilityBiometricsEnforced ?? false,
91
+ isLoading,
92
+ error,
93
+ mutate,
94
+ };
95
+ };
96
+
97
+ export const useProviderNationalId = (providerUuid: string) => {
98
+ const { providerNationalIdUuid } = useConfig<ExpressWorkflowConfig>();
99
+ const customRep = 'custom:(attributes:(attributeType:(uuid,display),value))';
100
+ const url = providerUuid ? `${restBaseUrl}/provider/${providerUuid}?v=${customRep}` : null;
101
+ const { data, isLoading, error } = useSWR<FetchResponse<ProviderAttributesResponse>>(url, openmrsFetch);
102
+ const providerNationalid = data?.data?.attributes?.find(
103
+ (attr) => attr.attributeType.uuid === providerNationalIdUuid,
104
+ )?.value;
105
+ return { providerNationalid, isLoading, error };
106
+ };
107
+
108
+ export const useBiometricConfig = () => {
109
+ const { data, error, isLoading } = useSWR<FetchResponse<BiometricConfigResponse>>(
110
+ `${virtualClaimBaseUrl}/biometric-config`,
111
+ openmrsFetch,
112
+ );
113
+ return {
114
+ agentUrl: data?.data?.agent_url,
115
+ agentTimeoutMs: data?.data?.agent_timeout_ms,
116
+ isLoading,
117
+ error,
118
+ };
119
+ };
120
+
121
+ export interface BiometricAgentStatus {
122
+ devices: any[];
123
+ card_readers: any[];
124
+ isAuthed: boolean;
125
+ workstationID: string;
126
+ version: string;
127
+ }
128
+
129
+ export const useBiometricAgentStatus = (agentUrl: string | undefined) => {
130
+ const { data, error, isLoading } = useSWR<BiometricAgentStatus>(
131
+ agentUrl ?? null,
132
+ async (url: string) => {
133
+ const res = await fetch(url, { method: 'GET', headers: { Accept: 'application/json' } });
134
+ if (!res.ok) {
135
+ throw new Error(`Biometric agent returned ${res.status}`);
136
+ }
137
+ return res.json();
138
+ },
139
+ { revalidateOnFocus: false, shouldRetryOnError: false, dedupingInterval: 30_000 },
140
+ );
141
+ return {
142
+ workstationId: data?.workstationID,
143
+ isAuthed: data?.isAuthed ?? false,
144
+ isLoading,
145
+ error,
146
+ };
147
+ };
148
+
149
+ export const useOtpWhitelistReasons = () => {
150
+ const { data, isLoading, error } = useSWR<FetchResponse<{ count: number; reasons: Array<WhitelistReason> }>>(
151
+ `${virtualClaimBaseUrl}/otp-whitelist-reasons`,
152
+ openmrsFetch,
153
+ {
154
+ revalidateOnFocus: false,
155
+ dedupingInterval: 5 * 60_000,
156
+ },
157
+ );
158
+ return { reasons: data?.data?.reasons ?? [], isLoading, error };
159
+ };
160
+
161
+ export const detectAuthorizingDeviceOS = (): AuthorizingDeviceOS => {
162
+ if (typeof navigator === 'undefined') {
163
+ return 'windows';
164
+ }
165
+ const uaDataPlatform = (
166
+ navigator as Navigator & { userAgentData?: { platform?: string } }
167
+ ).userAgentData?.platform?.toLowerCase();
168
+ if (uaDataPlatform?.includes('android')) {
169
+ return 'android';
170
+ }
171
+ if (uaDataPlatform?.includes('windows')) {
172
+ return 'windows';
173
+ }
174
+ const userAgent = navigator.userAgent?.toLowerCase() ?? '';
175
+ if (userAgent.includes('android')) {
176
+ return 'android';
177
+ }
178
+ return 'windows';
179
+ };
180
+
181
+ export const sendSHAOtp = async (
182
+ patientCRId: string,
183
+ options: string[] | { consentToken: string },
184
+ ): Promise<OTPResponse> => {
185
+ const body = Array.isArray(options)
186
+ ? { patient_id: patientCRId, intervention_codes: options }
187
+ : { patient_id: patientCRId, consent_token: options.consentToken };
188
+
189
+ const response = await openmrsFetch(`${virtualClaimBaseUrl}/otp`, {
190
+ method: 'POST',
191
+ headers: { 'Content-Type': 'application/json' },
192
+ body,
193
+ });
194
+ return response.data;
195
+ };
196
+
197
+ export const createSHABiometricAuthorize = async (
198
+ payload: BiometricAuthorizeRequest,
199
+ ): Promise<BiometricAuthorizeResponse> => {
200
+ const response = await openmrsFetch(`${virtualClaimBaseUrl}/biometric-authorize`, {
201
+ method: 'POST',
202
+ headers: { 'Content-Type': 'application/json' },
203
+ body: payload,
204
+ });
205
+ return response.data;
206
+ };
207
+
208
+ export const checkBiometricAuthorizationStatus = async (token: string): Promise<BiometricAuthorizationStatus> => {
209
+ const response = await openmrsFetch<BiometricAuthorizationStatus>(
210
+ `${virtualClaimBaseUrl}/biometric-authorization-status?token=${encodeURIComponent(token)}`,
211
+ );
212
+ return response.data;
213
+ };
214
+
215
+ export const rejectBiometricAuthorization = async (
216
+ token: string,
217
+ ): Promise<{ success: boolean; message?: string; error?: string }> => {
218
+ const response = await openmrsFetch(`${virtualClaimBaseUrl}/biometric-reject`, {
219
+ method: 'POST',
220
+ headers: { 'Content-Type': 'application/json' },
221
+ body: { token },
222
+ });
223
+ return response.data;
224
+ };
225
+
226
+ export const fetchWhitelistStatus = async (beneficiaryCrId: string): Promise<WhitelistStatusPoll> => {
227
+ const response = await openmrsFetch(
228
+ `${virtualClaimBaseUrl}/otp-whitelist-status?beneficiary_cr_id=${encodeURIComponent(beneficiaryCrId)}`,
229
+ );
230
+ return response.data;
231
+ };
232
+
233
+ /**
234
+ * Submits a visit insurance claim and ends the visit in a single call.
235
+ * Call this after obtaining OTP or biometric authorisation.
236
+ *
237
+ * @param visitUuid - UUID of the active visit to end.
238
+ * @param otp - OTP supplied by the patient (optional — omit when using biometric auth).
239
+ * @param dischargeReason - Discharge reason code (e.g. RECOVERED, REFERRED, ABSCONDED, OTHER).
240
+ * @param dischargeAuthGuid - GUID returned by the biometric authorisation flow (optional — omit when using OTP).
241
+ */
242
+ export const submitVisitClaim = async (params: {
243
+ visitUuid: string;
244
+ otp?: string;
245
+ dischargeReason?: string;
246
+ dischargeAuthGuid?: string;
247
+ }): Promise<{ success: boolean; message?: string; error?: string }> => {
248
+ const query = new URLSearchParams({ visitUuid: params.visitUuid });
249
+ if (params.otp) {
250
+ query.set('otp', params.otp);
251
+ }
252
+ if (params.dischargeReason) {
253
+ query.set('dischargeReason', params.dischargeReason);
254
+ }
255
+ if (params.dischargeAuthGuid) {
256
+ query.set('dischargeAuthGuid', params.dischargeAuthGuid);
257
+ }
258
+ const response = await openmrsFetch(`${restBaseUrl}/insuranceclaims/phc/submitVisit?${query.toString()}`, {
259
+ method: 'POST',
260
+ headers: { 'Content-Type': 'application/json' },
261
+ });
262
+ return response.data;
263
+ };
264
+
265
+ export const submitOtpWhitelist = async (params: {
266
+ beneficiaryCrId: string;
267
+ reasonType: string;
268
+ reason: string;
269
+ biometricAttempts: number;
270
+ attachment: File | null;
271
+ }): Promise<WhitelistSubmitResponse> => {
272
+ const formData = new FormData();
273
+ formData.append('beneficiary_cr_id', params.beneficiaryCrId);
274
+ formData.append('reason_type', params.reasonType);
275
+ formData.append('reason', params.reason);
276
+ formData.append('biometric_attempts', String(params.biometricAttempts));
277
+ if (params.attachment && params.attachment.size > 0) {
278
+ formData.append('attachment', params.attachment, params.attachment.name);
279
+ }
280
+ const response = await openmrsFetch(`${virtualClaimBaseUrl}/otp-whitelists`, {
281
+ method: 'POST',
282
+ body: formData,
283
+ });
284
+ return response.data;
285
+ };