@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,307 @@
1
+ import React from 'react';
2
+ import { vi, describe, it, expect, test } from 'vitest';
3
+ import { render, screen } from '@testing-library/react';
4
+ import { renderTag } from './tag.component';
5
+ import { type ConfigConcepts, type Encounter, type Observation } from '../types';
6
+
7
+ describe('Tag component', () => {
8
+ const mockConfig: ConfigConcepts = {
9
+ trueConceptUuid: 'true-uuid',
10
+ falseConceptUuid: 'false-uuid',
11
+ otherConceptUuid: 'other-uuid',
12
+ };
13
+
14
+ const mockStatusColorMappings = {
15
+ 'status-uuid-1': 'green',
16
+ 'status-uuid-2': 'red',
17
+ };
18
+
19
+ const createMockEncounter = (obsValue: Observation['value']): Encounter => ({
20
+ uuid: 'encounter-uuid',
21
+ encounterDatetime: '2024-01-01',
22
+ encounterType: {
23
+ uuid: 'encounter-type-uuid',
24
+ name: 'Test Encounter',
25
+ },
26
+ obs: [
27
+ {
28
+ uuid: 'obs-uuid',
29
+ concept: {
30
+ uuid: 'test-concept-uuid',
31
+ name: 'Test Concept',
32
+ },
33
+ value: obsValue,
34
+ obsDatetime: '2024-01-01',
35
+ },
36
+ ],
37
+ encounterProviders: [],
38
+ form: undefined,
39
+ patient: {
40
+ uuid: 'patient-uuid',
41
+ display: 'Test Patient',
42
+ age: 30,
43
+ birthDate: '1994-01-01',
44
+ },
45
+ location: {
46
+ uuid: 'location-uuid',
47
+ display: 'Test Location',
48
+ name: 'Test Location',
49
+ },
50
+ });
51
+
52
+ it('should render "--" when columnStatus is "--"', () => {
53
+ const mockEncounter = createMockEncounter('--');
54
+ const view = renderTag(mockEncounter, 'non-existent-concept', mockStatusColorMappings, mockConfig);
55
+ expect(view).toBe('--');
56
+ });
57
+
58
+ it('should render a Tag component with the correct text content', () => {
59
+ const mockEncounter = createMockEncounter({
60
+ uuid: 'status-uuid-1',
61
+ name: {
62
+ name: 'Active',
63
+ display: 'Active',
64
+ },
65
+ });
66
+
67
+ render(
68
+ <div data-testid="tag-wrapper">
69
+ {renderTag(mockEncounter, 'test-concept-uuid', mockStatusColorMappings, mockConfig)}
70
+ </div>,
71
+ );
72
+
73
+ expect(screen.getByText('Active')).toBeInTheDocument();
74
+ });
75
+
76
+ it('should not have a title attribute when rendering a Tag', () => {
77
+ const mockEncounter = createMockEncounter({
78
+ uuid: 'status-uuid-1',
79
+ name: {
80
+ name: 'Active',
81
+ display: 'Active',
82
+ },
83
+ });
84
+
85
+ const { container } = render(
86
+ <div data-testid="tag-wrapper">
87
+ {renderTag(mockEncounter, 'test-concept-uuid', mockStatusColorMappings, mockConfig)}
88
+ </div>,
89
+ );
90
+
91
+ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
92
+ const tag = container.querySelector('.cds--tag');
93
+ expect(tag).not.toHaveAttribute('title');
94
+ expect(screen.getByText('Active')).toBeInTheDocument();
95
+ });
96
+
97
+ it('should apply the correct color type based on status color mappings', () => {
98
+ const mockEncounter = createMockEncounter({
99
+ uuid: 'status-uuid-2',
100
+ name: {
101
+ name: 'Inactive',
102
+ display: 'Inactive',
103
+ },
104
+ });
105
+
106
+ const { container } = render(
107
+ <div data-testid="tag-wrapper">
108
+ {renderTag(mockEncounter, 'test-concept-uuid', mockStatusColorMappings, mockConfig)}
109
+ </div>,
110
+ );
111
+
112
+ expect(screen.getByText('Inactive')).toBeInTheDocument();
113
+ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
114
+ const tag = container.querySelector('.cds--tag');
115
+ expect(tag).toHaveClass('cds--tag--red');
116
+ });
117
+
118
+ it('should render with minimum width style', () => {
119
+ const mockEncounter = createMockEncounter({
120
+ uuid: 'status-uuid-1',
121
+ name: {
122
+ name: 'Active',
123
+ display: 'Active',
124
+ },
125
+ });
126
+
127
+ const { container } = render(
128
+ <div data-testid="tag-wrapper">
129
+ {renderTag(mockEncounter, 'test-concept-uuid', mockStatusColorMappings, mockConfig)}
130
+ </div>,
131
+ );
132
+
133
+ expect(screen.getByText('Active')).toBeInTheDocument();
134
+ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
135
+ const tag = container.querySelector('.cds--tag');
136
+ expect(tag).toHaveStyle({ minWidth: '80px' });
137
+ });
138
+
139
+ it('should handle string values correctly', () => {
140
+ const mockEncounter = createMockEncounter('Completed');
141
+
142
+ render(
143
+ <div data-testid="tag-wrapper">
144
+ {renderTag(mockEncounter, 'test-concept-uuid', mockStatusColorMappings, mockConfig)}
145
+ </div>,
146
+ );
147
+
148
+ expect(screen.getByText('Completed')).toBeInTheDocument();
149
+ });
150
+
151
+ it('should render Tag without color type when uuid is not in statusColorMappings', () => {
152
+ const mockEncounter = createMockEncounter({
153
+ uuid: 'unmapped-uuid',
154
+ name: {
155
+ name: 'Unmapped Status',
156
+ display: 'Unmapped Status',
157
+ },
158
+ });
159
+
160
+ const { container } = render(
161
+ <div data-testid="tag-wrapper">
162
+ {renderTag(mockEncounter, 'test-concept-uuid', mockStatusColorMappings, mockConfig)}
163
+ </div>,
164
+ );
165
+
166
+ expect(screen.getByText('Unmapped Status')).toBeInTheDocument();
167
+
168
+ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
169
+ const tag = container.querySelector('.cds--tag');
170
+ expect(tag).toBeInTheDocument();
171
+ const allColorClasses = Object.values(mockStatusColorMappings).map((color) => `cds--tag--${color}`);
172
+ allColorClasses.forEach((colorClass) => {
173
+ expect(tag).not.toHaveClass(colorClass);
174
+ });
175
+ });
176
+
177
+ it('should render Tag without color type when value is a string', () => {
178
+ const mockEncounter = createMockEncounter('String Value');
179
+
180
+ const { container } = render(
181
+ <div data-testid="tag-wrapper">
182
+ {renderTag(mockEncounter, 'test-concept-uuid', mockStatusColorMappings, mockConfig)}
183
+ </div>,
184
+ );
185
+
186
+ expect(screen.getByText('String Value')).toBeInTheDocument();
187
+
188
+ // String values don't have uuid, so no color type should be applied
189
+ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
190
+ const tag = container.querySelector('.cds--tag');
191
+ expect(tag).toBeInTheDocument();
192
+ const allColorClasses = Object.values(mockStatusColorMappings).map((color) => `cds--tag--${color}`);
193
+ allColorClasses.forEach((colorClass) => {
194
+ expect(tag).not.toHaveClass(colorClass);
195
+ });
196
+ });
197
+
198
+ it('should render Tag without color type when observation value object lacks uuid property', () => {
199
+ // Create an observation value without uuid property (edge case)
200
+ const mockEncounter: Encounter = {
201
+ uuid: 'encounter-uuid',
202
+ encounterDatetime: '2024-01-01',
203
+ encounterType: {
204
+ uuid: 'encounter-type-uuid',
205
+ name: 'Test Encounter',
206
+ },
207
+ obs: [
208
+ {
209
+ uuid: 'obs-uuid',
210
+ concept: {
211
+ uuid: 'test-concept-uuid',
212
+ name: 'Test Concept',
213
+ },
214
+ value: {
215
+ name: {
216
+ name: 'Status Without UUID',
217
+ display: 'Status Without UUID',
218
+ },
219
+ // Missing uuid property - using type assertion for test case
220
+ } as Observation['value'],
221
+ obsDatetime: '2024-01-01',
222
+ },
223
+ ],
224
+ encounterProviders: [],
225
+ form: undefined,
226
+ patient: {
227
+ uuid: 'patient-uuid',
228
+ display: 'Test Patient',
229
+ age: 30,
230
+ birthDate: '1994-01-01',
231
+ },
232
+ location: {
233
+ uuid: 'location-uuid',
234
+ display: 'Test Location',
235
+ name: 'Test Location',
236
+ },
237
+ };
238
+
239
+ const { container } = render(
240
+ <div data-testid="tag-wrapper">
241
+ {renderTag(mockEncounter, 'test-concept-uuid', mockStatusColorMappings, mockConfig)}
242
+ </div>,
243
+ );
244
+
245
+ expect(screen.getByText('Status Without UUID')).toBeInTheDocument();
246
+ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
247
+ const tag = container.querySelector('.cds--tag');
248
+ const allColorClasses = Object.values(mockStatusColorMappings).map((color) => `cds--tag--${color}`);
249
+ allColorClasses.forEach((colorClass) => {
250
+ expect(tag).not.toHaveClass(colorClass);
251
+ });
252
+ });
253
+
254
+ it('should handle empty statusColorMappings', () => {
255
+ const emptyMappings = {};
256
+ const mockEncounter = createMockEncounter({
257
+ uuid: 'status-uuid-1',
258
+ name: {
259
+ name: 'Active',
260
+ display: 'Active',
261
+ },
262
+ });
263
+
264
+ const { container } = render(
265
+ <div data-testid="tag-wrapper">{renderTag(mockEncounter, 'test-concept-uuid', emptyMappings, mockConfig)}</div>,
266
+ );
267
+
268
+ expect(screen.getByText('Active')).toBeInTheDocument();
269
+ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
270
+ const tag = container.querySelector('.cds--tag');
271
+ expect(tag).toBeInTheDocument();
272
+ // With empty mappings, verify no color classes from mockStatusColorMappings are applied
273
+ const allColorClasses = Object.values(mockStatusColorMappings).map((color) => `cds--tag--${color}`);
274
+ allColorClasses.forEach((colorClass) => {
275
+ expect(tag).not.toHaveClass(colorClass);
276
+ });
277
+ });
278
+
279
+ it('should handle when findObs returns undefined (no observation found)', () => {
280
+ const mockEncounter: Encounter = {
281
+ uuid: 'encounter-uuid',
282
+ encounterDatetime: '2024-01-01',
283
+ encounterType: {
284
+ uuid: 'encounter-type-uuid',
285
+ name: 'Test Encounter',
286
+ },
287
+ obs: [], // No observations
288
+ encounterProviders: [],
289
+ form: undefined,
290
+ patient: {
291
+ uuid: 'patient-uuid',
292
+ display: 'Test Patient',
293
+ age: 30,
294
+ birthDate: '1994-01-01',
295
+ },
296
+ location: {
297
+ uuid: 'location-uuid',
298
+ display: 'Test Location',
299
+ name: 'Test Location',
300
+ },
301
+ };
302
+
303
+ const view = renderTag(mockEncounter, 'non-existent-concept', mockStatusColorMappings, mockConfig);
304
+ // When no observation is found, getObsFromEncounter returns '--'
305
+ expect(view).toBe('--');
306
+ });
307
+ });
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { Tag } from '@carbon/react';
3
+ import { getObsFromEncounter, findObs } from '../utils/helpers';
4
+ import { type ConfigConcepts, type Encounter } from '../types';
5
+
6
+ export const renderTag = (
7
+ encounter: Encounter,
8
+ concept: string,
9
+ statusColorMappings: Record<string, string>,
10
+ config: ConfigConcepts,
11
+ ) => {
12
+ const columnStatus = getObsFromEncounter({ encounter, obsConcept: concept, config });
13
+ const columnStatusObs = findObs(encounter, concept);
14
+
15
+ if (columnStatus === '--') {
16
+ return '--';
17
+ }
18
+
19
+ return (
20
+ <Tag
21
+ type={
22
+ typeof columnStatusObs?.value === 'object' && 'uuid' in columnStatusObs.value
23
+ ? (statusColorMappings[columnStatusObs.value.uuid] as
24
+ | 'red'
25
+ | 'magenta'
26
+ | 'purple'
27
+ | 'blue'
28
+ | 'cyan'
29
+ | 'teal'
30
+ | 'green'
31
+ | 'gray'
32
+ | 'cool-gray'
33
+ | 'warm-gray'
34
+ | 'high-contrast'
35
+ | 'outline')
36
+ : undefined
37
+ }
38
+ style={{ minWidth: '80px' }}
39
+ >
40
+ {typeof columnStatus === 'string' ? columnStatus : ''}
41
+ </Tag>
42
+ );
43
+ };
@@ -0,0 +1,40 @@
1
+ import React, { memo, useMemo } from 'react';
2
+
3
+ import { useTranslation } from 'react-i18next';
4
+ import { useConfig } from '@openmrs/esm-framework';
5
+ import { getEncounterTileColumns } from '../utils';
6
+ import { EncounterTile } from './encounter-tile.component';
7
+ import { type MenuCardProps } from '../types';
8
+
9
+ interface OverviewListProps {
10
+ patientUuid: string;
11
+ }
12
+
13
+ const ClinicalViewsSummary: React.FC<OverviewListProps> = memo(({ patientUuid }) => {
14
+ const { tileDefinitions, trueConceptUuid, falseConceptUuid, otherConceptUuid } = useConfig();
15
+
16
+ const { t } = useTranslation();
17
+
18
+ const tilesData = useMemo(() => {
19
+ const configConcepts = {
20
+ trueConceptUuid,
21
+ falseConceptUuid,
22
+ otherConceptUuid,
23
+ };
24
+
25
+ return tileDefinitions?.map((tile: MenuCardProps) => ({
26
+ title: t(tile.tileHeader),
27
+ columns: getEncounterTileColumns(tile, configConcepts),
28
+ }));
29
+ }, [tileDefinitions, t, trueConceptUuid, falseConceptUuid, otherConceptUuid]);
30
+
31
+ return tilesData?.length > 0 ? (
32
+ <>
33
+ {tilesData.map((tile, index) => (
34
+ <EncounterTile key={index} patientUuid={patientUuid} columns={tile.columns} headerTitle={tile.title} />
35
+ ))}
36
+ </>
37
+ ) : null;
38
+ });
39
+
40
+ export default ClinicalViewsSummary;
@@ -0,0 +1,94 @@
1
+ import React, { memo } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { CodeSnippetSkeleton, Tile, Layer, Grid, Column } from '@carbon/react';
4
+ import { isNil } from 'lodash-es';
5
+ import { NumericObservation, useLayoutType } from '@openmrs/esm-framework';
6
+ import { useLastEncounter } from '../hooks';
7
+ import type { EncounterTileColumn, EncounterTileProps } from '../types';
8
+ import { withUnit, getConceptUnitsFromEncounter } from '../utils/concept-utils';
9
+ import styles from './tile.scss';
10
+
11
+ export const EncounterTile = memo(({ patientUuid, columns, headerTitle }: EncounterTileProps) => {
12
+ const isTablet = useLayoutType() === 'tablet';
13
+ const columnSpan = columns.length > 0 ? Math.floor(16 / columns.length) : 16;
14
+
15
+ return (
16
+ <Layer className={styles.layer}>
17
+ <Tile className={styles.tile}>
18
+ <div className={isTablet ? styles.tabletHeading : styles.desktopHeading}>
19
+ <h4 className={styles.title}>{headerTitle}</h4>
20
+ </div>
21
+ <Grid fullWidth>
22
+ {columns.map((column, index) => (
23
+ <Column
24
+ key={`${column.encounterTypeUuid}-${column.title}-${index}`}
25
+ sm={columnSpan}
26
+ md={columnSpan}
27
+ lg={columnSpan}
28
+ span={columnSpan}
29
+ >
30
+ <EncounterData patientUuid={patientUuid} column={column} />
31
+ </Column>
32
+ ))}
33
+ </Grid>
34
+ </Tile>
35
+ </Layer>
36
+ );
37
+ });
38
+
39
+ const EncounterData: React.FC<{
40
+ patientUuid: string;
41
+ column: EncounterTileColumn;
42
+ }> = ({ patientUuid, column }) => {
43
+ const { t } = useTranslation();
44
+ const { lastEncounter, isLoading, error, isValidating } = useLastEncounter(patientUuid, column.encounterTypeUuid);
45
+ const units = getConceptUnitsFromEncounter(lastEncounter, column.concept);
46
+ const summaryUnits = column.summaryConcept?.primaryConcept
47
+ ? getConceptUnitsFromEncounter(lastEncounter, column.summaryConcept.primaryConcept)
48
+ : null;
49
+ const obsValue = column.getObsValue(lastEncounter);
50
+ const summaryValue =
51
+ column.hasSummary === true && column.getSummaryObsValue && typeof column.getSummaryObsValue === 'function'
52
+ ? column.getSummaryObsValue(lastEncounter)
53
+ : null;
54
+
55
+ if (isLoading || isValidating) {
56
+ return <CodeSnippetSkeleton type="multi" className="skeleton" />;
57
+ }
58
+
59
+ if (error || lastEncounter === undefined) {
60
+ return (
61
+ <>
62
+ <span className={styles.tileTitle}>{t(column.title)}</span>
63
+ <span className={styles.tileValue}>{error?.message}</span>
64
+ </>
65
+ );
66
+ }
67
+
68
+ const isNumericObs = typeof obsValue === 'number' && column.concept;
69
+ const showObsValue = !(obsValue === '--' && summaryValue !== '--' && !isNil(summaryValue));
70
+
71
+ return (
72
+ <>
73
+ {showObsValue && isNumericObs ? (
74
+ <NumericObservation
75
+ value={obsValue}
76
+ unit={units}
77
+ label={t(column.header)}
78
+ conceptUuid={column.concept}
79
+ patientUuid={patientUuid}
80
+ variant="card"
81
+ />
82
+ ) : (
83
+ <>
84
+ <span className={styles.tileTitle}>{t(column.header)}</span>
85
+ {showObsValue && <div className={styles.tileValue}>{withUnit(obsValue, units)}</div>}
86
+ </>
87
+ )}
88
+
89
+ {!isNil(summaryValue) && summaryValue !== '--' && (
90
+ <div className={styles.tileValue}>{withUnit(summaryValue, summaryUnits)}</div>
91
+ )}
92
+ </>
93
+ );
94
+ };
@@ -0,0 +1,82 @@
1
+ @use '@carbon/layout';
2
+ @use '@carbon/type';
3
+ @use '@openmrs/esm-styleguide/src/vars' as *;
4
+
5
+ .title {
6
+ @include type.type-style('productive-heading-03');
7
+ }
8
+
9
+ .title:after {
10
+ content: '';
11
+ display: block;
12
+ width: layout.$spacing-07;
13
+ padding-top: layout.$spacing-01;
14
+ border-bottom: layout.$spacing-03 solid $brand-teal-01;
15
+ }
16
+
17
+ .tileTitle {
18
+ @include type.type-style('body-long-01');
19
+ @include type.type-style('label-01');
20
+ color: $text-02;
21
+ display: block;
22
+ }
23
+
24
+ .tileValue {
25
+ margin: layout.$spacing-04 0 layout.$spacing-04;
26
+ display: block;
27
+ }
28
+
29
+ .tileBox {
30
+ width: 25%;
31
+ display: flex;
32
+ flex-direction: row;
33
+ flex: 1;
34
+ gap: layout.$spacing-05;
35
+ justify-content: space-around;
36
+ }
37
+
38
+ .desktopHeading {
39
+ h4 {
40
+ @include type.type-style('heading-compact-02');
41
+ color: $text-02;
42
+ }
43
+ }
44
+
45
+ .tabletHeading {
46
+ h4 {
47
+ @include type.type-style('heading-03');
48
+ color: $text-02;
49
+ }
50
+ }
51
+
52
+ .desktopHeading,
53
+ .tabletHeading {
54
+ text-align: left;
55
+ text-transform: capitalize;
56
+ margin-bottom: layout.$spacing-05;
57
+
58
+ h4:after {
59
+ content: '';
60
+ display: block;
61
+ width: layout.$spacing-07;
62
+ padding-top: layout.$spacing-01;
63
+ border-bottom: 0.375rem solid var(--brand-03);
64
+ }
65
+ }
66
+
67
+ .heading:after {
68
+ content: '';
69
+ display: block;
70
+ width: layout.$spacing-07;
71
+ padding-top: layout.$spacing-01;
72
+ border-bottom: 0.375rem solid var(--brand-03);
73
+ }
74
+
75
+ .tile {
76
+ border: 1px solid $ui-03;
77
+ margin-bottom: layout.$spacing-03;
78
+ }
79
+
80
+ [data-extension-id='clinical-views-summary'] {
81
+ height: auto;
82
+ }
@@ -0,0 +1,3 @@
1
+ export * from './useEncounterRows';
2
+ export * from './useFormsJson';
3
+ export * from './useLastEncounter';
@@ -0,0 +1,60 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import useSWR from 'swr';
3
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
4
+ import { type Encounter } from '../types';
5
+
6
+ export const encounterRepresentation =
7
+ 'custom:(uuid,encounterDatetime,encounterType,location:(uuid,name),' +
8
+ 'patient:(uuid,display,age,identifiers,person),encounterProviders:(uuid,provider:(uuid,name)),' +
9
+ 'obs:(uuid,obsDatetime,voided,groupMembers,concept:(uuid,name:(uuid,name)),value:(uuid,name:(uuid,name),' +
10
+ 'names:(uuid,conceptNameType,name))),form:(uuid,name),visit:(uuid,startDatetime,stopDatetime,visitType:(uuid,display)))';
11
+
12
+ interface EncounterResponse {
13
+ results: Encounter[];
14
+ totalCount?: number;
15
+ }
16
+
17
+ export function useEncounterRows(
18
+ patientUuid: string,
19
+ encounterType: string,
20
+ encounterFilter: (encounter) => boolean,
21
+ afterFormSaveAction: () => void,
22
+ pageSize?: number,
23
+ currentPage?: number,
24
+ ) {
25
+ const startIndex = (currentPage - 1) * pageSize;
26
+ const [encounters, setEncounters] = useState([]);
27
+ const url = `${restBaseUrl}/encounter?encounterType=${encounterType}&patient=${patientUuid}&v=${encounterRepresentation}&totalCount=true&limit=${pageSize}&startIndex=${startIndex}`;
28
+
29
+ const { data: response, error, isLoading, mutate } = useSWR<{ data: EncounterResponse }, Error>(url, openmrsFetch);
30
+
31
+ useEffect(() => {
32
+ if (response) {
33
+ response.data.results.sort(
34
+ (a, b) => new Date(b.encounterDatetime).getTime() - new Date(a.encounterDatetime).getTime(),
35
+ );
36
+
37
+ if (encounterFilter) {
38
+ setEncounters(response.data.results.filter((encounter) => encounterFilter(encounter)));
39
+ } else {
40
+ setEncounters([...response.data.results]);
41
+ }
42
+ }
43
+ }, [encounterFilter, response]);
44
+
45
+ const onFormSave = useCallback(() => {
46
+ mutate();
47
+ if (afterFormSaveAction) {
48
+ afterFormSaveAction();
49
+ }
50
+ }, [afterFormSaveAction, mutate]);
51
+
52
+ return {
53
+ encounters,
54
+ total: response?.data?.totalCount,
55
+ isLoading,
56
+ error,
57
+ onFormSave,
58
+ mutate,
59
+ };
60
+ }
@@ -0,0 +1,13 @@
1
+ import { type Encounter, restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
2
+
3
+ export function useEncountersByVisit(patientUuid: string, visitUuid: string) {
4
+ const customRepresentation =
5
+ 'custom:(uuid,encounterType:(uuid,display),encounterProviders:(provider:(person:(display))),encounterDatetime,visit:(uuid))';
6
+ const url = `${restBaseUrl}/encounter?patient=${patientUuid}&order=desc&visit=${visitUuid}&v=${customRepresentation}`;
7
+ const { data: encounters, ...rest } = useOpenmrsFetchAll<Encounter>(url);
8
+
9
+ return {
10
+ encounters,
11
+ ...rest,
12
+ };
13
+ }
@@ -0,0 +1,15 @@
1
+ import useSWR from 'swr';
2
+
3
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
4
+ import { type Form } from '../types';
5
+
6
+ export function useFormsJson(formUuid: string) {
7
+ const url = `${restBaseUrl}/form/${formUuid}`;
8
+ const { data, isLoading, error } = useSWR<{ data: Form }, Error>(formUuid ? url : null, openmrsFetch);
9
+
10
+ return {
11
+ formsJson: data?.data ?? null,
12
+ isLoading,
13
+ error,
14
+ };
15
+ }
@@ -0,0 +1,29 @@
1
+ import { openmrsFetch } from '@openmrs/esm-framework';
2
+ import { type Encounter } from '../types';
3
+ import useSWR from 'swr';
4
+
5
+ const encounterRepresentation =
6
+ 'custom:(uuid,encounterDatetime,encounterType,location:(uuid,name),' +
7
+ 'patient:(uuid,display,age,identifiers,person),encounterProviders:(uuid,provider:(uuid,name)),' +
8
+ 'obs:(uuid,obsDatetime,voided,groupMembers,concept:(uuid,display,units,name:(uuid,name)),value:(uuid,name:(uuid,name,display),' +
9
+ 'names:(uuid,conceptNameType,name,display))),form:(uuid,name))';
10
+
11
+ export function useLastEncounter(patientUuid: string, encounterType: string) {
12
+ const query = `encounterType=${encounterType}&patient=${patientUuid}`;
13
+ const endpointUrl =
14
+ patientUuid && encounterType
15
+ ? `/ws/rest/v1/encounter?${query}&v=${encounterRepresentation}&limit=1&order=desc&startIndex=0`
16
+ : null;
17
+
18
+ const { data, error, isLoading, isValidating } = useSWR<{ data: { results: Array<Encounter> } }, Error>(
19
+ endpointUrl,
20
+ openmrsFetch,
21
+ );
22
+
23
+ return {
24
+ lastEncounter: data?.data.results?.length > 0 ? data?.data.results[0] : null,
25
+ error,
26
+ isLoading,
27
+ isValidating,
28
+ };
29
+ }