@bathiran212/esm-patient-chart-app 7.0.0

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 (382) hide show
  1. package/README.md +3 -0
  2. package/dist/108.js +1 -0
  3. package/dist/108.js.map +1 -0
  4. package/dist/1339.js +1 -0
  5. package/dist/1339.js.map +1 -0
  6. package/dist/1480.js +1 -0
  7. package/dist/1480.js.map +1 -0
  8. package/dist/1543.js +1 -0
  9. package/dist/1543.js.map +1 -0
  10. package/dist/1582.js +1 -0
  11. package/dist/1582.js.map +1 -0
  12. package/dist/1646.js +1 -0
  13. package/dist/1646.js.map +1 -0
  14. package/dist/1797.js +1 -0
  15. package/dist/1797.js.map +1 -0
  16. package/dist/1869.js +1 -0
  17. package/dist/1869.js.map +1 -0
  18. package/dist/1877.js +1 -0
  19. package/dist/1877.js.map +1 -0
  20. package/dist/2020.js +1 -0
  21. package/dist/2020.js.map +1 -0
  22. package/dist/2246.js +1 -0
  23. package/dist/2246.js.map +1 -0
  24. package/dist/2317.js +1 -0
  25. package/dist/2317.js.map +1 -0
  26. package/dist/2416.js +1 -0
  27. package/dist/2416.js.map +1 -0
  28. package/dist/2790.js +1 -0
  29. package/dist/2790.js.map +1 -0
  30. package/dist/282.js +1 -0
  31. package/dist/282.js.map +1 -0
  32. package/dist/2881.js +1 -0
  33. package/dist/2881.js.map +1 -0
  34. package/dist/3137.js +1 -0
  35. package/dist/3137.js.map +1 -0
  36. package/dist/3378.js +1 -0
  37. package/dist/3378.js.map +1 -0
  38. package/dist/3390.js +1 -0
  39. package/dist/3390.js.map +1 -0
  40. package/dist/3536.js +1 -0
  41. package/dist/3536.js.map +1 -0
  42. package/dist/3720.js +1 -0
  43. package/dist/3720.js.map +1 -0
  44. package/dist/3857.js +1 -0
  45. package/dist/3857.js.map +1 -0
  46. package/dist/3925.js +1 -0
  47. package/dist/3925.js.map +1 -0
  48. package/dist/3963.js +1 -0
  49. package/dist/3963.js.map +1 -0
  50. package/dist/3989.js +1 -0
  51. package/dist/3989.js.map +1 -0
  52. package/dist/4092.js +1 -0
  53. package/dist/4092.js.map +1 -0
  54. package/dist/4106.js +1 -0
  55. package/dist/4106.js.map +1 -0
  56. package/dist/4111.js +1 -0
  57. package/dist/4111.js.map +1 -0
  58. package/dist/4145.js +1 -0
  59. package/dist/4145.js.map +1 -0
  60. package/dist/434.js +1 -0
  61. package/dist/434.js.map +1 -0
  62. package/dist/4348.js +1 -0
  63. package/dist/4348.js.map +1 -0
  64. package/dist/4383.js +1 -0
  65. package/dist/4383.js.map +1 -0
  66. package/dist/4540.js +1 -0
  67. package/dist/4540.js.map +1 -0
  68. package/dist/4658.js +1 -0
  69. package/dist/4658.js.map +1 -0
  70. package/dist/466.js +1 -0
  71. package/dist/466.js.map +1 -0
  72. package/dist/4913.js +1 -0
  73. package/dist/4913.js.map +1 -0
  74. package/dist/4928.js +1 -0
  75. package/dist/4928.js.map +1 -0
  76. package/dist/5069.js +1 -0
  77. package/dist/5069.js.map +1 -0
  78. package/dist/5117.js +1 -0
  79. package/dist/5117.js.map +1 -0
  80. package/dist/5132.js +1 -0
  81. package/dist/5132.js.map +1 -0
  82. package/dist/5145.js +1 -0
  83. package/dist/5145.js.map +1 -0
  84. package/dist/52.js +1 -0
  85. package/dist/52.js.map +1 -0
  86. package/dist/5422.js +1 -0
  87. package/dist/5422.js.map +1 -0
  88. package/dist/5503.js +1 -0
  89. package/dist/5503.js.map +1 -0
  90. package/dist/5549.js +1 -0
  91. package/dist/5549.js.map +1 -0
  92. package/dist/556.js +1 -0
  93. package/dist/556.js.map +1 -0
  94. package/dist/5644.js +1 -0
  95. package/dist/5644.js.map +1 -0
  96. package/dist/5697.js +1 -0
  97. package/dist/5697.js.map +1 -0
  98. package/dist/5793.js +1 -0
  99. package/dist/5793.js.map +1 -0
  100. package/dist/5940.js +1 -0
  101. package/dist/5940.js.map +1 -0
  102. package/dist/5952.js +1 -0
  103. package/dist/5952.js.map +1 -0
  104. package/dist/6047.js +1 -0
  105. package/dist/6047.js.map +1 -0
  106. package/dist/6371.js +1 -0
  107. package/dist/6371.js.map +1 -0
  108. package/dist/6377.js +1 -0
  109. package/dist/6377.js.map +1 -0
  110. package/dist/6444.js +1 -0
  111. package/dist/6444.js.map +1 -0
  112. package/dist/6479.js +1 -0
  113. package/dist/6479.js.map +1 -0
  114. package/dist/6508.js +1 -0
  115. package/dist/6508.js.map +1 -0
  116. package/dist/6724.js +1 -0
  117. package/dist/6724.js.map +1 -0
  118. package/dist/6759.js +27 -0
  119. package/dist/6759.js.map +1 -0
  120. package/dist/689.js +1 -0
  121. package/dist/689.js.map +1 -0
  122. package/dist/6904.js +1 -0
  123. package/dist/6904.js.map +1 -0
  124. package/dist/7045.js +1 -0
  125. package/dist/7045.js.map +1 -0
  126. package/dist/7175.js +1 -0
  127. package/dist/7175.js.map +1 -0
  128. package/dist/7182.js +1 -0
  129. package/dist/7182.js.map +1 -0
  130. package/dist/7302.js +1 -0
  131. package/dist/7302.js.map +1 -0
  132. package/dist/7646.js +17 -0
  133. package/dist/7646.js.map +1 -0
  134. package/dist/7742.js +1 -0
  135. package/dist/7742.js.map +1 -0
  136. package/dist/7912.js +1 -0
  137. package/dist/7912.js.map +1 -0
  138. package/dist/8105.js +21 -0
  139. package/dist/8105.js.map +1 -0
  140. package/dist/8202.js +1 -0
  141. package/dist/8202.js.map +1 -0
  142. package/dist/8349.js +1 -0
  143. package/dist/8349.js.map +1 -0
  144. package/dist/8358.js +1 -0
  145. package/dist/8358.js.map +1 -0
  146. package/dist/8359.js +1 -0
  147. package/dist/8359.js.map +1 -0
  148. package/dist/8695.js +1 -0
  149. package/dist/8695.js.map +1 -0
  150. package/dist/8702.js +1 -0
  151. package/dist/8702.js.map +1 -0
  152. package/dist/8894.js +1 -0
  153. package/dist/8894.js.map +1 -0
  154. package/dist/8958.js +1 -0
  155. package/dist/8958.js.map +1 -0
  156. package/dist/903.js +1 -0
  157. package/dist/903.js.map +1 -0
  158. package/dist/9061.js +1 -0
  159. package/dist/9061.js.map +1 -0
  160. package/dist/9072.js +1 -0
  161. package/dist/9072.js.map +1 -0
  162. package/dist/9105.js +1 -0
  163. package/dist/9105.js.map +1 -0
  164. package/dist/9107.js +1 -0
  165. package/dist/9107.js.map +1 -0
  166. package/dist/9456.js +1 -0
  167. package/dist/9456.js.map +1 -0
  168. package/dist/9586.js +1 -0
  169. package/dist/9586.js.map +1 -0
  170. package/dist/9712.js +1 -0
  171. package/dist/9712.js.map +1 -0
  172. package/dist/9771.js +1 -0
  173. package/dist/9771.js.map +1 -0
  174. package/dist/9806.js +1 -0
  175. package/dist/9806.js.map +1 -0
  176. package/dist/9873.js +1 -0
  177. package/dist/9873.js.map +1 -0
  178. package/dist/9927.js +1 -0
  179. package/dist/9927.js.map +1 -0
  180. package/dist/main.js +6 -0
  181. package/dist/main.js.map +1 -0
  182. package/dist/openmrs-esm-patient-chart-app.js +6 -0
  183. package/dist/openmrs-esm-patient-chart-app.js.buildmanifest.json +2386 -0
  184. package/dist/openmrs-esm-patient-chart-app.js.map +1 -0
  185. package/dist/routes.json +1 -0
  186. package/package.json +63 -0
  187. package/rspack.config.js +1 -0
  188. package/src/actions-buttons/action-button.scss +3 -0
  189. package/src/actions-buttons/delete-visit.component.tsx +41 -0
  190. package/src/actions-buttons/delete-visit.test.tsx +26 -0
  191. package/src/actions-buttons/mark-patient-alive.component.tsx +42 -0
  192. package/src/actions-buttons/mark-patient-deceased.component.tsx +35 -0
  193. package/src/actions-buttons/start-visit.component.tsx +41 -0
  194. package/src/actions-buttons/start-visit.test.tsx +44 -0
  195. package/src/actions-buttons/stop-visit.component.tsx +39 -0
  196. package/src/actions-buttons/stop-visit.test.tsx +27 -0
  197. package/src/clinical-views/encounter-list/encounter-list-tabs.extension.tsx +78 -0
  198. package/src/clinical-views/encounter-list/encounter-list-tabs.scss +7 -0
  199. package/src/clinical-views/encounter-list/encounter-list.component.tsx +306 -0
  200. package/src/clinical-views/encounter-list/encounter-list.scss +36 -0
  201. package/src/clinical-views/encounter-list/table.component.tsx +63 -0
  202. package/src/clinical-views/encounter-list/table.scss +11 -0
  203. package/src/clinical-views/encounter-list/tag.component.test.tsx +307 -0
  204. package/src/clinical-views/encounter-list/tag.component.tsx +43 -0
  205. package/src/clinical-views/encounter-tile/clinical-views-summary.component.tsx +40 -0
  206. package/src/clinical-views/encounter-tile/encounter-tile.component.tsx +94 -0
  207. package/src/clinical-views/encounter-tile/tile.scss +82 -0
  208. package/src/clinical-views/hooks/index.ts +3 -0
  209. package/src/clinical-views/hooks/useEncounterRows.ts +60 -0
  210. package/src/clinical-views/hooks/useEncountersByVisit.ts +13 -0
  211. package/src/clinical-views/hooks/useFormsJson.ts +15 -0
  212. package/src/clinical-views/hooks/useLastEncounter.ts +29 -0
  213. package/src/clinical-views/types.ts +305 -0
  214. package/src/clinical-views/utils/concept-utils.ts +24 -0
  215. package/src/clinical-views/utils/encounter-list-config-builder.ts +160 -0
  216. package/src/clinical-views/utils/encounter-list.resource.ts +26 -0
  217. package/src/clinical-views/utils/helpers.ts +226 -0
  218. package/src/clinical-views/utils/index.ts +90 -0
  219. package/src/config-schema.ts +235 -0
  220. package/src/constants.ts +11 -0
  221. package/src/dashboard.meta.ts +15 -0
  222. package/src/data.resource.ts +117 -0
  223. package/src/declarations.d.ts +4 -0
  224. package/src/index.ts +204 -0
  225. package/src/loader/loader.component.tsx +11 -0
  226. package/src/loader/loader.scss +9 -0
  227. package/src/mark-patient-alive/mark-patient-alive.modal.tsx +54 -0
  228. package/src/mark-patient-deceased/mark-patient-deceased-form.scss +175 -0
  229. package/src/mark-patient-deceased/mark-patient-deceased-form.test.tsx +203 -0
  230. package/src/mark-patient-deceased/mark-patient-deceased-form.workspace.tsx +295 -0
  231. package/src/offline.ts +41 -0
  232. package/src/patient-banner-tags/visit-attribute-tags.extension.tsx +62 -0
  233. package/src/patient-banner-tags/visit-attribute-tags.scss +8 -0
  234. package/src/patient-chart/chart-review/chart-review.component.tsx +138 -0
  235. package/src/patient-chart/chart-review/chart-review.test.tsx +77 -0
  236. package/src/patient-chart/chart-review/dashboard-view.component.tsx +85 -0
  237. package/src/patient-chart/chart-review/dashboard-view.scss +84 -0
  238. package/src/patient-chart/patient-chart.component.tsx +71 -0
  239. package/src/patient-chart/patient-chart.resources.test.ts +238 -0
  240. package/src/patient-chart/patient-chart.resources.ts +231 -0
  241. package/src/patient-chart/patient-chart.scss +65 -0
  242. package/src/patient-details-tile/patient-details-tile.component.tsx +25 -0
  243. package/src/patient-details-tile/patient-details-tile.scss +24 -0
  244. package/src/root.component.tsx +35 -0
  245. package/src/root.scss +54 -0
  246. package/src/routes.json +267 -0
  247. package/src/side-nav/side-menu.component.tsx +10 -0
  248. package/src/side-nav/side-menu.scss +38 -0
  249. package/src/side-nav/side-menu.test.tsx +27 -0
  250. package/src/utils.test.ts +17 -0
  251. package/src/utils.ts +5 -0
  252. package/src/visit/hooks/useDefaultFacilityLocation.tsx +15 -0
  253. package/src/visit/hooks/useDefaultVisitLocation.tsx +24 -0
  254. package/src/visit/hooks/useDeleteVisit.test.tsx +267 -0
  255. package/src/visit/hooks/useDeleteVisit.tsx +103 -0
  256. package/src/visit/hooks/useOfflineVisitType.tsx +18 -0
  257. package/src/visit/hooks/useRecommendedVisitTypes.tsx +34 -0
  258. package/src/visit/hooks/useVisitAttributeType.tsx +102 -0
  259. package/src/visit/start-visit-button.component.tsx +47 -0
  260. package/src/visit/start-visit-button.test.tsx +32 -0
  261. package/src/visit/visit-action-items/delete-visit-action-item.component.tsx +60 -0
  262. package/src/visit/visit-action-items/delete-visit-action-item.test.tsx +48 -0
  263. package/src/visit/visit-action-items/edit-visit-details.component.tsx +79 -0
  264. package/src/visit/visit-form/base-visit-type.component.tsx +121 -0
  265. package/src/visit/visit-form/base-visit-type.scss +75 -0
  266. package/src/visit/visit-form/base-visit-type.test.tsx +153 -0
  267. package/src/visit/visit-form/exported-visit-form.workspace.tsx +755 -0
  268. package/src/visit/visit-form/location-selector.component.tsx +86 -0
  269. package/src/visit/visit-form/location-selector.test.tsx +146 -0
  270. package/src/visit/visit-form/recommended-visit-type.component.tsx +32 -0
  271. package/src/visit/visit-form/visit-attribute-type.component.tsx +258 -0
  272. package/src/visit/visit-form/visit-attribute-type.scss +5 -0
  273. package/src/visit/visit-form/visit-date-time.component.tsx +206 -0
  274. package/src/visit/visit-form/visit-form.resource.ts +401 -0
  275. package/src/visit/visit-form/visit-form.scss +167 -0
  276. package/src/visit/visit-form/visit-form.test.tsx +1233 -0
  277. package/src/visit/visit-form/visit-form.workspace.tsx +61 -0
  278. package/src/visit/visit-form/visit-type.test.tsx +88 -0
  279. package/src/visit/visit-history-table/visit-actions-cell.component.tsx +20 -0
  280. package/src/visit/visit-history-table/visit-actions-cell.scss +4 -0
  281. package/src/visit/visit-history-table/visit-date-cell.component.tsx +19 -0
  282. package/src/visit/visit-history-table/visit-diagnoses-cell.component.tsx +18 -0
  283. package/src/visit/visit-history-table/visit-history-table.component.tsx +145 -0
  284. package/src/visit/visit-history-table/visit-history-table.scss +25 -0
  285. package/src/visit/visit-history-table/visit-type-cell.component.tsx +15 -0
  286. package/src/visit/visit-prompt/delete-visit-dialog.modal.tsx +46 -0
  287. package/src/visit/visit-prompt/delete-visit-dialog.test.tsx +79 -0
  288. package/src/visit/visit-prompt/end-visit-dialog.modal.tsx +82 -0
  289. package/src/visit/visit-prompt/end-visit-dialog.scss +7 -0
  290. package/src/visit/visit-prompt/end-visit-dialog.test.tsx +131 -0
  291. package/src/visit/visit-prompt/modify-visit-date.modal.tsx +40 -0
  292. package/src/visit/visit-prompt/start-visit-dialog.modal.tsx +64 -0
  293. package/src/visit/visit-prompt/start-visit-dialog.scss +10 -0
  294. package/src/visit/visit-prompt/start-visit-dialog.test.tsx +40 -0
  295. package/src/visit/visits-widget/active-visit-buttons/active-visit-buttons.scss +7 -0
  296. package/src/visit/visits-widget/active-visit-buttons/active-visit-buttons.tsx +178 -0
  297. package/src/visit/visits-widget/current-visit-summary.extension.tsx +48 -0
  298. package/src/visit/visits-widget/current-visit-summary.scss +10 -0
  299. package/src/visit/visits-widget/current-visit-summary.test.tsx +85 -0
  300. package/src/visit/visits-widget/encounter-observations/encounter-observations.component.tsx +67 -0
  301. package/src/visit/visits-widget/encounter-observations/index.ts +3 -0
  302. package/src/visit/visits-widget/encounter-observations/styles.scss +22 -0
  303. package/src/visit/visits-widget/past-visits-components/delete-encounter.modal.tsx +47 -0
  304. package/src/visit/visits-widget/past-visits-components/delete-encounter.scss +9 -0
  305. package/src/visit/visits-widget/past-visits-components/encounters-table/all-encounters-table.component.tsx +49 -0
  306. package/src/visit/visits-widget/past-visits-components/encounters-table/completed-forms-table.component.tsx +67 -0
  307. package/src/visit/visits-widget/past-visits-components/encounters-table/completed-forms-table.test.tsx +146 -0
  308. package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.component.tsx +452 -0
  309. package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.resource.test.ts +156 -0
  310. package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.resource.ts +215 -0
  311. package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.scss +113 -0
  312. package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.test.tsx +432 -0
  313. package/src/visit/visits-widget/past-visits-components/encounters-table/visit-completed-forms-table.component.tsx +61 -0
  314. package/src/visit/visits-widget/past-visits-components/encounters-table/visit-completed-forms-table.test.tsx +125 -0
  315. package/src/visit/visits-widget/past-visits-components/encounters-table/visit-encounters-table.component.tsx +47 -0
  316. package/src/visit/visits-widget/past-visits-components/medications-summary.component.tsx +163 -0
  317. package/src/visit/visits-widget/past-visits-components/notes-summary.component.tsx +66 -0
  318. package/src/visit/visits-widget/past-visits-components/patient-notes-summary.component.tsx +318 -0
  319. package/src/visit/visits-widget/past-visits-components/tests-summary.component.tsx +16 -0
  320. package/src/visit/visits-widget/past-visits-components/visit-summary.component.tsx +192 -0
  321. package/src/visit/visits-widget/past-visits-components/visit-summary.scss +72 -0
  322. package/src/visit/visits-widget/past-visits-components/visit-summary.test.tsx +105 -0
  323. package/src/visit/visits-widget/single-visit-details/visit-timeline/visit-timeline.component.tsx +94 -0
  324. package/src/visit/visits-widget/single-visit-details/visit-timeline/visit-timeline.scss +60 -0
  325. package/src/visit/visits-widget/visit-context/retrospective-data-date-time-picker/restrospective-date-time-picker.scss +35 -0
  326. package/src/visit/visits-widget/visit-context/retrospective-data-date-time-picker/retrospective-date-time-picker.component.tsx +140 -0
  327. package/src/visit/visits-widget/visit-context/visit-context-header.extension.tsx +61 -0
  328. package/src/visit/visits-widget/visit-context/visit-context-header.scss +45 -0
  329. package/src/visit/visits-widget/visit-context/visit-context-header.test.tsx +59 -0
  330. package/src/visit/visits-widget/visit-context/visit-context-info.component.tsx +37 -0
  331. package/src/visit/visits-widget/visit-context/visit-context-info.scss +12 -0
  332. package/src/visit/visits-widget/visit-context/visit-context-switcher.modal.tsx +166 -0
  333. package/src/visit/visits-widget/visit-context/visit-context-switcher.scss +83 -0
  334. package/src/visit/visits-widget/visit-context/visit-context-switcher.test.tsx +79 -0
  335. package/src/visit/visits-widget/visit-detail-overview.component.tsx +67 -0
  336. package/src/visit/visits-widget/visit-detail-overview.scss +301 -0
  337. package/src/visit/visits-widget/visit-detail-overview.test.tsx +205 -0
  338. package/src/visit/visits-widget/visit.resource.tsx +146 -0
  339. package/translations/am.json +209 -0
  340. package/translations/ar.json +209 -0
  341. package/translations/ar_SY.json +209 -0
  342. package/translations/bn.json +209 -0
  343. package/translations/cs.json +209 -0
  344. package/translations/de.json +209 -0
  345. package/translations/en.json +209 -0
  346. package/translations/en_US.json +209 -0
  347. package/translations/es.json +209 -0
  348. package/translations/es_MX.json +209 -0
  349. package/translations/fr.json +209 -0
  350. package/translations/he.json +209 -0
  351. package/translations/hi.json +209 -0
  352. package/translations/hi_IN.json +209 -0
  353. package/translations/id.json +209 -0
  354. package/translations/it.json +209 -0
  355. package/translations/ka.json +209 -0
  356. package/translations/km.json +209 -0
  357. package/translations/ku.json +209 -0
  358. package/translations/ky.json +209 -0
  359. package/translations/lg.json +209 -0
  360. package/translations/ne.json +209 -0
  361. package/translations/pl.json +209 -0
  362. package/translations/pt.json +209 -0
  363. package/translations/pt_BR.json +209 -0
  364. package/translations/qu.json +209 -0
  365. package/translations/ro_RO.json +209 -0
  366. package/translations/ru_RU.json +209 -0
  367. package/translations/si.json +209 -0
  368. package/translations/sq.json +209 -0
  369. package/translations/sw.json +209 -0
  370. package/translations/sw_KE.json +209 -0
  371. package/translations/tr.json +209 -0
  372. package/translations/tr_TR.json +209 -0
  373. package/translations/uk.json +209 -0
  374. package/translations/uz.json +209 -0
  375. package/translations/uz@Latn.json +209 -0
  376. package/translations/uz_UZ.json +209 -0
  377. package/translations/vi.json +209 -0
  378. package/translations/zh.json +209 -0
  379. package/translations/zh_CN.json +209 -0
  380. package/translations/zh_TW.json +209 -0
  381. package/tsconfig.json +4 -0
  382. package/vitest.config.ts +4 -0
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { LeftNavMenu, useLayoutType } from '@openmrs/esm-framework';
3
+
4
+ const SideMenuPanel: React.FC = () => {
5
+ const layout = useLayoutType();
6
+
7
+ return layout === 'large-desktop' && <LeftNavMenu />;
8
+ };
9
+
10
+ export default SideMenuPanel;
@@ -0,0 +1,38 @@
1
+ @use '@carbon/layout';
2
+ @use '@carbon/type';
3
+ @use '@openmrs/esm-styleguide/src/vars' as *;
4
+
5
+ .link > div a:nth-child(1) {
6
+ height: layout.$spacing-09;
7
+ padding: layout.$spacing-06 0 layout.$spacing-06 1.25rem;
8
+ color: $ui-04;
9
+ @extend .productiveHeading01;
10
+ border-left: layout.$spacing-02 solid transparent;
11
+ }
12
+
13
+ :global(.omrs-breakpoint-gt-tablet) .link > div {
14
+ padding-top: layout.$spacing-05;
15
+ }
16
+
17
+ :global(.omrs-breakpoint-gt-tablet) .link > div a:nth-child(1) {
18
+ height: layout.$spacing-07;
19
+ color: $ui-04;
20
+ padding-left: layout.$spacing-05;
21
+ }
22
+
23
+ .link > div a:nth-child(1):hover {
24
+ background-color: $ui-03;
25
+ color: $ui-05;
26
+ border-left: var(--brand-01);
27
+ }
28
+
29
+ .link > div a:nth-child(1):focus {
30
+ background-color: $ui-03;
31
+ outline: none;
32
+ color: $ui-05;
33
+ border-left: var(--brand-01);
34
+ }
35
+
36
+ .productiveHeading01 {
37
+ @include type.type-style('heading-compact-01');
38
+ }
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import { vi, describe, it, expect } from 'vitest';
3
+ import { render, screen } from '@testing-library/react';
4
+ import { useLayoutType } from '@openmrs/esm-framework';
5
+ import SideMenu from './side-menu.component';
6
+
7
+ const mockUseLayoutType = vi.mocked(useLayoutType);
8
+
9
+ describe('Side menu', () => {
10
+ it('is rendered when viewport == large-desktop', () => {
11
+ mockUseLayoutType.mockReturnValue('large-desktop');
12
+ renderSideMenu();
13
+
14
+ expect(screen.getByText(/left nav menu/i)).toBeInTheDocument();
15
+ });
16
+
17
+ it('is not rendered when viewport == tablet or viewport == small-desktop', () => {
18
+ mockUseLayoutType.mockReturnValue('tablet');
19
+ renderSideMenu();
20
+
21
+ expect(screen.queryByText(/left nav menu/i)).not.toBeInTheDocument();
22
+ });
23
+ });
24
+
25
+ function renderSideMenu() {
26
+ render(<SideMenu />);
27
+ }
@@ -0,0 +1,17 @@
1
+ import { isDesktop } from './utils';
2
+ import { vi, describe, it, expect } from 'vitest';
3
+
4
+ describe('isDesktop', () => {
5
+ it('is true when layout = tablet', () => {
6
+ expect(isDesktop('tablet')).toBeFalsy();
7
+ });
8
+
9
+ it('is true when layout = phone', () => {
10
+ expect(isDesktop('phone')).toBeFalsy();
11
+ });
12
+
13
+ it('is false is desktop', () => {
14
+ expect(isDesktop('small-desktop')).toBeTruthy();
15
+ expect(isDesktop('large-desktop')).toBeTruthy();
16
+ });
17
+ });
package/src/utils.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { isDesktop as checkIfIsDesktop, type LayoutType } from '@openmrs/esm-framework';
2
+
3
+ export function isDesktop(layout: LayoutType) {
4
+ return checkIfIsDesktop(layout);
5
+ }
@@ -0,0 +1,15 @@
1
+ import { type FetchResponse, openmrsFetch, useConfig } from '@openmrs/esm-framework';
2
+ import useSWRImmutable from 'swr/immutable';
3
+ import { type ChartConfig } from '../../config-schema';
4
+
5
+ export const useDefaultFacilityLocation = () => {
6
+ const config = useConfig() as ChartConfig;
7
+ const apiUrl = config.defaultFacilityUrl;
8
+ const { data, error, isLoading } = useSWRImmutable<FetchResponse>(apiUrl, openmrsFetch);
9
+
10
+ return {
11
+ defaultFacility: data ? data?.data : null,
12
+ isLoading: isLoading,
13
+ error: error,
14
+ };
15
+ };
@@ -0,0 +1,24 @@
1
+ import { type FetchResponse, type Location, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { useEffect } from 'react';
3
+ import useSWR from 'swr';
4
+
5
+ /**
6
+ * Fetches the default visit location based on the location and the restrictByVisitLocationTag
7
+ * If restrictByVisitLocationTag is true, it fetches the nearest ancestor location that supports visits, otherwise it returns the passed-in location
8
+ *
9
+ * @param location
10
+ * @param restrictByVisitLocationTag
11
+ */
12
+ export function useDefaultVisitLocation(location: Location, restrictByVisitLocationTag: boolean) {
13
+ let url = `${restBaseUrl}/emrapi/locationThatSupportsVisits?location=${location?.uuid}`;
14
+
15
+ const { data, error } = useSWR<FetchResponse>(restrictByVisitLocationTag ? url : null, openmrsFetch);
16
+
17
+ useEffect(() => {
18
+ if (error) {
19
+ console.error(error);
20
+ }
21
+ }, [error]);
22
+
23
+ return !restrictByVisitLocationTag ? location : data?.data;
24
+ }
@@ -0,0 +1,267 @@
1
+ import { useSWRConfig } from 'swr';
2
+ import { vi, describe, it, expect, test, beforeEach } from 'vitest';
3
+ import { renderHook, act } from '@testing-library/react';
4
+ import { showSnackbar, type Visit } from '@openmrs/esm-framework';
5
+ import {
6
+ invalidateCurrentVisit,
7
+ invalidateVisitAndEncounterData,
8
+ usePatientChartStore,
9
+ } from '@openmrs/esm-patient-common-lib';
10
+ import { useDeleteVisit } from './useDeleteVisit';
11
+ import { deleteVisit, restoreVisit } from '../visits-widget/visit.resource';
12
+
13
+ vi.mock('swr', () => ({
14
+ useSWRConfig: vi.fn(),
15
+ }));
16
+
17
+ vi.mock('../visits-widget/visit.resource', async () => {
18
+ const original = (await vi.importActual('../visits-widget/visit.resource')) as object;
19
+ return {
20
+ ...original,
21
+ deleteVisit: vi.fn(),
22
+ restoreVisit: vi.fn(),
23
+ };
24
+ });
25
+
26
+ vi.mock('@openmrs/esm-patient-common-lib', () => ({
27
+ invalidateCurrentVisit: vi.fn(),
28
+ invalidateVisitAndEncounterData: vi.fn(),
29
+ usePatientChartStore: vi.fn(),
30
+ }));
31
+
32
+ const mockDeleteVisit = vi.mocked(deleteVisit);
33
+ const mockRestoreVisit = vi.mocked(restoreVisit);
34
+ const mockShowSnackbar = vi.mocked(showSnackbar);
35
+ const mockUseSWRConfig = vi.mocked(useSWRConfig);
36
+ const mockUsePatientChartStore = vi.mocked(usePatientChartStore);
37
+ const mockInvalidateVisitAndEncounterData = vi.mocked(invalidateVisitAndEncounterData);
38
+
39
+ const mockGlobalMutate = vi.fn();
40
+ const mockSetVisitContext = vi.fn();
41
+
42
+ const mockVisitType = {
43
+ uuid: 'visit-type-123',
44
+ display: 'Outpatient Visit',
45
+ name: 'Outpatient Visit',
46
+ };
47
+
48
+ const mockVisit = {
49
+ uuid: 'visit-123',
50
+ patient: { uuid: 'patient-123' },
51
+ visitType: mockVisitType,
52
+ startDatetime: '2023-01-01T10:00:00Z',
53
+ stopDatetime: null,
54
+ location: { uuid: 'location-123', display: 'Test Location' },
55
+ encounters: [],
56
+ attributes: [],
57
+ voided: false,
58
+ links: [],
59
+ resourceVersion: '1.8',
60
+ } as Visit;
61
+
62
+ describe('useDeleteVisit', () => {
63
+ beforeEach(() => {
64
+ mockUsePatientChartStore.mockReturnValue({
65
+ patientUuid: 'patient-123',
66
+ patient: null,
67
+ visitContext: null,
68
+ mutateVisitContext: vi.fn(),
69
+ setPatient: vi.fn(),
70
+ setVisitContext: mockSetVisitContext,
71
+ });
72
+
73
+ mockUseSWRConfig.mockReturnValue({
74
+ mutate: mockGlobalMutate,
75
+ cache: new Map(),
76
+ } as any);
77
+ });
78
+
79
+ it('should delete visit successfully and trigger revalidation', async () => {
80
+ mockDeleteVisit.mockResolvedValue({ data: {} } as any);
81
+ const onVisitDelete = vi.fn();
82
+
83
+ const { result } = renderHook(() => useDeleteVisit(mockVisit, onVisitDelete));
84
+
85
+ await act(async () => {
86
+ result.current.initiateDeletingVisit();
87
+ });
88
+
89
+ expect(mockDeleteVisit).toHaveBeenCalledWith('visit-123');
90
+ expect(mockInvalidateVisitAndEncounterData).toHaveBeenCalledWith(mockGlobalMutate, 'patient-123');
91
+
92
+ expect(mockShowSnackbar).toHaveBeenCalledWith(
93
+ expect.objectContaining({
94
+ title: 'Outpatient Visit deleted',
95
+ subtitle: 'Outpatient Visit deleted successfully',
96
+ kind: 'success',
97
+ actionButtonLabel: 'Undo',
98
+ onActionButtonClick: expect.any(Function),
99
+ }),
100
+ );
101
+
102
+ expect(onVisitDelete).toHaveBeenCalled();
103
+ });
104
+
105
+ it('should handle delete error and trigger revalidation', async () => {
106
+ mockDeleteVisit.mockRejectedValue(new Error('Delete failed'));
107
+ const onVisitDelete = vi.fn();
108
+
109
+ const { result } = renderHook(() => useDeleteVisit(mockVisit, onVisitDelete));
110
+
111
+ await act(async () => {
112
+ result.current.initiateDeletingVisit();
113
+ });
114
+
115
+ expect(mockInvalidateVisitAndEncounterData).toHaveBeenCalledWith(mockGlobalMutate, 'patient-123');
116
+
117
+ expect(mockShowSnackbar).toHaveBeenCalledWith({
118
+ title: 'Error deleting visit',
119
+ kind: 'error',
120
+ subtitle: 'An error occurred when deleting visit',
121
+ });
122
+
123
+ expect(onVisitDelete).not.toHaveBeenCalled();
124
+ });
125
+
126
+ it('should restore visit successfully when undo is clicked', async () => {
127
+ mockRestoreVisit.mockResolvedValue({ data: {} } as any);
128
+ const onVisitRestore = vi.fn();
129
+
130
+ const { result } = renderHook(() => useDeleteVisit(mockVisit, undefined, onVisitRestore));
131
+
132
+ // First delete to get the restore function
133
+ mockDeleteVisit.mockResolvedValue({ data: {} } as any);
134
+ await act(async () => {
135
+ result.current.initiateDeletingVisit();
136
+ });
137
+
138
+ // Get the restore function from the snackbar
139
+ const restoreFunction = mockShowSnackbar.mock.calls[0][0].onActionButtonClick;
140
+
141
+ // Clear mocks to test restore independently
142
+ vi.clearAllMocks();
143
+ mockUsePatientChartStore.mockReturnValue({
144
+ patientUuid: 'patient-123',
145
+ patient: null,
146
+ visitContext: null,
147
+ mutateVisitContext: vi.fn(),
148
+ setPatient: vi.fn(),
149
+ setVisitContext: mockSetVisitContext,
150
+ });
151
+ mockUseSWRConfig.mockReturnValue({
152
+ mutate: mockGlobalMutate,
153
+ cache: new Map(),
154
+ } as any);
155
+
156
+ // Test restore functionality
157
+ await act(async () => {
158
+ restoreFunction();
159
+ });
160
+
161
+ expect(mockRestoreVisit).toHaveBeenCalledWith('visit-123');
162
+ expect(mockInvalidateVisitAndEncounterData).toHaveBeenCalledWith(mockGlobalMutate, 'patient-123');
163
+
164
+ expect(mockShowSnackbar).toHaveBeenCalledWith({
165
+ title: 'Visit restored',
166
+ subtitle: 'Outpatient Visit restored successfully',
167
+ kind: 'success',
168
+ });
169
+
170
+ expect(onVisitRestore).toHaveBeenCalled();
171
+ });
172
+
173
+ it('should handle restore error and trigger revalidation', async () => {
174
+ mockRestoreVisit.mockRejectedValue(new Error('Restore failed'));
175
+ const onVisitRestore = vi.fn();
176
+
177
+ const { result } = renderHook(() => useDeleteVisit(mockVisit, undefined, onVisitRestore));
178
+
179
+ // First delete to get the restore function
180
+ mockDeleteVisit.mockResolvedValue({ data: {} } as any);
181
+ await act(async () => {
182
+ result.current.initiateDeletingVisit();
183
+ });
184
+
185
+ const restoreFunction = mockShowSnackbar.mock.calls[0][0].onActionButtonClick;
186
+
187
+ // Clear mocks to test restore independently
188
+ vi.clearAllMocks();
189
+ mockUsePatientChartStore.mockReturnValue({
190
+ patientUuid: 'patient-123',
191
+ patient: null,
192
+ visitContext: null,
193
+ mutateVisitContext: vi.fn(),
194
+ setPatient: vi.fn(),
195
+ setVisitContext: mockSetVisitContext,
196
+ });
197
+ mockUseSWRConfig.mockReturnValue({
198
+ mutate: mockGlobalMutate,
199
+ cache: new Map(),
200
+ } as any);
201
+
202
+ // Test restore error
203
+ await act(async () => {
204
+ restoreFunction();
205
+ });
206
+
207
+ expect(mockInvalidateVisitAndEncounterData).toHaveBeenCalledWith(mockGlobalMutate, 'patient-123');
208
+
209
+ expect(mockShowSnackbar).toHaveBeenCalledWith({
210
+ title: "Visit couldn't be restored",
211
+ subtitle: 'Error occurred when restoring Outpatient Visit',
212
+ kind: 'error',
213
+ });
214
+
215
+ expect(onVisitRestore).not.toHaveBeenCalled();
216
+ });
217
+
218
+ it('should manage loading state correctly', async () => {
219
+ mockDeleteVisit.mockResolvedValue({ data: {} } as any);
220
+
221
+ const { result } = renderHook(() => useDeleteVisit(mockVisit, () => {}));
222
+
223
+ // Initially not deleting
224
+ expect(result.current.isDeletingVisit).toBe(false);
225
+
226
+ // Start deletion and wait for completion
227
+ await act(async () => {
228
+ result.current.initiateDeletingVisit();
229
+ });
230
+
231
+ // Should no longer be loading after completion
232
+ expect(result.current.isDeletingVisit).toBe(false);
233
+ });
234
+
235
+ it('should handle visit with missing patient UUID', () => {
236
+ const visitWithoutPatient = { ...mockVisit, patient: null };
237
+
238
+ expect(() => {
239
+ renderHook(() => useDeleteVisit(visitWithoutPatient, () => {}));
240
+ }).not.toThrow();
241
+ });
242
+
243
+ it('should handle visit with empty patient UUID', () => {
244
+ const visitWithEmptyPatient = { ...mockVisit, patient: { uuid: '' } };
245
+
246
+ expect(() => {
247
+ renderHook(() => useDeleteVisit(visitWithEmptyPatient, () => {}));
248
+ }).not.toThrow();
249
+ });
250
+
251
+ it('should handle visit with missing visit type display', async () => {
252
+ const visitWithoutDisplay = {
253
+ ...mockVisit,
254
+ visitType: { ...mockVisitType, display: undefined },
255
+ };
256
+
257
+ mockDeleteVisit.mockResolvedValue({ data: {} } as any);
258
+ const { result } = renderHook(() => useDeleteVisit(visitWithoutDisplay, () => {}));
259
+
260
+ await act(async () => {
261
+ result.current.initiateDeletingVisit();
262
+ });
263
+
264
+ // Should complete without throwing
265
+ expect(mockDeleteVisit).toHaveBeenCalled();
266
+ });
267
+ });
@@ -0,0 +1,103 @@
1
+ import { useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { useSWRConfig } from 'swr';
4
+ import { type Visit, showSnackbar } from '@openmrs/esm-framework';
5
+ import {
6
+ invalidateCurrentVisit,
7
+ invalidateVisitAndEncounterData,
8
+ invalidateVisitByUuid,
9
+ usePatientChartStore,
10
+ } from '@openmrs/esm-patient-common-lib';
11
+ import { deleteVisit, restoreVisit } from '../visits-widget/visit.resource';
12
+
13
+ export function useDeleteVisit(activeVisit: Visit, onVisitDelete = () => {}, onVisitRestore = () => {}) {
14
+ const { t } = useTranslation();
15
+ const { mutate: globalMutate } = useSWRConfig();
16
+ const [isDeletingVisit, setIsDeletingVisit] = useState(false);
17
+ const patientUuid = activeVisit?.patient?.uuid || '';
18
+ const { visitContext, setVisitContext } = usePatientChartStore(patientUuid);
19
+
20
+ const restoreDeletedVisit = () => {
21
+ restoreVisit(activeVisit?.uuid)
22
+ .then(({ data: updatedVisit }) => {
23
+ if (!updatedVisit.stopDatetime) {
24
+ const mutateSavedOrUpdatedVisit = () => invalidateVisitByUuid(globalMutate, updatedVisit.uuid);
25
+ setVisitContext(updatedVisit, mutateSavedOrUpdatedVisit);
26
+ }
27
+
28
+ // Use targeted SWR invalidation instead of global mutateVisit
29
+ invalidateCurrentVisit(globalMutate, patientUuid);
30
+ invalidateVisitAndEncounterData(globalMutate, patientUuid);
31
+ window.dispatchEvent(new CustomEvent('queue-entry-updated'));
32
+
33
+ showSnackbar({
34
+ title: t('visitRestored', 'Visit restored'),
35
+ subtitle: t('visitRestoredSuccessfully', '{{visit}} restored successfully', {
36
+ visit: activeVisit?.visitType?.display ?? t('visit', 'Visit'),
37
+ }),
38
+ kind: 'success',
39
+ });
40
+ onVisitRestore?.();
41
+ })
42
+ .catch(() => {
43
+ // On error, revalidate to get correct state
44
+ invalidateCurrentVisit(globalMutate, patientUuid);
45
+ invalidateVisitAndEncounterData(globalMutate, patientUuid);
46
+ showSnackbar({
47
+ title: t('visitNotRestored', "Visit couldn't be restored"),
48
+ subtitle: t('errorWhenRestoringVisit', 'Error occurred when restoring {{visit}}', {
49
+ visit: activeVisit?.visitType?.display ?? t('visit', 'Visit'),
50
+ }),
51
+ kind: 'error',
52
+ });
53
+ });
54
+ };
55
+
56
+ const initiateDeletingVisit = () => {
57
+ setIsDeletingVisit(true);
58
+
59
+ deleteVisit(activeVisit?.uuid)
60
+ .then(() => {
61
+ if (activeVisit.uuid == visitContext?.uuid) {
62
+ setVisitContext(null, null);
63
+ }
64
+
65
+ // Use targeted SWR invalidation instead of global mutateVisit
66
+ invalidateCurrentVisit(globalMutate, patientUuid);
67
+ invalidateVisitAndEncounterData(globalMutate, patientUuid);
68
+ window.dispatchEvent(new CustomEvent('queue-entry-updated'));
69
+
70
+ showSnackbar({
71
+ title: t('visitDeleted', '{{visit}} deleted', {
72
+ visit: activeVisit?.visitType?.display ?? t('visit', 'Visit'),
73
+ }),
74
+ subtitle: t('visitDeletedSuccessfully', '{{visit}} deleted successfully', {
75
+ visit: activeVisit?.visitType?.display ?? t('visit', 'Visit'),
76
+ }),
77
+ kind: 'success',
78
+ actionButtonLabel: t('undo', 'Undo'),
79
+ onActionButtonClick: restoreDeletedVisit,
80
+ });
81
+ onVisitDelete?.();
82
+ })
83
+ .catch(() => {
84
+ // On error, revalidate to get correct state
85
+ invalidateCurrentVisit(globalMutate, patientUuid);
86
+ invalidateVisitAndEncounterData(globalMutate, patientUuid);
87
+
88
+ showSnackbar({
89
+ title: t('errorDeletingVisit', 'Error deleting visit'),
90
+ kind: 'error',
91
+ subtitle: t('errorOccurredDeletingVisit', 'An error occurred when deleting visit'),
92
+ });
93
+ })
94
+ .finally(() => {
95
+ setIsDeletingVisit(false);
96
+ });
97
+ };
98
+
99
+ return {
100
+ initiateDeletingVisit,
101
+ isDeletingVisit,
102
+ };
103
+ }
@@ -0,0 +1,18 @@
1
+ import { type VisitType, useConfig } from '@openmrs/esm-framework';
2
+ import { type ChartConfig } from '../../config-schema';
3
+ import { useEffect, useState } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ export const useOfflineVisitType = () => {
7
+ const config = useConfig() as ChartConfig;
8
+ const { t } = useTranslation();
9
+ const [visitTypes, setVisitTypes] = useState<Array<VisitType>>([]);
10
+
11
+ useEffect(() => {
12
+ setVisitTypes([
13
+ { uuid: config.offlineVisitTypeUuid, name: 'Offline Visit', display: t('offlineVisit', 'Offline Visit') },
14
+ ]);
15
+ }, [t, config.offlineVisitTypeUuid]);
16
+
17
+ return visitTypes;
18
+ };
@@ -0,0 +1,34 @@
1
+ import { useMemo } from 'react';
2
+ import useSWR from 'swr';
3
+ import { openmrsFetch, useConfig } from '@openmrs/esm-framework';
4
+ import { type ChartConfig } from '../../config-schema';
5
+
6
+ interface EnrollmentVisitType {
7
+ dataDependencies: Array<string>;
8
+ enrollmentOptions: object;
9
+ incompatibleWith: Array<string>;
10
+ name: string;
11
+ visitTypes: { allowed: Array<EnrollmentVisitType>; disallowed: Array<EnrollmentVisitType> };
12
+ }
13
+
14
+ export const useRecommendedVisitTypes = (
15
+ patientUuid: string,
16
+ enrollmentUuid: string,
17
+ programUuid: string,
18
+ locationUuid: string,
19
+ ) => {
20
+ const { visitTypeResourceUrl, showRecommendedVisitTypeTab } = useConfig() as ChartConfig;
21
+ const url = `${visitTypeResourceUrl}${patientUuid}/program/${programUuid}/enrollment/${enrollmentUuid}?intendedLocationUuid=${locationUuid}`;
22
+
23
+ const { data, error, isLoading } = useSWR<{ data: EnrollmentVisitType }>(
24
+ showRecommendedVisitTypeTab && patientUuid && enrollmentUuid && programUuid ? url : null,
25
+ openmrsFetch,
26
+ );
27
+
28
+ const recommendedVisitTypes = useMemo(() => data?.data?.visitTypes?.allowed.map(mapToVisitType) ?? [], [data]);
29
+ return { recommendedVisitTypes, error, isLoading };
30
+ };
31
+
32
+ const mapToVisitType = (visitType) => {
33
+ return { ...visitType, display: visitType.name };
34
+ };
@@ -0,0 +1,102 @@
1
+ import { useMemo } from 'react';
2
+ import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
3
+ import useSWRImmutable from 'swr/immutable';
4
+
5
+ interface VisitAttributeType {
6
+ uuid: string;
7
+ display: string;
8
+ name: string;
9
+ description: string | null;
10
+ datatypeClassname:
11
+ | 'org.openmrs.customdatatype.datatype.ConceptDatatype'
12
+ | 'org.openmrs.customdatatype.datatype.FloatDatatype'
13
+ | 'org.openmrs.customdatatype.datatype.BooleanDatatype'
14
+ | 'org.openmrs.customdatatype.datatype.LongFreeTextDatatype'
15
+ | 'org.openmrs.customdatatype.datatype.FreeTextDatatype'
16
+ | 'org.openmrs.customdatatype.datatype.DateDatatype';
17
+ datatypeConfig: string;
18
+ preferredHandlerClassname: any;
19
+ retired: boolean;
20
+ }
21
+
22
+ interface Concept {
23
+ uuid: string;
24
+ name: {
25
+ display: string;
26
+ };
27
+ display: string;
28
+ answers: Array<{
29
+ display: string;
30
+ uuid: string;
31
+ }>;
32
+ }
33
+
34
+ const visitAttributeTypeCustomRepresentation =
35
+ 'custom:(uuid,display,name,description,datatypeClassname,datatypeConfig)';
36
+
37
+ export function useVisitAttributeTypes() {
38
+ const { data, error, isLoading } = useSWRImmutable<FetchResponse<{ results: VisitAttributeType[] }>, Error>(
39
+ `${restBaseUrl}/visitattributetype?v=${visitAttributeTypeCustomRepresentation}`,
40
+ openmrsFetch,
41
+ );
42
+
43
+ if (error) {
44
+ console.error('Failed to fetch visit attribute types: ', error);
45
+ }
46
+
47
+ const results = useMemo(
48
+ () => ({
49
+ isLoading,
50
+ error,
51
+ visitAttributeTypes: data?.data?.results ?? [],
52
+ }),
53
+ [data, error, isLoading],
54
+ );
55
+
56
+ return results;
57
+ }
58
+
59
+ export function useVisitAttributeType(uuid) {
60
+ const { data, error, isLoading } = useSWRImmutable<FetchResponse<VisitAttributeType>, Error>(
61
+ `${restBaseUrl}/visitattributetype/${uuid}?v=${visitAttributeTypeCustomRepresentation}`,
62
+ openmrsFetch,
63
+ );
64
+
65
+ if (error) {
66
+ console.error(`Failed to fetch visit attribute type ${uuid}: `, error);
67
+ }
68
+
69
+ const results = useMemo(
70
+ () => ({
71
+ isLoading,
72
+ error: error,
73
+ data: data?.data,
74
+ }),
75
+ [data, error, isLoading],
76
+ );
77
+
78
+ return results;
79
+ }
80
+
81
+ export function useConceptAnswersForVisitAttributeType(conceptUuid) {
82
+ const { data, error, isLoading } = useSWRImmutable<FetchResponse<Concept>, Error>(
83
+ conceptUuid ? `${restBaseUrl}/concept/${conceptUuid}` : null,
84
+ openmrsFetch,
85
+ );
86
+
87
+ if (error) {
88
+ console.error(`Failed to fetch concept answers for visit attribute type ${conceptUuid}: `, error);
89
+ }
90
+
91
+ const results = useMemo(
92
+ () => ({
93
+ isLoading,
94
+ error: error,
95
+ data: data?.data,
96
+ answers: data?.data?.answers,
97
+ }),
98
+ [data, error, isLoading],
99
+ );
100
+
101
+ return results;
102
+ }