vintasend 0.4.0 → 0.4.7

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 (284) hide show
  1. package/README.md +5 -0
  2. package/dist/examples/vintasend-medplum-example/.env.example +11 -0
  3. package/dist/examples/vintasend-medplum-example/IMPLEMENTATION_PLAN_FILE_ATTACHMENTS.md +597 -0
  4. package/dist/examples/vintasend-medplum-example/README.md +190 -0
  5. package/dist/examples/vintasend-medplum-example/TUTORIAL_EMAIL_NOTIFICATIONS.md +2596 -0
  6. package/dist/examples/vintasend-medplum-example/bots/handlers/send-pending-notifications-bot.ts +39 -0
  7. package/dist/examples/vintasend-medplum-example/bots/handlers/send-task-assignment-email.ts +41 -0
  8. package/dist/examples/vintasend-medplum-example/bots/handlers/task-due-soon-notification-bot.ts +86 -0
  9. package/dist/examples/vintasend-medplum-example/bots/index.ts +53 -0
  10. package/dist/examples/vintasend-medplum-example/bots/services/emails/schedule-task-due-soon-email.ts +84 -0
  11. package/dist/examples/vintasend-medplum-example/bots/services/emails/send-task-assignment-email.test.ts +388 -0
  12. package/dist/examples/vintasend-medplum-example/bots/services/emails/send-task-assignment-email.ts +113 -0
  13. package/dist/examples/vintasend-medplum-example/bots/shared/task-due-soon-helpers.ts +115 -0
  14. package/dist/examples/vintasend-medplum-example/bots/task-assignment-bot.ts +41 -0
  15. package/dist/examples/vintasend-medplum-example/compiled-notification-templates.json +6 -0
  16. package/dist/examples/vintasend-medplum-example/esbuild-script.mjs +71 -0
  17. package/dist/examples/vintasend-medplum-example/index.html +14 -0
  18. package/dist/examples/vintasend-medplum-example/lib/constants.ts +32 -0
  19. package/dist/examples/vintasend-medplum-example/lib/extensions.ts +1 -0
  20. package/dist/examples/vintasend-medplum-example/lib/file-upload.test.ts +389 -0
  21. package/dist/examples/vintasend-medplum-example/lib/file-upload.ts +222 -0
  22. package/dist/examples/vintasend-medplum-example/lib/medplum-singleton.ts +18 -0
  23. package/dist/examples/vintasend-medplum-example/lib/notification-service.test.ts +293 -0
  24. package/dist/examples/vintasend-medplum-example/lib/notification-service.ts +284 -0
  25. package/dist/examples/vintasend-medplum-example/lib/patients.ts +20 -0
  26. package/dist/examples/vintasend-medplum-example/notification-templates/emails/task-assignment/body.html.pug +37 -0
  27. package/dist/examples/vintasend-medplum-example/notification-templates/emails/task-assignment/subject.txt.pug +4 -0
  28. package/dist/examples/vintasend-medplum-example/notification-templates/emails/task-due-soon/body.html.pug +34 -0
  29. package/dist/examples/vintasend-medplum-example/notification-templates/emails/task-due-soon/subject.txt.pug +4 -0
  30. package/dist/examples/vintasend-medplum-example/package.json +75 -0
  31. package/dist/examples/vintasend-medplum-example/plugins/gql-plugin.mjs +31 -0
  32. package/dist/examples/vintasend-medplum-example/postcss.config.mjs +21 -0
  33. package/dist/examples/vintasend-medplum-example/public/favicon.ico +0 -0
  34. package/dist/examples/vintasend-medplum-example/public/img/integrations/acuity.png +0 -0
  35. package/dist/examples/vintasend-medplum-example/public/img/integrations/auth0.png +0 -0
  36. package/dist/examples/vintasend-medplum-example/public/img/integrations/azure.png +0 -0
  37. package/dist/examples/vintasend-medplum-example/public/img/integrations/calcom.png +0 -0
  38. package/dist/examples/vintasend-medplum-example/public/img/integrations/candid.png +0 -0
  39. package/dist/examples/vintasend-medplum-example/public/img/integrations/claude.png +0 -0
  40. package/dist/examples/vintasend-medplum-example/public/img/integrations/datadog.png +0 -0
  41. package/dist/examples/vintasend-medplum-example/public/img/integrations/deepseek.png +0 -0
  42. package/dist/examples/vintasend-medplum-example/public/img/integrations/entra.png +0 -0
  43. package/dist/examples/vintasend-medplum-example/public/img/integrations/epic.png +0 -0
  44. package/dist/examples/vintasend-medplum-example/public/img/integrations/google.png +0 -0
  45. package/dist/examples/vintasend-medplum-example/public/img/integrations/healthgorilla.png +0 -0
  46. package/dist/examples/vintasend-medplum-example/public/img/integrations/healthie.png +0 -0
  47. package/dist/examples/vintasend-medplum-example/public/img/integrations/labcorp.png +0 -0
  48. package/dist/examples/vintasend-medplum-example/public/img/integrations/okta.png +0 -0
  49. package/dist/examples/vintasend-medplum-example/public/img/integrations/openai.png +0 -0
  50. package/dist/examples/vintasend-medplum-example/public/img/integrations/particle.png +0 -0
  51. package/dist/examples/vintasend-medplum-example/public/img/integrations/quest.png +0 -0
  52. package/dist/examples/vintasend-medplum-example/public/img/integrations/recaptcha.png +0 -0
  53. package/dist/examples/vintasend-medplum-example/public/img/integrations/snowflake.png +0 -0
  54. package/dist/examples/vintasend-medplum-example/public/img/integrations/stedi.png +0 -0
  55. package/dist/examples/vintasend-medplum-example/public/img/integrations/stripe.png +0 -0
  56. package/dist/examples/vintasend-medplum-example/public/img/integrations/sumo.png +0 -0
  57. package/dist/examples/vintasend-medplum-example/scripts/README.md +162 -0
  58. package/dist/examples/vintasend-medplum-example/scripts/client.ts +18 -0
  59. package/dist/examples/vintasend-medplum-example/scripts/deploy-bots.ts +171 -0
  60. package/dist/examples/vintasend-medplum-example/src/App.tsx +185 -0
  61. package/dist/examples/vintasend-medplum-example/src/components/ChargeItem/ChargeItemList.test.tsx +350 -0
  62. package/dist/examples/vintasend-medplum-example/src/components/ChargeItem/ChargeItemList.tsx +241 -0
  63. package/dist/examples/vintasend-medplum-example/src/components/ChargeItem/ChargeItemPanel.test.tsx +616 -0
  64. package/dist/examples/vintasend-medplum-example/src/components/ChargeItem/ChargeItemPanel.tsx +138 -0
  65. package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionItem.test.tsx +92 -0
  66. package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionItem.tsx +47 -0
  67. package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionList.test.tsx +464 -0
  68. package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionList.tsx +186 -0
  69. package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionModal.test.tsx +80 -0
  70. package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionModal.tsx +82 -0
  71. package/dist/examples/vintasend-medplum-example/src/components/DoseSpotIcon.test.tsx +100 -0
  72. package/dist/examples/vintasend-medplum-example/src/components/DoseSpotIcon.tsx +20 -0
  73. package/dist/examples/vintasend-medplum-example/src/components/IntegrationCard.module.css +3 -0
  74. package/dist/examples/vintasend-medplum-example/src/components/IntegrationCard.tsx +62 -0
  75. package/dist/examples/vintasend-medplum-example/src/components/MessageWithLinks.tsx +47 -0
  76. package/dist/examples/vintasend-medplum-example/src/components/PerformingLabInput.test.tsx +299 -0
  77. package/dist/examples/vintasend-medplum-example/src/components/PerformingLabInput.tsx +52 -0
  78. package/dist/examples/vintasend-medplum-example/src/components/ResourceFormWithRequiredProfile.tsx +82 -0
  79. package/dist/examples/vintasend-medplum-example/src/components/encounter/BillingTab.test.tsx +1016 -0
  80. package/dist/examples/vintasend-medplum-example/src/components/encounter/BillingTab.tsx +298 -0
  81. package/dist/examples/vintasend-medplum-example/src/components/encounter/EncounterChart.test.tsx +732 -0
  82. package/dist/examples/vintasend-medplum-example/src/components/encounter/EncounterChart.tsx +282 -0
  83. package/dist/examples/vintasend-medplum-example/src/components/encounter/EncounterHeader.test.tsx +268 -0
  84. package/dist/examples/vintasend-medplum-example/src/components/encounter/EncounterHeader.tsx +224 -0
  85. package/dist/examples/vintasend-medplum-example/src/components/encounter/SignAddendum.test.tsx +255 -0
  86. package/dist/examples/vintasend-medplum-example/src/components/encounter/SignAddendum.tsx +212 -0
  87. package/dist/examples/vintasend-medplum-example/src/components/encounter/SignLockDialog.test.tsx +120 -0
  88. package/dist/examples/vintasend-medplum-example/src/components/encounter/SignLockDialog.tsx +57 -0
  89. package/dist/examples/vintasend-medplum-example/src/components/encounter/VisitDetailsPanel.test.tsx +224 -0
  90. package/dist/examples/vintasend-medplum-example/src/components/encounter/VisitDetailsPanel.tsx +100 -0
  91. package/dist/examples/vintasend-medplum-example/src/components/labs/CoverageInput.test.tsx +431 -0
  92. package/dist/examples/vintasend-medplum-example/src/components/labs/CoverageInput.tsx +130 -0
  93. package/dist/examples/vintasend-medplum-example/src/components/labs/LabListItem.module.css +31 -0
  94. package/dist/examples/vintasend-medplum-example/src/components/labs/LabListItem.test.tsx +234 -0
  95. package/dist/examples/vintasend-medplum-example/src/components/labs/LabListItem.tsx +143 -0
  96. package/dist/examples/vintasend-medplum-example/src/components/labs/LabOrderDetails.module.css +11 -0
  97. package/dist/examples/vintasend-medplum-example/src/components/labs/LabOrderDetails.test.tsx +875 -0
  98. package/dist/examples/vintasend-medplum-example/src/components/labs/LabOrderDetails.tsx +943 -0
  99. package/dist/examples/vintasend-medplum-example/src/components/labs/LabResultDetails.test.tsx +413 -0
  100. package/dist/examples/vintasend-medplum-example/src/components/labs/LabResultDetails.tsx +203 -0
  101. package/dist/examples/vintasend-medplum-example/src/components/labs/LabSelectEmpty.tsx +22 -0
  102. package/dist/examples/vintasend-medplum-example/src/components/labs/README.md +104 -0
  103. package/dist/examples/vintasend-medplum-example/src/components/labs/TestMetadataCardInput.test.tsx +318 -0
  104. package/dist/examples/vintasend-medplum-example/src/components/labs/TestMetadataCardInput.tsx +87 -0
  105. package/dist/examples/vintasend-medplum-example/src/components/messages/ChatList.test.tsx +126 -0
  106. package/dist/examples/vintasend-medplum-example/src/components/messages/ChatList.tsx +38 -0
  107. package/dist/examples/vintasend-medplum-example/src/components/messages/ChatListItem.module.css +23 -0
  108. package/dist/examples/vintasend-medplum-example/src/components/messages/ChatListItem.test.tsx +167 -0
  109. package/dist/examples/vintasend-medplum-example/src/components/messages/ChatListItem.tsx +53 -0
  110. package/dist/examples/vintasend-medplum-example/src/components/messages/NewTopicDialog.test.tsx +94 -0
  111. package/dist/examples/vintasend-medplum-example/src/components/messages/NewTopicDialog.tsx +165 -0
  112. package/dist/examples/vintasend-medplum-example/src/components/messages/ParticipantFilter.module.css +8 -0
  113. package/dist/examples/vintasend-medplum-example/src/components/messages/ParticipantFilter.test.tsx +523 -0
  114. package/dist/examples/vintasend-medplum-example/src/components/messages/ParticipantFilter.tsx +230 -0
  115. package/dist/examples/vintasend-medplum-example/src/components/messages/ThreadInbox.module.css +23 -0
  116. package/dist/examples/vintasend-medplum-example/src/components/messages/ThreadInbox.test.tsx +567 -0
  117. package/dist/examples/vintasend-medplum-example/src/components/messages/ThreadInbox.tsx +358 -0
  118. package/dist/examples/vintasend-medplum-example/src/components/plandefinition/AddPlanDefinition.module.css +40 -0
  119. package/dist/examples/vintasend-medplum-example/src/components/plandefinition/AddPlanDefinition.tsx +257 -0
  120. package/dist/examples/vintasend-medplum-example/src/components/schedule/CreateVisit.module.css +7 -0
  121. package/dist/examples/vintasend-medplum-example/src/components/schedule/CreateVisit.test.tsx +279 -0
  122. package/dist/examples/vintasend-medplum-example/src/components/schedule/CreateVisit.tsx +156 -0
  123. package/dist/examples/vintasend-medplum-example/src/components/spaces/HistoryList.module.css +45 -0
  124. package/dist/examples/vintasend-medplum-example/src/components/spaces/HistoryList.test.tsx +90 -0
  125. package/dist/examples/vintasend-medplum-example/src/components/spaces/HistoryList.tsx +84 -0
  126. package/dist/examples/vintasend-medplum-example/src/components/spaces/ResourceBox.module.css +26 -0
  127. package/dist/examples/vintasend-medplum-example/src/components/spaces/ResourceBox.tsx +90 -0
  128. package/dist/examples/vintasend-medplum-example/src/components/spaces/ResourcePanel.test.tsx +305 -0
  129. package/dist/examples/vintasend-medplum-example/src/components/spaces/ResourcePanel.tsx +46 -0
  130. package/dist/examples/vintasend-medplum-example/src/components/spaces/SpacesInbox.module.css +262 -0
  131. package/dist/examples/vintasend-medplum-example/src/components/spaces/SpacesInbox.test.tsx +622 -0
  132. package/dist/examples/vintasend-medplum-example/src/components/spaces/SpacesInbox.tsx +286 -0
  133. package/dist/examples/vintasend-medplum-example/src/components/tasks/NewTaskModal.tsx +275 -0
  134. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskAttachmentList.tsx +132 -0
  135. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskBoard.module.css +45 -0
  136. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskBoard.test.tsx +749 -0
  137. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskBoard.tsx +416 -0
  138. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailPanel.test.tsx +278 -0
  139. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailPanel.tsx +133 -0
  140. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailsModal.module.css +16 -0
  141. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailsModal.test.tsx +255 -0
  142. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailsModal.tsx +203 -0
  143. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskFileUpload.tsx +129 -0
  144. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskFilterMenu.test.tsx +156 -0
  145. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskFilterMenu.tsx +142 -0
  146. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskFilterMenu.utils.ts +28 -0
  147. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskInputNote.test.tsx +134 -0
  148. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskInputNote.tsx +250 -0
  149. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskListItem.module.css +23 -0
  150. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskListItem.test.tsx +149 -0
  151. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskListItem.tsx +53 -0
  152. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskNoteItem.test.tsx +68 -0
  153. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskNoteItem.tsx +46 -0
  154. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskProperties.test.tsx +555 -0
  155. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskProperties.tsx +170 -0
  156. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskSelectEmpty.test.tsx +32 -0
  157. package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskSelectEmpty.tsx +34 -0
  158. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/SimpleTask.test.tsx +47 -0
  159. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/SimpleTask.tsx +29 -0
  160. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskPanel.test.tsx +285 -0
  161. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskPanel.tsx +129 -0
  162. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskQuestionnaireForm.test.tsx +455 -0
  163. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskQuestionnaireForm.tsx +167 -0
  164. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskServiceRequest.test.tsx +435 -0
  165. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskServiceRequest.tsx +116 -0
  166. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskStatusPanel.module.css +38 -0
  167. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskStatusPanel.test.tsx +200 -0
  168. package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskStatusPanel.tsx +84 -0
  169. package/dist/examples/vintasend-medplum-example/src/components/utils.test.ts +176 -0
  170. package/dist/examples/vintasend-medplum-example/src/components/utils.ts +17 -0
  171. package/dist/examples/vintasend-medplum-example/src/config/constants.ts +3 -0
  172. package/dist/examples/vintasend-medplum-example/src/hooks/useDebouncedUpdateResource.test.tsx +166 -0
  173. package/dist/examples/vintasend-medplum-example/src/hooks/useDebouncedUpdateResource.ts +28 -0
  174. package/dist/examples/vintasend-medplum-example/src/hooks/useEncounter.test.tsx +94 -0
  175. package/dist/examples/vintasend-medplum-example/src/hooks/useEncounter.ts +11 -0
  176. package/dist/examples/vintasend-medplum-example/src/hooks/useEncounterChart.test.tsx +477 -0
  177. package/dist/examples/vintasend-medplum-example/src/hooks/useEncounterChart.ts +191 -0
  178. package/dist/examples/vintasend-medplum-example/src/hooks/usePatient.test.tsx +100 -0
  179. package/dist/examples/vintasend-medplum-example/src/hooks/usePatient.ts +18 -0
  180. package/dist/examples/vintasend-medplum-example/src/hooks/useThreadInbox.test.tsx +379 -0
  181. package/dist/examples/vintasend-medplum-example/src/hooks/useThreadInbox.ts +194 -0
  182. package/dist/examples/vintasend-medplum-example/src/index.css +8 -0
  183. package/dist/examples/vintasend-medplum-example/src/main.tsx +57 -0
  184. package/dist/examples/vintasend-medplum-example/src/pages/SearchPage.module.css +6 -0
  185. package/dist/examples/vintasend-medplum-example/src/pages/SearchPage.test.tsx +295 -0
  186. package/dist/examples/vintasend-medplum-example/src/pages/SearchPage.tsx +124 -0
  187. package/dist/examples/vintasend-medplum-example/src/pages/SignInPage.test.tsx +77 -0
  188. package/dist/examples/vintasend-medplum-example/src/pages/SignInPage.tsx +22 -0
  189. package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterChartPage.test.tsx +87 -0
  190. package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterChartPage.tsx +27 -0
  191. package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterModal.module.css +16 -0
  192. package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterModal.test.tsx +287 -0
  193. package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterModal.tsx +151 -0
  194. package/dist/examples/vintasend-medplum-example/src/pages/integrations/DoseSpotFavoritesPage.test.tsx +519 -0
  195. package/dist/examples/vintasend-medplum-example/src/pages/integrations/DoseSpotFavoritesPage.tsx +179 -0
  196. package/dist/examples/vintasend-medplum-example/src/pages/integrations/FavoriteMedicationsTable.tsx +76 -0
  197. package/dist/examples/vintasend-medplum-example/src/pages/integrations/IntegrationsPage.test.tsx +234 -0
  198. package/dist/examples/vintasend-medplum-example/src/pages/integrations/IntegrationsPage.tsx +222 -0
  199. package/dist/examples/vintasend-medplum-example/src/pages/labs/OrderLabsPage.test.tsx +356 -0
  200. package/dist/examples/vintasend-medplum-example/src/pages/labs/OrderLabsPage.tsx +275 -0
  201. package/dist/examples/vintasend-medplum-example/src/pages/messages/MessagesPage.module.css +8 -0
  202. package/dist/examples/vintasend-medplum-example/src/pages/messages/MessagesPage.test.tsx +103 -0
  203. package/dist/examples/vintasend-medplum-example/src/pages/messages/MessagesPage.tsx +78 -0
  204. package/dist/examples/vintasend-medplum-example/src/pages/patient/CommunicationTab.test.tsx +84 -0
  205. package/dist/examples/vintasend-medplum-example/src/pages/patient/CommunicationTab.tsx +82 -0
  206. package/dist/examples/vintasend-medplum-example/src/pages/patient/DoseSpotAdvancedOptions.test.tsx +364 -0
  207. package/dist/examples/vintasend-medplum-example/src/pages/patient/DoseSpotAdvancedOptions.tsx +149 -0
  208. package/dist/examples/vintasend-medplum-example/src/pages/patient/DoseSpotTab.test.tsx +159 -0
  209. package/dist/examples/vintasend-medplum-example/src/pages/patient/DoseSpotTab.tsx +37 -0
  210. package/dist/examples/vintasend-medplum-example/src/pages/patient/EditTab.test.tsx +140 -0
  211. package/dist/examples/vintasend-medplum-example/src/pages/patient/EditTab.tsx +72 -0
  212. package/dist/examples/vintasend-medplum-example/src/pages/patient/ExportTab.test.tsx +57 -0
  213. package/dist/examples/vintasend-medplum-example/src/pages/patient/ExportTab.tsx +14 -0
  214. package/dist/examples/vintasend-medplum-example/src/pages/patient/IntakeFormPage.test.tsx +241 -0
  215. package/dist/examples/vintasend-medplum-example/src/pages/patient/IntakeFormPage.tsx +710 -0
  216. package/dist/examples/vintasend-medplum-example/src/pages/patient/LabsPage.module.css +37 -0
  217. package/dist/examples/vintasend-medplum-example/src/pages/patient/LabsPage.test.tsx +428 -0
  218. package/dist/examples/vintasend-medplum-example/src/pages/patient/LabsPage.tsx +334 -0
  219. package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.module.css +24 -0
  220. package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.test.tsx +154 -0
  221. package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.tsx +115 -0
  222. package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.utils.test.ts +223 -0
  223. package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.utils.ts +89 -0
  224. package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientSearchPage.test.tsx +147 -0
  225. package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientSearchPage.tsx +79 -0
  226. package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientTabsNavigation.tsx +35 -0
  227. package/dist/examples/vintasend-medplum-example/src/pages/patient/TasksTab.test.tsx +185 -0
  228. package/dist/examples/vintasend-medplum-example/src/pages/patient/TasksTab.tsx +115 -0
  229. package/dist/examples/vintasend-medplum-example/src/pages/patient/TimelineTab.tsx +14 -0
  230. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceCreatePage.test.tsx +170 -0
  231. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceCreatePage.tsx +117 -0
  232. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceDetailPage.tsx +28 -0
  233. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceEditPage.test.tsx +131 -0
  234. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceEditPage.tsx +65 -0
  235. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceHistoryPage.test.tsx +108 -0
  236. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceHistoryPage.tsx +16 -0
  237. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourcePage.module.css +7 -0
  238. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourcePage.test.tsx +37 -0
  239. package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourcePage.tsx +44 -0
  240. package/dist/examples/vintasend-medplum-example/src/pages/resource/useResourceType.ts +44 -0
  241. package/dist/examples/vintasend-medplum-example/src/pages/resource/utils.ts +9 -0
  242. package/dist/examples/vintasend-medplum-example/src/pages/schedule/SchedulePage.test.tsx +302 -0
  243. package/dist/examples/vintasend-medplum-example/src/pages/schedule/SchedulePage.tsx +416 -0
  244. package/dist/examples/vintasend-medplum-example/src/pages/spaces/ChatInput.tsx +91 -0
  245. package/dist/examples/vintasend-medplum-example/src/pages/spaces/SpacesPage.module.css +6 -0
  246. package/dist/examples/vintasend-medplum-example/src/pages/spaces/SpacesPage.test.tsx +102 -0
  247. package/dist/examples/vintasend-medplum-example/src/pages/spaces/SpacesPage.tsx +44 -0
  248. package/dist/examples/vintasend-medplum-example/src/pages/tasks/TasksPage.module.css +7 -0
  249. package/dist/examples/vintasend-medplum-example/src/pages/tasks/TasksPage.test.tsx +133 -0
  250. package/dist/examples/vintasend-medplum-example/src/pages/tasks/TasksPage.tsx +91 -0
  251. package/dist/examples/vintasend-medplum-example/src/test-utils/render.tsx +20 -0
  252. package/dist/examples/vintasend-medplum-example/src/test.setup.ts +49 -0
  253. package/dist/examples/vintasend-medplum-example/src/types/encounter.ts +8 -0
  254. package/dist/examples/vintasend-medplum-example/src/types/spaces.ts +10 -0
  255. package/dist/examples/vintasend-medplum-example/src/utils/chargeitems.test.ts +141 -0
  256. package/dist/examples/vintasend-medplum-example/src/utils/chargeitems.ts +59 -0
  257. package/dist/examples/vintasend-medplum-example/src/utils/claims.test.ts +153 -0
  258. package/dist/examples/vintasend-medplum-example/src/utils/claims.ts +65 -0
  259. package/dist/examples/vintasend-medplum-example/src/utils/communication-search.ts +47 -0
  260. package/dist/examples/vintasend-medplum-example/src/utils/coverage.test.ts +48 -0
  261. package/dist/examples/vintasend-medplum-example/src/utils/coverage.ts +33 -0
  262. package/dist/examples/vintasend-medplum-example/src/utils/documentReference.test.ts +102 -0
  263. package/dist/examples/vintasend-medplum-example/src/utils/documentReference.ts +55 -0
  264. package/dist/examples/vintasend-medplum-example/src/utils/encounter.test.ts +169 -0
  265. package/dist/examples/vintasend-medplum-example/src/utils/encounter.ts +261 -0
  266. package/dist/examples/vintasend-medplum-example/src/utils/intake-form.test.ts +154 -0
  267. package/dist/examples/vintasend-medplum-example/src/utils/intake-form.ts +272 -0
  268. package/dist/examples/vintasend-medplum-example/src/utils/intake-utils.test.ts +1137 -0
  269. package/dist/examples/vintasend-medplum-example/src/utils/intake-utils.ts +827 -0
  270. package/dist/examples/vintasend-medplum-example/src/utils/notifications.test.ts +27 -0
  271. package/dist/examples/vintasend-medplum-example/src/utils/notifications.ts +15 -0
  272. package/dist/examples/vintasend-medplum-example/src/utils/spaceMessaging.ts +249 -0
  273. package/dist/examples/vintasend-medplum-example/src/utils/spacePersistence.test.ts +450 -0
  274. package/dist/examples/vintasend-medplum-example/src/utils/spacePersistence.ts +147 -0
  275. package/dist/examples/vintasend-medplum-example/src/utils/task-search.ts +63 -0
  276. package/dist/examples/vintasend-medplum-example/src/vite-env.d.ts +3 -0
  277. package/dist/examples/vintasend-medplum-example/tsconfig.bots.json +4 -0
  278. package/dist/examples/vintasend-medplum-example/tsconfig.json +19 -0
  279. package/dist/examples/vintasend-medplum-example/vercel.json +3 -0
  280. package/dist/examples/vintasend-medplum-example/vite.config.ts +44 -0
  281. package/dist/services/notification-backends/base-notification-backend.d.ts +5 -0
  282. package/dist/services/notification-service.js +11 -1
  283. package/dist/services/notification-template-renderers/base-email-template-renderer.d.ts +5 -0
  284. package/package.json +1 -1
@@ -0,0 +1,413 @@
1
+ // SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { MantineProvider } from '@mantine/core';
4
+ import { MockClient } from '@medplum/mock';
5
+ import { MedplumProvider } from '@medplum/react';
6
+ import { render, screen, waitFor } from '../../test-utils/render';
7
+ import { MemoryRouter } from 'react-router';
8
+ import { describe, expect, test, beforeEach } from 'vitest';
9
+ import { LabResultDetails } from './LabResultDetails';
10
+ import type { DiagnosticReport, Patient, Practitioner, Reference } from '@medplum/fhirtypes';
11
+
12
+ const mockPatient: Patient = {
13
+ resourceType: 'Patient',
14
+ id: 'patient-123',
15
+ name: [{ given: ['John'], family: 'Doe' }],
16
+ };
17
+
18
+ const mockPractitioner: Practitioner = {
19
+ resourceType: 'Practitioner',
20
+ id: 'practitioner-123',
21
+ name: [{ given: ['Dr. Jane'], family: 'Smith' }],
22
+ };
23
+
24
+ function createMockDiagnosticReport(overrides?: Partial<DiagnosticReport>): DiagnosticReport {
25
+ return {
26
+ resourceType: 'DiagnosticReport',
27
+ id: 'diagnostic-report-123',
28
+ status: 'final',
29
+ code: {
30
+ coding: [
31
+ {
32
+ system: 'http://loinc.org',
33
+ code: '24323-8',
34
+ display: 'Complete Blood Count',
35
+ },
36
+ ],
37
+ text: 'CBC with Differential',
38
+ },
39
+ subject: {
40
+ reference: 'Patient/patient-123',
41
+ },
42
+ issued: '2024-01-15T10:00:00Z',
43
+ ...overrides,
44
+ };
45
+ }
46
+
47
+ describe('LabResultDetails', () => {
48
+ let medplum: MockClient;
49
+
50
+ beforeEach(async () => {
51
+ medplum = new MockClient();
52
+ });
53
+
54
+ function setup(result: DiagnosticReport | Reference<DiagnosticReport>): ReturnType<typeof render> {
55
+ return render(
56
+ <MemoryRouter>
57
+ <MedplumProvider medplum={medplum}>
58
+ <MantineProvider>
59
+ <LabResultDetails result={result} />
60
+ </MantineProvider>
61
+ </MedplumProvider>
62
+ </MemoryRouter>
63
+ );
64
+ }
65
+
66
+ test('Renders with DiagnosticReport object', async () => {
67
+ const diagnosticReport = createMockDiagnosticReport();
68
+ await medplum.createResource(mockPatient);
69
+ await medplum.createResource(mockPractitioner);
70
+
71
+ setup(diagnosticReport);
72
+
73
+ await waitFor(() => {
74
+ expect(screen.getByText('CBC with Differential')).toBeInTheDocument();
75
+ });
76
+ expect(screen.getByText('Final')).toBeInTheDocument();
77
+ });
78
+
79
+ test('Renders with DiagnosticReport reference', async () => {
80
+ const diagnosticReport = createMockDiagnosticReport();
81
+ await medplum.createResource(diagnosticReport);
82
+ await medplum.createResource(mockPatient);
83
+ await medplum.createResource(mockPractitioner);
84
+
85
+ const reference: Reference<DiagnosticReport> = {
86
+ reference: `DiagnosticReport/${diagnosticReport.id}`,
87
+ };
88
+
89
+ setup(reference);
90
+
91
+ await waitFor(() => {
92
+ expect(screen.getByText('CBC with Differential')).toBeInTheDocument();
93
+ });
94
+ });
95
+
96
+ test('Displays default title when code text and display are missing', () => {
97
+ const diagnosticReport = createMockDiagnosticReport({
98
+ code: {
99
+ coding: [],
100
+ },
101
+ });
102
+
103
+ setup(diagnosticReport);
104
+
105
+ expect(screen.getByText('Lab Result')).toBeInTheDocument();
106
+ });
107
+
108
+ test('Displays code display when code text is missing', () => {
109
+ const diagnosticReport = createMockDiagnosticReport({
110
+ code: {
111
+ coding: [
112
+ {
113
+ system: 'http://loinc.org',
114
+ code: '24323-8',
115
+ display: 'Complete Blood Count',
116
+ },
117
+ ],
118
+ },
119
+ });
120
+
121
+ setup(diagnosticReport);
122
+
123
+ const titles = screen.getAllByText('Complete Blood Count');
124
+ expect(titles.length).toBeGreaterThan(0);
125
+ expect(titles[0]).toBeInTheDocument();
126
+ });
127
+
128
+ test('Displays status badge with correct color for final status', () => {
129
+ const diagnosticReport = createMockDiagnosticReport({ status: 'final' });
130
+
131
+ setup(diagnosticReport);
132
+
133
+ const badge = screen.getByText('Final');
134
+ expect(badge).toBeInTheDocument();
135
+ });
136
+
137
+ test('Displays status badge with correct color for entered-in-error status', () => {
138
+ const diagnosticReport = createMockDiagnosticReport({ status: 'entered-in-error' });
139
+
140
+ setup(diagnosticReport);
141
+
142
+ expect(screen.getByText('Error')).toBeInTheDocument();
143
+ });
144
+
145
+ test('Displays issued date', () => {
146
+ const diagnosticReport = createMockDiagnosticReport({ issued: '2024-01-15T10:00:00Z' });
147
+
148
+ setup(diagnosticReport);
149
+
150
+ expect(screen.getByText('Issued Date:')).toBeInTheDocument();
151
+ });
152
+
153
+ test('Displays effective date when present', () => {
154
+ const diagnosticReport = createMockDiagnosticReport({
155
+ effectiveDateTime: '2024-01-16T10:00:00Z',
156
+ });
157
+
158
+ setup(diagnosticReport);
159
+
160
+ expect(screen.getByText('Effective Date:')).toBeInTheDocument();
161
+ });
162
+
163
+ test('Does not display effective date when absent', () => {
164
+ const diagnosticReport = createMockDiagnosticReport({
165
+ effectiveDateTime: undefined,
166
+ });
167
+
168
+ setup(diagnosticReport);
169
+
170
+ expect(screen.queryByText('Effective Date:')).not.toBeInTheDocument();
171
+ });
172
+
173
+ test('Displays all result detail sections when present', async () => {
174
+ const patient = await medplum.createResource(mockPatient);
175
+ const practitioner = await medplum.createResource(mockPractitioner);
176
+ const diagnosticReport = createMockDiagnosticReport({
177
+ code: {
178
+ coding: [
179
+ {
180
+ system: 'http://loinc.org',
181
+ code: '24323-8',
182
+ display: 'Complete Blood Count',
183
+ },
184
+ {
185
+ system: 'http://loinc.org',
186
+ code: '24325-3',
187
+ display: 'CBC with Differential',
188
+ },
189
+ ],
190
+ },
191
+ subject: { reference: `Patient/${patient.id}` },
192
+ performer: [{ reference: `Practitioner/${practitioner.id}` }],
193
+ category: [
194
+ {
195
+ coding: [
196
+ {
197
+ system: 'http://terminology.hl7.org/CodeSystem/v2-0074',
198
+ code: 'LAB',
199
+ display: 'Laboratory',
200
+ },
201
+ ],
202
+ text: 'Laboratory',
203
+ },
204
+ {
205
+ text: 'Hematology',
206
+ },
207
+ ],
208
+ conclusion: 'All values within normal limits',
209
+ });
210
+
211
+ setup(diagnosticReport);
212
+
213
+ await waitFor(() => {
214
+ expect(screen.getByText('Performed by:')).toBeInTheDocument();
215
+ });
216
+
217
+ expect(screen.getByText('Test Code:')).toBeInTheDocument();
218
+ expect(screen.getByText('24323-8')).toBeInTheDocument();
219
+ expect(screen.getAllByText('Complete Blood Count').length).toBeGreaterThan(0);
220
+ expect(screen.getByText('24325-3')).toBeInTheDocument();
221
+ expect(screen.getByText('CBC with Differential')).toBeInTheDocument();
222
+ expect(screen.getByText('Dr. Jane Smith')).toBeInTheDocument();
223
+ expect(screen.getByText('Patient:')).toBeInTheDocument();
224
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
225
+ expect(screen.getByText('Category:')).toBeInTheDocument();
226
+ expect(screen.getByText('Laboratory')).toBeInTheDocument();
227
+ expect(screen.getByText('Hematology')).toBeInTheDocument();
228
+ expect(screen.getByText('CONCLUSION')).toBeInTheDocument();
229
+ expect(screen.getByText('All values within normal limits')).toBeInTheDocument();
230
+ });
231
+
232
+ test('Does not display conclusion section when absent', () => {
233
+ const diagnosticReport = createMockDiagnosticReport({
234
+ conclusion: undefined,
235
+ });
236
+
237
+ setup(diagnosticReport);
238
+
239
+ expect(screen.queryByText('CONCLUSION')).not.toBeInTheDocument();
240
+ });
241
+
242
+ test('Displays conclusion codes when present', () => {
243
+ const diagnosticReport = createMockDiagnosticReport({
244
+ conclusionCode: [
245
+ {
246
+ coding: [
247
+ {
248
+ system: 'http://snomed.info/sct',
249
+ code: '123456789',
250
+ display: 'Normal',
251
+ },
252
+ ],
253
+ text: 'Normal',
254
+ },
255
+ ],
256
+ });
257
+
258
+ setup(diagnosticReport);
259
+
260
+ expect(screen.getByText('CONCLUSION CODES')).toBeInTheDocument();
261
+ expect(screen.getByText('Code 1:')).toBeInTheDocument();
262
+ expect(screen.getByText('Normal')).toBeInTheDocument();
263
+ });
264
+
265
+ test('Displays multiple conclusion codes', () => {
266
+ const diagnosticReport = createMockDiagnosticReport({
267
+ conclusionCode: [
268
+ {
269
+ text: 'Normal',
270
+ },
271
+ {
272
+ text: 'Abnormal',
273
+ },
274
+ ],
275
+ });
276
+
277
+ setup(diagnosticReport);
278
+
279
+ expect(screen.getByText('Code 1:')).toBeInTheDocument();
280
+ expect(screen.getByText('Code 2:')).toBeInTheDocument();
281
+ expect(screen.getByText('Normal')).toBeInTheDocument();
282
+ expect(screen.getByText('Abnormal')).toBeInTheDocument();
283
+ });
284
+
285
+ test('Displays attachments when present', () => {
286
+ const diagnosticReport = createMockDiagnosticReport({
287
+ presentedForm: [
288
+ {
289
+ contentType: 'application/pdf',
290
+ title: 'Lab Report PDF',
291
+ },
292
+ ],
293
+ });
294
+
295
+ setup(diagnosticReport);
296
+
297
+ expect(screen.getByText('ATTACHMENTS')).toBeInTheDocument();
298
+ expect(screen.getByText('Attachment 1:')).toBeInTheDocument();
299
+ expect(screen.getByText('Lab Report PDF')).toBeInTheDocument();
300
+ });
301
+
302
+ test('Displays attachment with contentType when title is missing', () => {
303
+ const diagnosticReport = createMockDiagnosticReport({
304
+ presentedForm: [
305
+ {
306
+ contentType: 'application/pdf',
307
+ },
308
+ ],
309
+ });
310
+
311
+ setup(diagnosticReport);
312
+
313
+ expect(screen.getByText('application/pdf')).toBeInTheDocument();
314
+ });
315
+
316
+ test('Displays attachment with default text when title and contentType are missing', () => {
317
+ const diagnosticReport = createMockDiagnosticReport({
318
+ presentedForm: [{}],
319
+ });
320
+
321
+ setup(diagnosticReport);
322
+
323
+ expect(screen.getByText('Attachment')).toBeInTheDocument();
324
+ });
325
+
326
+ test('Displays multiple attachments', () => {
327
+ const diagnosticReport = createMockDiagnosticReport({
328
+ presentedForm: [
329
+ {
330
+ title: 'Report 1',
331
+ },
332
+ {
333
+ title: 'Report 2',
334
+ },
335
+ ],
336
+ });
337
+
338
+ setup(diagnosticReport);
339
+
340
+ expect(screen.getByText('Attachment 1:')).toBeInTheDocument();
341
+ expect(screen.getByText('Attachment 2:')).toBeInTheDocument();
342
+ expect(screen.getByText('Report 1')).toBeInTheDocument();
343
+ expect(screen.getByText('Report 2')).toBeInTheDocument();
344
+ });
345
+
346
+ test('Does not display test results section when result array is empty', () => {
347
+ const diagnosticReport = createMockDiagnosticReport({
348
+ result: [],
349
+ });
350
+
351
+ setup(diagnosticReport);
352
+
353
+ expect(screen.queryByText('TEST RESULTS')).not.toBeInTheDocument();
354
+ });
355
+
356
+ test('Does not display test results section when result is undefined', () => {
357
+ const diagnosticReport = createMockDiagnosticReport({
358
+ result: undefined,
359
+ });
360
+
361
+ setup(diagnosticReport);
362
+
363
+ expect(screen.queryByText('TEST RESULTS')).not.toBeInTheDocument();
364
+ });
365
+
366
+ test('Handles undefined diagnostic report gracefully', async () => {
367
+ const reference: Reference<DiagnosticReport> = {
368
+ reference: 'DiagnosticReport/non-existent-id',
369
+ };
370
+
371
+ setup(reference);
372
+
373
+ await waitFor(() => {
374
+ expect(screen.getByText('Lab Result')).toBeInTheDocument();
375
+ });
376
+ expect(screen.getByText('Unknown')).toBeInTheDocument();
377
+ });
378
+
379
+ test('Renders all sections together', async () => {
380
+ const patient = await medplum.createResource(mockPatient);
381
+ const practitioner = await medplum.createResource(mockPractitioner);
382
+ const diagnosticReport = createMockDiagnosticReport({
383
+ subject: { reference: `Patient/${patient.id}` },
384
+ performer: [{ reference: `Practitioner/${practitioner.id}` }],
385
+ effectiveDateTime: '2024-01-16T10:00:00Z',
386
+ conclusion: 'All values normal',
387
+ conclusionCode: [
388
+ {
389
+ text: 'Normal',
390
+ },
391
+ ],
392
+ presentedForm: [
393
+ {
394
+ title: 'Report PDF',
395
+ },
396
+ ],
397
+ result: [{ reference: 'Observation/obs-123' }],
398
+ });
399
+
400
+ setup(diagnosticReport);
401
+
402
+ await waitFor(() => {
403
+ expect(screen.getByText('CBC with Differential')).toBeInTheDocument();
404
+ });
405
+ expect(screen.getByText('Effective Date:')).toBeInTheDocument();
406
+ expect(screen.getByText('Patient:')).toBeInTheDocument();
407
+ expect(screen.getByText('Performed by:')).toBeInTheDocument();
408
+ expect(screen.getByText('CONCLUSION')).toBeInTheDocument();
409
+ expect(screen.getByText('CONCLUSION CODES')).toBeInTheDocument();
410
+ expect(screen.getByText('ATTACHMENTS')).toBeInTheDocument();
411
+ expect(screen.getByText('TEST RESULTS')).toBeInTheDocument();
412
+ });
413
+ });
@@ -0,0 +1,203 @@
1
+ // SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { Paper, Stack, Text, Group, Badge, Divider } from '@mantine/core';
4
+ import { formatDate, formatHumanName } from '@medplum/core';
5
+ import type { DiagnosticReport, HumanName, Reference } from '@medplum/fhirtypes';
6
+ import type { JSX } from 'react';
7
+ import { useResource, ObservationTable } from '@medplum/react';
8
+
9
+ interface LabResultDetailsProps {
10
+ result: DiagnosticReport | Reference<DiagnosticReport>;
11
+ onResultChange?: (result: DiagnosticReport) => void;
12
+ }
13
+
14
+ export function LabResultDetails({ result, onResultChange: _onResultChange }: LabResultDetailsProps): JSX.Element {
15
+ const diagnosticReport = useResource(result);
16
+ const patient = useResource(diagnosticReport?.subject);
17
+ const performer = useResource(diagnosticReport?.performer?.[0]);
18
+
19
+ return (
20
+ <Paper h="100%" p="md" style={{ overflow: 'auto' }}>
21
+ <Stack gap="md">
22
+ <Stack gap="xs">
23
+ <Text size="xl" fw={700}>
24
+ {diagnosticReport?.code?.text || diagnosticReport?.code?.coding?.[0]?.display || 'Lab Result'}
25
+ </Text>
26
+ <Badge size="lg" color={getStatusColor(diagnosticReport?.status)} variant="light">
27
+ {getStatusDisplayText(diagnosticReport?.status)}
28
+ </Badge>
29
+ </Stack>
30
+
31
+ <Divider />
32
+
33
+ <Stack gap="sm">
34
+ <Text fw={600} size="sm" c="dimmed">
35
+ RESULT DETAILS
36
+ </Text>
37
+
38
+ <Group>
39
+ <Text fw={500} size="sm">
40
+ Issued Date:
41
+ </Text>
42
+ <Text size="sm">{formatDate(diagnosticReport?.issued)}</Text>
43
+ </Group>
44
+
45
+ {diagnosticReport?.effectiveDateTime && (
46
+ <Group>
47
+ <Text fw={500} size="sm">
48
+ Effective Date:
49
+ </Text>
50
+ <Text size="sm">{formatDate(diagnosticReport?.effectiveDateTime)}</Text>
51
+ </Group>
52
+ )}
53
+
54
+ {diagnosticReport?.code?.coding && (
55
+ <Group align="flex-start">
56
+ <Text fw={500} size="sm">
57
+ Test Code:
58
+ </Text>
59
+ <Stack gap="xs">
60
+ {diagnosticReport?.code?.coding?.map((coding, index) => (
61
+ <Group key={index} gap="xs">
62
+ <Badge size="sm" variant="outline">
63
+ {coding.code}
64
+ </Badge>
65
+ <Text size="sm">{coding.display}</Text>
66
+ </Group>
67
+ ))}
68
+ </Stack>
69
+ </Group>
70
+ )}
71
+
72
+ {performer?.resourceType === 'Practitioner' && (
73
+ <Group>
74
+ <Text fw={500} size="sm">
75
+ Performed by:
76
+ </Text>
77
+ <Text size="sm">{formatHumanName(performer.name?.[0] as HumanName)}</Text>
78
+ </Group>
79
+ )}
80
+
81
+ {patient?.resourceType === 'Patient' && (
82
+ <Group>
83
+ <Text fw={500} size="sm">
84
+ Patient:
85
+ </Text>
86
+ <Text size="sm">{formatHumanName(patient.name?.[0] as HumanName)}</Text>
87
+ </Group>
88
+ )}
89
+
90
+ {diagnosticReport?.category && (
91
+ <Group align="flex-start">
92
+ <Text fw={500} size="sm">
93
+ Category:
94
+ </Text>
95
+ <Stack gap="xs">
96
+ {diagnosticReport?.category?.map((category, index) => (
97
+ <Text key={index} size="sm">
98
+ {category.text || category.coding?.[0]?.display}
99
+ </Text>
100
+ ))}
101
+ </Stack>
102
+ </Group>
103
+ )}
104
+ </Stack>
105
+
106
+ {diagnosticReport?.conclusion && (
107
+ <>
108
+ <Divider />
109
+ <Stack gap="sm">
110
+ <Text fw={600} size="sm" c="dimmed">
111
+ CONCLUSION
112
+ </Text>
113
+ <Text size="sm">{diagnosticReport?.conclusion}</Text>
114
+ </Stack>
115
+ </>
116
+ )}
117
+
118
+ {diagnosticReport?.conclusionCode && (
119
+ <>
120
+ <Divider />
121
+ <Stack gap="sm">
122
+ <Text fw={600} size="sm" c="dimmed">
123
+ CONCLUSION CODES
124
+ </Text>
125
+ {diagnosticReport?.conclusionCode?.map((code, index) => (
126
+ <Group key={index} align="flex-start">
127
+ <Text fw={500} size="sm">
128
+ Code {index + 1}:
129
+ </Text>
130
+ <Text size="sm">{code.text || code.coding?.[0]?.display}</Text>
131
+ </Group>
132
+ ))}
133
+ </Stack>
134
+ </>
135
+ )}
136
+
137
+ {diagnosticReport?.presentedForm && (
138
+ <>
139
+ <Divider />
140
+ <Stack gap="sm">
141
+ <Text fw={600} size="sm" c="dimmed">
142
+ ATTACHMENTS
143
+ </Text>
144
+ {diagnosticReport?.presentedForm?.map((form, index) => (
145
+ <Group key={index} align="flex-start">
146
+ <Text fw={500} size="sm">
147
+ Attachment {index + 1}:
148
+ </Text>
149
+ <Text size="sm">{form.title || form.contentType || 'Attachment'}</Text>
150
+ </Group>
151
+ ))}
152
+ </Stack>
153
+ </>
154
+ )}
155
+
156
+ {diagnosticReport?.result && diagnosticReport?.result?.length > 0 && (
157
+ <>
158
+ <Divider />
159
+ <Stack gap="sm">
160
+ <Text fw={600} size="sm" c="dimmed">
161
+ TEST RESULTS
162
+ </Text>
163
+ <ObservationTable value={diagnosticReport?.result} hideObservationNotes={false} />
164
+ </Stack>
165
+ </>
166
+ )}
167
+ </Stack>
168
+ </Paper>
169
+ );
170
+ }
171
+
172
+ const getStatusColor = (status: string | undefined): string => {
173
+ switch (status) {
174
+ case 'final':
175
+ return 'green';
176
+ case 'partial':
177
+ return 'yellow';
178
+ case 'preliminary':
179
+ return 'blue';
180
+ case 'cancelled':
181
+ case 'entered-in-error':
182
+ return 'red';
183
+ default:
184
+ return 'gray';
185
+ }
186
+ };
187
+
188
+ const getStatusDisplayText = (status: string | undefined): string => {
189
+ switch (status) {
190
+ case 'final':
191
+ return 'Final';
192
+ case 'partial':
193
+ return 'Partial';
194
+ case 'preliminary':
195
+ return 'Preliminary';
196
+ case 'cancelled':
197
+ return 'Cancelled';
198
+ case 'entered-in-error':
199
+ return 'Error';
200
+ default:
201
+ return status || 'Unknown';
202
+ }
203
+ };
@@ -0,0 +1,22 @@
1
+ // SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { Flex, Stack, Text } from '@mantine/core';
4
+ import type { JSX } from 'react';
5
+
6
+ type LabTab = 'open' | 'completed';
7
+
8
+ interface LabSelectEmptyProps {
9
+ activeTab: LabTab;
10
+ }
11
+
12
+ export function LabSelectEmpty({ activeTab: _activeTab }: LabSelectEmptyProps): JSX.Element {
13
+ return (
14
+ <Flex direction="column" h="100%" justify="center" align="center">
15
+ <Stack align="center" gap="md" pt="xl">
16
+ <Text size="md" c="dimmed" fw={400}>
17
+ Lab details will appear here when selected.
18
+ </Text>
19
+ </Stack>
20
+ </Flex>
21
+ );
22
+ }