@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,158 @@
1
+ import React, { useRef, useState, useMemo } from 'react';
2
+ import { Button, ButtonSet, ModalBody, ModalFooter, InlineNotification } from '@carbon/react';
3
+ import { useReactToPrint } from 'react-to-print';
4
+ import { formatDatetime, parseDate, useSession } from '@openmrs/esm-framework';
5
+ import { useTranslation } from 'react-i18next';
6
+ import styles from './print-order.scss';
7
+ import { Order } from '../../../types/order/order';
8
+ import { documentId } from '../../utils';
9
+ export type OrderDocumentType = 'lab' | 'radiology' | 'procedure';
10
+
11
+ type PrintOrderPreviewModalProps = {
12
+ onClose: () => void;
13
+ orders: Array<Order>;
14
+ orderType: OrderDocumentType;
15
+ patientName?: string;
16
+ patientId?: string;
17
+ patientAge?: string | number;
18
+ };
19
+
20
+ const documentMeta = (
21
+ orderType: OrderDocumentType,
22
+ t: (k: string, d: string) => string,
23
+ ): { title: string; orderLabel: string } => {
24
+ switch (orderType) {
25
+ case 'lab':
26
+ return { title: t('labOrderForm', 'Laboratory Order Form'), orderLabel: t('test', 'Test') };
27
+ case 'radiology':
28
+ return { title: t('radiologyOrderForm', 'Radiology Order Form'), orderLabel: t('procedure', 'Procedure') };
29
+ case 'procedure':
30
+ return { title: t('procedureOrderForm', 'Procedure Order Form'), orderLabel: t('procedure', 'Procedure') };
31
+ default:
32
+ return { title: t('orderForm', 'Order Form'), orderLabel: t('order', 'Order') };
33
+ }
34
+ };
35
+
36
+ const PrintOrderPreviewModal: React.FC<PrintOrderPreviewModalProps> = ({
37
+ onClose,
38
+ orders,
39
+ orderType,
40
+ patientName,
41
+ patientId,
42
+ patientAge,
43
+ }) => {
44
+ const { t } = useTranslation();
45
+ const [printError, setPrintError] = useState<string | null>(null);
46
+ const printRef = useRef<HTMLDivElement>(null);
47
+ const { sessionLocation, user } = useSession();
48
+ const userDisplay = user ? user.display : '';
49
+ const generationTimestamp = useMemo(() => new Date(), []);
50
+ const { title, orderLabel } = documentMeta(orderType, t);
51
+
52
+ const handlePrint = useReactToPrint({
53
+ content: () => printRef.current,
54
+ documentTitle: title,
55
+ onAfterPrint: () => setPrintError(null),
56
+ onPrintError: (_, error) => {
57
+ setPrintError(error?.message || t('errorOccurredWhilePrinting', 'An error occurred while printing'));
58
+ },
59
+ pageStyle: `
60
+ @page {
61
+ size: A4;
62
+ margin: 15mm;
63
+ }
64
+ `,
65
+ });
66
+
67
+ return (
68
+ <>
69
+ <ModalBody>
70
+ <div className={styles.container}>
71
+ <div ref={printRef} className={styles.printableContent}>
72
+ <div className={styles.printableHeader}>
73
+ <div className={styles.facilityDetails}>
74
+ <div className={styles.facilityName}>{sessionLocation?.display}</div>
75
+ <div className={styles.heading}>{title}</div>
76
+ </div>
77
+ </div>
78
+
79
+ <div className={styles.printableBody}>
80
+ <div className={styles.topInfoRow}>
81
+ <div className={styles.infoItem}>
82
+ <span className={styles.label}>{t('patientName', 'Patient Name:')}</span>
83
+ <span className={styles.value}>{patientName || ''}</span>
84
+ </div>
85
+ <div className={styles.infoItem}>
86
+ <span className={styles.label}>{t('patientNo', 'Patient No:')}</span>
87
+ <span className={styles.value}>{patientId || ''}</span>
88
+ </div>
89
+ <div className={styles.infoItem}>
90
+ <span className={styles.label}>{t('age', 'Age:')}</span>
91
+ <span className={styles.value}>{patientAge ?? ''}</span>
92
+ </div>
93
+ <div className={styles.infoItem}>
94
+ <span className={styles.label}>{t('date', 'Date:')}</span>
95
+ <span className={styles.value}>{formatDatetime(generationTimestamp, { mode: 'standard' })}</span>
96
+ </div>
97
+ </div>
98
+
99
+ <table className={styles.orderTable}>
100
+ <thead>
101
+ <tr>
102
+ <th className={styles.th}>{t('orderNo', 'Order No')}</th>
103
+ <th className={styles.th}>{t('dateOrdered', 'Date Ordered')}</th>
104
+ <th className={styles.th}>{orderLabel}</th>
105
+ <th className={styles.th}>{t('priority', 'Priority')}</th>
106
+ <th className={styles.th}>{t('orderBy', 'Order By')}</th>
107
+ </tr>
108
+ </thead>
109
+ <tbody>
110
+ {orders.map((order) => (
111
+ <tr key={order.uuid}>
112
+ <td className={styles.td}>{order.orderNumber}</td>
113
+ <td className={styles.td}>
114
+ {order.dateActivated
115
+ ? formatDatetime(parseDate(order.dateActivated), { mode: 'standard' })
116
+ : '--'}
117
+ </td>
118
+ <td className={styles.td}>{order.concept?.display?.replace('_', ' ') ?? '--'}</td>
119
+ <td className={styles.td}>{order.urgency ?? '--'}</td>
120
+ <td className={styles.td}>{order.orderer?.display ?? '--'}</td>
121
+ </tr>
122
+ ))}
123
+ </tbody>
124
+ </table>
125
+ <div className={styles.footer}>
126
+ <div className={styles.footerDetails}>
127
+ <div>
128
+ {documentId()} | {t('generatedBy', 'Generated By')}: {userDisplay}
129
+ </div>
130
+ <div>
131
+ {t('generationTimestamp', 'Generated')}: {formatDatetime(generationTimestamp)} |{' '}
132
+ {t('facility', 'Facility')}: {sessionLocation?.display}
133
+ </div>
134
+ </div>
135
+ </div>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </ModalBody>
140
+ <ModalFooter>
141
+ <ButtonSet className={styles.btnSet}>
142
+ <Button kind="secondary" onClick={onClose} type="button">
143
+ {t('cancel', 'Cancel')}
144
+ </Button>
145
+ <Button kind="primary" type="button" onClick={handlePrint}>
146
+ {t('print', 'Print')}
147
+ </Button>
148
+ </ButtonSet>
149
+ </ModalFooter>
150
+
151
+ {printError && (
152
+ <InlineNotification kind="error" title={t('printError', 'Error')} subtitle={printError} hideCloseButton />
153
+ )}
154
+ </>
155
+ );
156
+ };
157
+
158
+ export default PrintOrderPreviewModal;
@@ -0,0 +1,225 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+
4
+ .container {
5
+ padding: layout.$spacing-06;
6
+ margin-bottom: layout.$spacing-05;
7
+ background-color: colors.$white;
8
+
9
+ @media print {
10
+ padding: 0;
11
+ margin: 0;
12
+ }
13
+ }
14
+
15
+ .printableContent {
16
+ background-color: colors.$white;
17
+ width: 210mm;
18
+ min-height: 297mm;
19
+ margin: 0 auto;
20
+ padding: layout.$spacing-07;
21
+ box-sizing: border-box;
22
+ font-size: 11px;
23
+ line-height: 1.3;
24
+ color: colors.$black;
25
+
26
+ @media print {
27
+ width: 100%;
28
+ height: 100%;
29
+ padding: layout.$spacing-07;
30
+ margin: 0;
31
+ box-shadow: none;
32
+ border: none;
33
+ }
34
+ }
35
+
36
+ .printableHeader {
37
+ text-align: center;
38
+ margin-bottom: layout.$spacing-05;
39
+ padding-bottom: layout.$spacing-03;
40
+ border-bottom: 1px solid colors.$black;
41
+ }
42
+
43
+ .facilityDetails {
44
+ display: flex;
45
+ flex-direction: column;
46
+ align-items: center;
47
+ }
48
+
49
+ .facilityName {
50
+ font-weight: 700;
51
+ color: colors.$black;
52
+ text-transform: uppercase;
53
+ letter-spacing: 2px;
54
+ margin-bottom: layout.$spacing-03;
55
+ font-size: 14px;
56
+ }
57
+
58
+ .heading {
59
+ font-weight: 600;
60
+ color: colors.$black;
61
+ text-transform: uppercase;
62
+ letter-spacing: 1px;
63
+ font-size: 12px;
64
+ }
65
+
66
+ .printableBody {
67
+ display: flex;
68
+ flex-direction: column;
69
+ gap: layout.$spacing-05;
70
+ }
71
+
72
+ .topInfoRow {
73
+ display: grid;
74
+ grid-template-columns: repeat(4, 1fr);
75
+ gap: layout.$spacing-03;
76
+ padding: layout.$spacing-03;
77
+ border: 1px solid colors.$black;
78
+ border-radius: 2px;
79
+ }
80
+
81
+ .infoItem {
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: layout.$spacing-02;
85
+ }
86
+
87
+ .label {
88
+ font-weight: 600;
89
+ color: colors.$black;
90
+ font-size: 10px;
91
+ white-space: nowrap;
92
+ }
93
+
94
+ .value {
95
+ color: colors.$black;
96
+ border-bottom: 1px solid colors.$black;
97
+ padding: layout.$spacing-01;
98
+ min-height: layout.$spacing-04;
99
+ display: flex;
100
+ align-items: center;
101
+ font-size: 10px;
102
+ }
103
+
104
+ .orderTable {
105
+ width: 100%;
106
+ border-collapse: collapse;
107
+ font-size: 10px;
108
+ }
109
+
110
+ .th {
111
+ border: 1px solid colors.$black;
112
+ padding: layout.$spacing-03;
113
+ text-align: left;
114
+ font-weight: 600;
115
+ background-color: colors.$gray-10;
116
+ text-transform: uppercase;
117
+ font-size: 9px;
118
+
119
+ @media print {
120
+ background-color: colors.$gray-10 !important;
121
+ -webkit-print-color-adjust: exact;
122
+ print-color-adjust: exact;
123
+ }
124
+ }
125
+
126
+ .td {
127
+ border: 1px solid colors.$black;
128
+ padding: layout.$spacing-03;
129
+ color: colors.$black;
130
+ }
131
+
132
+ .signaturesSection {
133
+ margin-top: layout.$spacing-05;
134
+ padding-top: layout.$spacing-03;
135
+ border-top: 1px solid colors.$black;
136
+ }
137
+
138
+ .signatureBlock {
139
+ margin-bottom: layout.$spacing-03;
140
+ }
141
+
142
+ .signatureRow {
143
+ display: grid;
144
+ grid-template-columns: 2fr 1fr 1fr;
145
+ gap: layout.$spacing-03;
146
+ align-items: center;
147
+ padding: layout.$spacing-02;
148
+ }
149
+
150
+ .nameField,
151
+ .signField {
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: layout.$spacing-02;
155
+ }
156
+
157
+ .nameValue {
158
+ color: colors.$black;
159
+ border-bottom: 1px solid colors.$black;
160
+ padding: layout.$spacing-01;
161
+ min-height: layout.$spacing-04;
162
+ display: flex;
163
+ align-items: center;
164
+ font-size: 10px;
165
+ }
166
+
167
+ .signatureLine {
168
+ border-bottom: 1px solid colors.$black;
169
+ height: layout.$spacing-04;
170
+ width: 100%;
171
+ }
172
+
173
+ .btnSet {
174
+ width: 100%;
175
+ margin-top: layout.$spacing-05;
176
+ }
177
+
178
+ .footer {
179
+ margin-top: layout.$spacing-06;
180
+ padding-top: layout.$spacing-04;
181
+ border-top: 1px solid colors.$black;
182
+ text-align: center;
183
+ page-break-inside: avoid;
184
+
185
+ @media print {
186
+ position: fixed !important;
187
+ bottom: layout.$spacing-05 !important;
188
+ left: 0 !important;
189
+ right: 0 !important;
190
+ width: 100% !important;
191
+ border-top: 0.5pt solid colors.$gray-50 !important;
192
+ box-sizing: border-box !important;
193
+ }
194
+ }
195
+
196
+ .footerDetails {
197
+ font-size: 7pt;
198
+ color: colors.$gray-70;
199
+ text-align: center;
200
+ line-height: 1.3;
201
+
202
+ div {
203
+ margin-bottom: layout.$spacing-02;
204
+ &:last-child {
205
+ margin-bottom: 0;
206
+ }
207
+ }
208
+ }
209
+
210
+ @media print {
211
+ body * {
212
+ visibility: hidden;
213
+ }
214
+ .printableContent,
215
+ .printableContent * {
216
+ visibility: visible;
217
+ }
218
+ .printableContent {
219
+ position: absolute;
220
+ left: 0;
221
+ top: 0;
222
+ width: 100%;
223
+ padding: layout.$spacing-07;
224
+ }
225
+ }
@@ -0,0 +1,65 @@
1
+ import React, { useRef } from 'react';
2
+ import { Button, ButtonSet, ModalBody, ModalFooter, InlineLoading, InlineNotification } from '@carbon/react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { usePrescriptionPdf } from './print-prescription.resource';
5
+ import styles from './print-prescription.scss';
6
+
7
+ type PrintPrescriptionModalProps = {
8
+ onClose: () => void;
9
+ medicationRequestUuids: string[];
10
+ };
11
+
12
+ const PrintPrescriptionModal: React.FC<PrintPrescriptionModalProps> = ({ onClose, medicationRequestUuids }) => {
13
+ const { t } = useTranslation();
14
+ const iframeRef = useRef<HTMLIFrameElement>(null);
15
+ const { pdfUrl, isLoading, error } = usePrescriptionPdf(medicationRequestUuids);
16
+
17
+ const handlePrint = () => {
18
+ if (iframeRef.current?.contentWindow) {
19
+ iframeRef.current.contentWindow.focus();
20
+ iframeRef.current.contentWindow.print();
21
+ }
22
+ };
23
+
24
+ return (
25
+ <>
26
+ <ModalBody className={styles.modalBody}>
27
+ {isLoading && (
28
+ <div className={styles.stateContainer}>
29
+ <InlineLoading description={t('loadingPrescription', 'Loading prescription...')} />
30
+ </div>
31
+ )}
32
+ {error && !isLoading && (
33
+ <div className={styles.stateContainer}>
34
+ <InlineNotification
35
+ kind="error"
36
+ title={t('errorLoadingPrescription', 'Error loading prescription')}
37
+ subtitle={error.message}
38
+ hideCloseButton
39
+ />
40
+ </div>
41
+ )}
42
+ {pdfUrl && !isLoading && (
43
+ <iframe
44
+ ref={iframeRef}
45
+ src={pdfUrl}
46
+ className={styles.pdfFrame}
47
+ title={t('prescriptionPreview', 'Prescription Preview')}
48
+ />
49
+ )}
50
+ </ModalBody>
51
+ <ModalFooter>
52
+ <ButtonSet className={styles.btnSet}>
53
+ <Button kind="secondary" onClick={onClose} type="button">
54
+ {t('cancel', 'Cancel')}
55
+ </Button>
56
+ <Button kind="primary" type="button" onClick={handlePrint} disabled={!pdfUrl || isLoading}>
57
+ {t('print', 'Print')}
58
+ </Button>
59
+ </ButtonSet>
60
+ </ModalFooter>
61
+ </>
62
+ );
63
+ };
64
+
65
+ export default PrintPrescriptionModal;
@@ -0,0 +1,45 @@
1
+ import { restBaseUrl } from '@openmrs/esm-framework';
2
+ import { useEffect, useMemo, useState } from 'react';
3
+
4
+ export function usePrescriptionPdf(medicationRequestUuids: string[]) {
5
+ const [pdfUrl, setPdfUrl] = useState<string | null>(null);
6
+ const [isLoading, setIsLoading] = useState(false);
7
+ const [error, setError] = useState<Error | null>(null);
8
+
9
+ const uuidParam = useMemo(() => medicationRequestUuids.join(','), [medicationRequestUuids]);
10
+
11
+ useEffect(() => {
12
+ if (!uuidParam) {
13
+ return;
14
+ }
15
+
16
+ let objectUrl: string | null = null;
17
+ setIsLoading(true);
18
+ setPdfUrl(null);
19
+ setError(null);
20
+
21
+ const url = `/openmrs${restBaseUrl}/palladiumemr/prescription?medicationRequestUuid=${uuidParam}`;
22
+
23
+ fetch(url, { credentials: 'include', headers: { Accept: 'application/pdf' } })
24
+ .then((response) => {
25
+ if (!response.ok) {
26
+ throw new Error(`${response.status} ${response.statusText}`);
27
+ }
28
+ return response.blob();
29
+ })
30
+ .then((blob) => {
31
+ objectUrl = URL.createObjectURL(new Blob([blob], { type: 'application/pdf' }));
32
+ setPdfUrl(objectUrl);
33
+ })
34
+ .catch((err) => setError(err instanceof Error ? err : new Error(String(err))))
35
+ .finally(() => setIsLoading(false));
36
+
37
+ return () => {
38
+ if (objectUrl) {
39
+ URL.revokeObjectURL(objectUrl);
40
+ }
41
+ };
42
+ }, [uuidParam]);
43
+
44
+ return { pdfUrl, isLoading, error };
45
+ }
@@ -0,0 +1,25 @@
1
+ @use '@carbon/layout';
2
+
3
+ .modalBody {
4
+ padding: 0;
5
+ min-height: 70vh;
6
+ display: flex;
7
+ flex-direction: column;
8
+ }
9
+
10
+ .pdfFrame {
11
+ width: 100%;
12
+ flex: 1;
13
+ min-height: 70vh;
14
+ border: none;
15
+ }
16
+
17
+ .stateContainer {
18
+ padding: layout.$spacing-06;
19
+ display: flex;
20
+ justify-content: center;
21
+ }
22
+
23
+ .btnSet {
24
+ width: 100%;
25
+ }
@@ -3,7 +3,36 @@ import { default as otpVerificationModal } from './otp-verification.modal';
3
3
  import { type ModalSize } from '@carbon/react/lib/components/Modal/Modal';
4
4
 
5
5
  /**
6
- * Options for configuring the OTP Verification modal.
6
+ * Result returned by onStartBiometric — the caller's `/biometric-authorize`
7
+ * handler resolves with this shape so the modal knows the embed URL to render
8
+ * and the auth code to round-trip on success.
9
+ */
10
+ export type BiometricStartResult = {
11
+ embed_url: string;
12
+ authorization_code: string;
13
+ consent_token: string;
14
+ };
15
+
16
+ /**
17
+ * Result handed to onBiometricSuccess when the iframe's eKYC capture completes
18
+ * successfully (postMessage from the eKYC origin).
19
+ */
20
+ export type BiometricSuccessResult = {
21
+ authorization_code: string;
22
+ consent_token: string;
23
+ };
24
+
25
+ /**
26
+ * Options for configuring the OTP / Secure Patient Authentication modal.
27
+ *
28
+ * The modal supports two operating modes:
29
+ *
30
+ * 1. **otp-only** (default, backward compatible) — opens directly into the
31
+ * existing OTP confirm-phone screen. Use this when the only auth path is OTP.
32
+ * All existing consumers don't need to change.
33
+ *
34
+ * 2. **multi** — opens an auth landing screen with three options: biometric,
35
+ * OTP, or whitelist request. The available options depend on `whitelistedForOTP`.
7
36
  *
8
37
  * @property {number} [otpLength] - The number of digits required for the OTP. Defaults to implementation-specific value.
9
38
  * @property {(otp: string) => Promise<void>} [onVerify] - Callback invoked when the user submits the OTP. Should return a promise that resolves on successful verification.
@@ -15,35 +44,61 @@ import { type ModalSize } from '@carbon/react/lib/components/Modal/Modal';
15
44
  * @property {number} [expiryMinutes] - The number of minutes after which the OTP expires. Defaults to 5 minutes. This is displayed to the user for clarity.
16
45
  * @property {() => void} [onCleanup] - Callback invoked when the modal closes to clean up OTP resources.
17
46
  *
47
+ * @property {'otp-only' | 'multi'} [authMode] - When 'multi', shows the auth-landing method picker first (Biometric / OTP / Whitelist). When 'otp-only' or undefined, opens directly to the existing OTP landing.
48
+ * @property {boolean} [whitelistedForOTP] - Whether the patient is approved for OTP whitelist bypass. Drives method picker layout and post-failure recovery options.
49
+ * @property {() => Promise<BiometricStartResult>} [onStartBiometric] - Called when the user picks biometric. Should resolve with the embed_url + auth code from /biometric-authorize.
50
+ * @property {(result: BiometricSuccessResult) => void} [onBiometricSuccess] - Called on successful biometric capture (iframe postMessage SUCCESS).
51
+ * @property {(consentToken: string | null) => void} [onBiometricCancel] - Called when biometric session is cancelled (user closes, timer expires). Backend's /biometric-cancel goes here.
52
+ * @property {() => void} [onRequestWhitelist] - Called when the user clicks "Request OTP Whitelisting" — parent should open the whitelist submission flow.
53
+ * @property {() => void} [onRejected] - Called when the user clicks "Reject" on the auth landing — visit proceeds without consent (administrative override).
54
+ * @property {string} [ekycOrigin] - Expected origin of the eKYC iframe's postMessage events for security validation. Defaults to https://test.ekyc.pesaflow.com.
55
+ *
56
+ * @example
57
+ * // OTP-only mode (existing behavior, unchanged)
58
+ * launchOtpVerificationModal({
59
+ * otpLength: 6,
60
+ * phoneNumber: '254700000000',
61
+ * onRequestOtp: async (phone) => sendSHAOtp(crId, codes),
62
+ * onVerify: async (otp) => createSHAVirtualClaim(crId, otp, ...),
63
+ * onVerificationSuccess: () => console.log('verified'),
64
+ * });
65
+ *
18
66
  * @example
19
- * <Button
20
- * onClick={() =>
21
- * launchOtpVerificationModal({
22
- * otpLength: 4,
23
- * obscureText: false,
24
- * phoneNumber: '254700000000',
25
- * expiryMinutes: 10, // OTP expires in 10 minutes
26
- * onRequestOtp: (phone) =>
27
- * new Promise((resolve, reject) => {
28
- * const success = true;
29
- * setTimeout(() => (success ? resolve() : reject(new Error('Some error'))), 3000);
30
- * }),
31
- * onVerify: async (otp) =>
32
- * new Promise((resolve, reject) => {
33
- * const success = true;
34
- * setTimeout(() => (success ? resolve() : reject(new Error('Some error'))), 3000);
35
- * }),
36
- * onCleanup: () => {
37
- * // Clean up OTP resources
38
- * otpManager.cleanupExpiredOTPs();
39
- * },
40
- * })
41
- * }
42
- * >
43
- * Launch OTP verification Modal
44
- * </Button>
67
+ * // Multi-method auth mode (biometric + OTP + whitelist)
68
+ * launchOtpVerificationModal({
69
+ * authMode: 'multi',
70
+ * whitelistedForOTP: patient.whitelisted_for_otp ?? false,
71
+ * phoneNumber: '254700000000',
72
+ *
73
+ * // OTP wiring
74
+ * onRequestOtp: async (phone) => sendSHAOtp(crId, codes),
75
+ * onVerify: async (otp) => createSHAVirtualClaim(crId, otp, ...),
76
+ * onVerificationSuccess: () => { ... },
77
+ *
78
+ * // Biometric wiring
79
+ * onStartBiometric: async () => {
80
+ * const res = await createSHABiometricAuthorize({ ... });
81
+ * if (!res.success || !res.embed_url) throw new Error(res.error);
82
+ * return {
83
+ * embed_url: res.embed_url,
84
+ * authorization_code: res.authorization_code!,
85
+ * consent_token: res.consent_token!,
86
+ * };
87
+ * },
88
+ * onBiometricSuccess: (result) => {
89
+ * shaClaimResponseRef.current = result;
90
+ * },
91
+ * onBiometricCancel: async (consentToken) => {
92
+ * if (consentToken) await cancelBiometricSession(consentToken);
93
+ * },
94
+ *
95
+ * // Escape paths
96
+ * onRequestWhitelist: () => launchWhitelistSubmissionModal({ patientCRId }),
97
+ * onRejected: () => markVisitProceedingWithoutConsent(),
98
+ * });
45
99
  */
46
100
  export type OTPVerificationModalOptions = {
101
+ // ── existing OTP props ──
47
102
  otpLength?: number;
48
103
  onVerify?: (otp: string) => Promise<void>;
49
104
  obscureText?: boolean;
@@ -54,12 +109,40 @@ export type OTPVerificationModalOptions = {
54
109
  expiryMinutes?: number;
55
110
  size?: ModalSize;
56
111
  onCleanup?: () => void;
112
+
113
+ // ── new multi-method auth props ──
114
+ /** When 'multi', shows the auth-landing method picker first. Defaults to 'otp-only'. */
115
+ authMode?: 'otp-only' | 'multi';
116
+
117
+ /** Whether the patient is approved for OTP whitelist bypass. */
118
+ whitelistedForOTP?: boolean;
119
+
120
+ /** Called when user picks biometric. Resolve with embed_url + auth code. */
121
+ onStartBiometric?: () => Promise<BiometricStartResult>;
122
+
123
+ /** Called on successful biometric capture (postMessage SUCCESS from eKYC). */
124
+ onBiometricSuccess?: (result: BiometricSuccessResult) => void;
125
+
126
+ /** Called when biometric session is cancelled. Wire to backend /biometric-cancel. */
127
+ onBiometricCancel?: (consentToken: string | null) => void;
128
+
129
+ /** Called when user clicks "Request OTP Whitelisting". */
130
+ onRequestWhitelist?: () => void;
131
+
132
+ /** Called when user clicks "Reject" — visit proceeds without consent. */
133
+ onRejected?: () => void;
134
+
135
+ /** Expected origin of eKYC postMessage events. Defaults to https://test.ekyc.pesaflow.com. */
136
+ ekycOrigin?: string;
137
+
138
+ /** Whether this modal is being used to start or end a visit. Defaults to 'start'. Affects progress message text. */
139
+ visitAction?: 'start' | 'end';
57
140
  };
58
141
 
59
142
  /**
60
- * Launch the OTP verification modal with the provided options
143
+ * Launch the OTP / Secure Patient Authentication modal with the provided options.
61
144
  *
62
- * @param props - Configuration options for the OTP verification modal
145
+ * @param props - Configuration options for the modal
63
146
  * @returns A dispose function to close the modal programmatically
64
147
  */
65
148
  export const launchOtpVerificationModal = (props: OTPVerificationModalOptions) => {