@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.
- package/README.md +3 -0
- package/dist/108.js +1 -0
- package/dist/108.js.map +1 -0
- package/dist/1339.js +1 -0
- package/dist/1339.js.map +1 -0
- package/dist/1480.js +1 -0
- package/dist/1480.js.map +1 -0
- package/dist/1543.js +1 -0
- package/dist/1543.js.map +1 -0
- package/dist/1582.js +1 -0
- package/dist/1582.js.map +1 -0
- package/dist/1646.js +1 -0
- package/dist/1646.js.map +1 -0
- package/dist/1797.js +1 -0
- package/dist/1797.js.map +1 -0
- package/dist/1869.js +1 -0
- package/dist/1869.js.map +1 -0
- package/dist/1877.js +1 -0
- package/dist/1877.js.map +1 -0
- package/dist/2020.js +1 -0
- package/dist/2020.js.map +1 -0
- package/dist/2246.js +1 -0
- package/dist/2246.js.map +1 -0
- package/dist/2317.js +1 -0
- package/dist/2317.js.map +1 -0
- package/dist/2416.js +1 -0
- package/dist/2416.js.map +1 -0
- package/dist/2790.js +1 -0
- package/dist/2790.js.map +1 -0
- package/dist/282.js +1 -0
- package/dist/282.js.map +1 -0
- package/dist/2881.js +1 -0
- package/dist/2881.js.map +1 -0
- package/dist/3137.js +1 -0
- package/dist/3137.js.map +1 -0
- package/dist/3378.js +1 -0
- package/dist/3378.js.map +1 -0
- package/dist/3390.js +1 -0
- package/dist/3390.js.map +1 -0
- package/dist/3536.js +1 -0
- package/dist/3536.js.map +1 -0
- package/dist/3720.js +1 -0
- package/dist/3720.js.map +1 -0
- package/dist/3857.js +1 -0
- package/dist/3857.js.map +1 -0
- package/dist/3925.js +1 -0
- package/dist/3925.js.map +1 -0
- package/dist/3963.js +1 -0
- package/dist/3963.js.map +1 -0
- package/dist/3989.js +1 -0
- package/dist/3989.js.map +1 -0
- package/dist/4092.js +1 -0
- package/dist/4092.js.map +1 -0
- package/dist/4106.js +1 -0
- package/dist/4106.js.map +1 -0
- package/dist/4111.js +1 -0
- package/dist/4111.js.map +1 -0
- package/dist/4145.js +1 -0
- package/dist/4145.js.map +1 -0
- package/dist/434.js +1 -0
- package/dist/434.js.map +1 -0
- package/dist/4348.js +1 -0
- package/dist/4348.js.map +1 -0
- package/dist/4383.js +1 -0
- package/dist/4383.js.map +1 -0
- package/dist/4540.js +1 -0
- package/dist/4540.js.map +1 -0
- package/dist/4658.js +1 -0
- package/dist/4658.js.map +1 -0
- package/dist/466.js +1 -0
- package/dist/466.js.map +1 -0
- package/dist/4913.js +1 -0
- package/dist/4913.js.map +1 -0
- package/dist/4928.js +1 -0
- package/dist/4928.js.map +1 -0
- package/dist/5069.js +1 -0
- package/dist/5069.js.map +1 -0
- package/dist/5117.js +1 -0
- package/dist/5117.js.map +1 -0
- package/dist/5132.js +1 -0
- package/dist/5132.js.map +1 -0
- package/dist/5145.js +1 -0
- package/dist/5145.js.map +1 -0
- package/dist/52.js +1 -0
- package/dist/52.js.map +1 -0
- package/dist/5422.js +1 -0
- package/dist/5422.js.map +1 -0
- package/dist/5503.js +1 -0
- package/dist/5503.js.map +1 -0
- package/dist/5549.js +1 -0
- package/dist/5549.js.map +1 -0
- package/dist/556.js +1 -0
- package/dist/556.js.map +1 -0
- package/dist/5644.js +1 -0
- package/dist/5644.js.map +1 -0
- package/dist/5697.js +1 -0
- package/dist/5697.js.map +1 -0
- package/dist/5793.js +1 -0
- package/dist/5793.js.map +1 -0
- package/dist/5940.js +1 -0
- package/dist/5940.js.map +1 -0
- package/dist/5952.js +1 -0
- package/dist/5952.js.map +1 -0
- package/dist/6047.js +1 -0
- package/dist/6047.js.map +1 -0
- package/dist/6371.js +1 -0
- package/dist/6371.js.map +1 -0
- package/dist/6377.js +1 -0
- package/dist/6377.js.map +1 -0
- package/dist/6444.js +1 -0
- package/dist/6444.js.map +1 -0
- package/dist/6479.js +1 -0
- package/dist/6479.js.map +1 -0
- package/dist/6508.js +1 -0
- package/dist/6508.js.map +1 -0
- package/dist/6724.js +1 -0
- package/dist/6724.js.map +1 -0
- package/dist/6759.js +27 -0
- package/dist/6759.js.map +1 -0
- package/dist/689.js +1 -0
- package/dist/689.js.map +1 -0
- package/dist/6904.js +1 -0
- package/dist/6904.js.map +1 -0
- package/dist/7045.js +1 -0
- package/dist/7045.js.map +1 -0
- package/dist/7175.js +1 -0
- package/dist/7175.js.map +1 -0
- package/dist/7182.js +1 -0
- package/dist/7182.js.map +1 -0
- package/dist/7302.js +1 -0
- package/dist/7302.js.map +1 -0
- package/dist/7646.js +17 -0
- package/dist/7646.js.map +1 -0
- package/dist/7742.js +1 -0
- package/dist/7742.js.map +1 -0
- package/dist/7912.js +1 -0
- package/dist/7912.js.map +1 -0
- package/dist/8105.js +21 -0
- package/dist/8105.js.map +1 -0
- package/dist/8202.js +1 -0
- package/dist/8202.js.map +1 -0
- package/dist/8349.js +1 -0
- package/dist/8349.js.map +1 -0
- package/dist/8358.js +1 -0
- package/dist/8358.js.map +1 -0
- package/dist/8359.js +1 -0
- package/dist/8359.js.map +1 -0
- package/dist/8695.js +1 -0
- package/dist/8695.js.map +1 -0
- package/dist/8702.js +1 -0
- package/dist/8702.js.map +1 -0
- package/dist/8894.js +1 -0
- package/dist/8894.js.map +1 -0
- package/dist/8958.js +1 -0
- package/dist/8958.js.map +1 -0
- package/dist/903.js +1 -0
- package/dist/903.js.map +1 -0
- package/dist/9061.js +1 -0
- package/dist/9061.js.map +1 -0
- package/dist/9072.js +1 -0
- package/dist/9072.js.map +1 -0
- package/dist/9105.js +1 -0
- package/dist/9105.js.map +1 -0
- package/dist/9107.js +1 -0
- package/dist/9107.js.map +1 -0
- package/dist/9456.js +1 -0
- package/dist/9456.js.map +1 -0
- package/dist/9586.js +1 -0
- package/dist/9586.js.map +1 -0
- package/dist/9712.js +1 -0
- package/dist/9712.js.map +1 -0
- package/dist/9771.js +1 -0
- package/dist/9771.js.map +1 -0
- package/dist/9806.js +1 -0
- package/dist/9806.js.map +1 -0
- package/dist/9873.js +1 -0
- package/dist/9873.js.map +1 -0
- package/dist/9927.js +1 -0
- package/dist/9927.js.map +1 -0
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -0
- package/dist/openmrs-esm-patient-chart-app.js +6 -0
- package/dist/openmrs-esm-patient-chart-app.js.buildmanifest.json +2386 -0
- package/dist/openmrs-esm-patient-chart-app.js.map +1 -0
- package/dist/routes.json +1 -0
- package/package.json +63 -0
- package/rspack.config.js +1 -0
- package/src/actions-buttons/action-button.scss +3 -0
- package/src/actions-buttons/delete-visit.component.tsx +41 -0
- package/src/actions-buttons/delete-visit.test.tsx +26 -0
- package/src/actions-buttons/mark-patient-alive.component.tsx +42 -0
- package/src/actions-buttons/mark-patient-deceased.component.tsx +35 -0
- package/src/actions-buttons/start-visit.component.tsx +41 -0
- package/src/actions-buttons/start-visit.test.tsx +44 -0
- package/src/actions-buttons/stop-visit.component.tsx +39 -0
- package/src/actions-buttons/stop-visit.test.tsx +27 -0
- package/src/clinical-views/encounter-list/encounter-list-tabs.extension.tsx +78 -0
- package/src/clinical-views/encounter-list/encounter-list-tabs.scss +7 -0
- package/src/clinical-views/encounter-list/encounter-list.component.tsx +306 -0
- package/src/clinical-views/encounter-list/encounter-list.scss +36 -0
- package/src/clinical-views/encounter-list/table.component.tsx +63 -0
- package/src/clinical-views/encounter-list/table.scss +11 -0
- package/src/clinical-views/encounter-list/tag.component.test.tsx +307 -0
- package/src/clinical-views/encounter-list/tag.component.tsx +43 -0
- package/src/clinical-views/encounter-tile/clinical-views-summary.component.tsx +40 -0
- package/src/clinical-views/encounter-tile/encounter-tile.component.tsx +94 -0
- package/src/clinical-views/encounter-tile/tile.scss +82 -0
- package/src/clinical-views/hooks/index.ts +3 -0
- package/src/clinical-views/hooks/useEncounterRows.ts +60 -0
- package/src/clinical-views/hooks/useEncountersByVisit.ts +13 -0
- package/src/clinical-views/hooks/useFormsJson.ts +15 -0
- package/src/clinical-views/hooks/useLastEncounter.ts +29 -0
- package/src/clinical-views/types.ts +305 -0
- package/src/clinical-views/utils/concept-utils.ts +24 -0
- package/src/clinical-views/utils/encounter-list-config-builder.ts +160 -0
- package/src/clinical-views/utils/encounter-list.resource.ts +26 -0
- package/src/clinical-views/utils/helpers.ts +226 -0
- package/src/clinical-views/utils/index.ts +90 -0
- package/src/config-schema.ts +235 -0
- package/src/constants.ts +11 -0
- package/src/dashboard.meta.ts +15 -0
- package/src/data.resource.ts +117 -0
- package/src/declarations.d.ts +4 -0
- package/src/index.ts +204 -0
- package/src/loader/loader.component.tsx +11 -0
- package/src/loader/loader.scss +9 -0
- package/src/mark-patient-alive/mark-patient-alive.modal.tsx +54 -0
- package/src/mark-patient-deceased/mark-patient-deceased-form.scss +175 -0
- package/src/mark-patient-deceased/mark-patient-deceased-form.test.tsx +203 -0
- package/src/mark-patient-deceased/mark-patient-deceased-form.workspace.tsx +295 -0
- package/src/offline.ts +41 -0
- package/src/patient-banner-tags/visit-attribute-tags.extension.tsx +62 -0
- package/src/patient-banner-tags/visit-attribute-tags.scss +8 -0
- package/src/patient-chart/chart-review/chart-review.component.tsx +138 -0
- package/src/patient-chart/chart-review/chart-review.test.tsx +77 -0
- package/src/patient-chart/chart-review/dashboard-view.component.tsx +85 -0
- package/src/patient-chart/chart-review/dashboard-view.scss +84 -0
- package/src/patient-chart/patient-chart.component.tsx +71 -0
- package/src/patient-chart/patient-chart.resources.test.ts +238 -0
- package/src/patient-chart/patient-chart.resources.ts +231 -0
- package/src/patient-chart/patient-chart.scss +65 -0
- package/src/patient-details-tile/patient-details-tile.component.tsx +25 -0
- package/src/patient-details-tile/patient-details-tile.scss +24 -0
- package/src/root.component.tsx +35 -0
- package/src/root.scss +54 -0
- package/src/routes.json +267 -0
- package/src/side-nav/side-menu.component.tsx +10 -0
- package/src/side-nav/side-menu.scss +38 -0
- package/src/side-nav/side-menu.test.tsx +27 -0
- package/src/utils.test.ts +17 -0
- package/src/utils.ts +5 -0
- package/src/visit/hooks/useDefaultFacilityLocation.tsx +15 -0
- package/src/visit/hooks/useDefaultVisitLocation.tsx +24 -0
- package/src/visit/hooks/useDeleteVisit.test.tsx +267 -0
- package/src/visit/hooks/useDeleteVisit.tsx +103 -0
- package/src/visit/hooks/useOfflineVisitType.tsx +18 -0
- package/src/visit/hooks/useRecommendedVisitTypes.tsx +34 -0
- package/src/visit/hooks/useVisitAttributeType.tsx +102 -0
- package/src/visit/start-visit-button.component.tsx +47 -0
- package/src/visit/start-visit-button.test.tsx +32 -0
- package/src/visit/visit-action-items/delete-visit-action-item.component.tsx +60 -0
- package/src/visit/visit-action-items/delete-visit-action-item.test.tsx +48 -0
- package/src/visit/visit-action-items/edit-visit-details.component.tsx +79 -0
- package/src/visit/visit-form/base-visit-type.component.tsx +121 -0
- package/src/visit/visit-form/base-visit-type.scss +75 -0
- package/src/visit/visit-form/base-visit-type.test.tsx +153 -0
- package/src/visit/visit-form/exported-visit-form.workspace.tsx +755 -0
- package/src/visit/visit-form/location-selector.component.tsx +86 -0
- package/src/visit/visit-form/location-selector.test.tsx +146 -0
- package/src/visit/visit-form/recommended-visit-type.component.tsx +32 -0
- package/src/visit/visit-form/visit-attribute-type.component.tsx +258 -0
- package/src/visit/visit-form/visit-attribute-type.scss +5 -0
- package/src/visit/visit-form/visit-date-time.component.tsx +206 -0
- package/src/visit/visit-form/visit-form.resource.ts +401 -0
- package/src/visit/visit-form/visit-form.scss +167 -0
- package/src/visit/visit-form/visit-form.test.tsx +1233 -0
- package/src/visit/visit-form/visit-form.workspace.tsx +61 -0
- package/src/visit/visit-form/visit-type.test.tsx +88 -0
- package/src/visit/visit-history-table/visit-actions-cell.component.tsx +20 -0
- package/src/visit/visit-history-table/visit-actions-cell.scss +4 -0
- package/src/visit/visit-history-table/visit-date-cell.component.tsx +19 -0
- package/src/visit/visit-history-table/visit-diagnoses-cell.component.tsx +18 -0
- package/src/visit/visit-history-table/visit-history-table.component.tsx +145 -0
- package/src/visit/visit-history-table/visit-history-table.scss +25 -0
- package/src/visit/visit-history-table/visit-type-cell.component.tsx +15 -0
- package/src/visit/visit-prompt/delete-visit-dialog.modal.tsx +46 -0
- package/src/visit/visit-prompt/delete-visit-dialog.test.tsx +79 -0
- package/src/visit/visit-prompt/end-visit-dialog.modal.tsx +82 -0
- package/src/visit/visit-prompt/end-visit-dialog.scss +7 -0
- package/src/visit/visit-prompt/end-visit-dialog.test.tsx +131 -0
- package/src/visit/visit-prompt/modify-visit-date.modal.tsx +40 -0
- package/src/visit/visit-prompt/start-visit-dialog.modal.tsx +64 -0
- package/src/visit/visit-prompt/start-visit-dialog.scss +10 -0
- package/src/visit/visit-prompt/start-visit-dialog.test.tsx +40 -0
- package/src/visit/visits-widget/active-visit-buttons/active-visit-buttons.scss +7 -0
- package/src/visit/visits-widget/active-visit-buttons/active-visit-buttons.tsx +178 -0
- package/src/visit/visits-widget/current-visit-summary.extension.tsx +48 -0
- package/src/visit/visits-widget/current-visit-summary.scss +10 -0
- package/src/visit/visits-widget/current-visit-summary.test.tsx +85 -0
- package/src/visit/visits-widget/encounter-observations/encounter-observations.component.tsx +67 -0
- package/src/visit/visits-widget/encounter-observations/index.ts +3 -0
- package/src/visit/visits-widget/encounter-observations/styles.scss +22 -0
- package/src/visit/visits-widget/past-visits-components/delete-encounter.modal.tsx +47 -0
- package/src/visit/visits-widget/past-visits-components/delete-encounter.scss +9 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/all-encounters-table.component.tsx +49 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/completed-forms-table.component.tsx +67 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/completed-forms-table.test.tsx +146 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.component.tsx +452 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.resource.test.ts +156 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.resource.ts +215 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.scss +113 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.test.tsx +432 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/visit-completed-forms-table.component.tsx +61 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/visit-completed-forms-table.test.tsx +125 -0
- package/src/visit/visits-widget/past-visits-components/encounters-table/visit-encounters-table.component.tsx +47 -0
- package/src/visit/visits-widget/past-visits-components/medications-summary.component.tsx +163 -0
- package/src/visit/visits-widget/past-visits-components/notes-summary.component.tsx +66 -0
- package/src/visit/visits-widget/past-visits-components/patient-notes-summary.component.tsx +318 -0
- package/src/visit/visits-widget/past-visits-components/tests-summary.component.tsx +16 -0
- package/src/visit/visits-widget/past-visits-components/visit-summary.component.tsx +192 -0
- package/src/visit/visits-widget/past-visits-components/visit-summary.scss +72 -0
- package/src/visit/visits-widget/past-visits-components/visit-summary.test.tsx +105 -0
- package/src/visit/visits-widget/single-visit-details/visit-timeline/visit-timeline.component.tsx +94 -0
- package/src/visit/visits-widget/single-visit-details/visit-timeline/visit-timeline.scss +60 -0
- package/src/visit/visits-widget/visit-context/retrospective-data-date-time-picker/restrospective-date-time-picker.scss +35 -0
- package/src/visit/visits-widget/visit-context/retrospective-data-date-time-picker/retrospective-date-time-picker.component.tsx +140 -0
- package/src/visit/visits-widget/visit-context/visit-context-header.extension.tsx +61 -0
- package/src/visit/visits-widget/visit-context/visit-context-header.scss +45 -0
- package/src/visit/visits-widget/visit-context/visit-context-header.test.tsx +59 -0
- package/src/visit/visits-widget/visit-context/visit-context-info.component.tsx +37 -0
- package/src/visit/visits-widget/visit-context/visit-context-info.scss +12 -0
- package/src/visit/visits-widget/visit-context/visit-context-switcher.modal.tsx +166 -0
- package/src/visit/visits-widget/visit-context/visit-context-switcher.scss +83 -0
- package/src/visit/visits-widget/visit-context/visit-context-switcher.test.tsx +79 -0
- package/src/visit/visits-widget/visit-detail-overview.component.tsx +67 -0
- package/src/visit/visits-widget/visit-detail-overview.scss +301 -0
- package/src/visit/visits-widget/visit-detail-overview.test.tsx +205 -0
- package/src/visit/visits-widget/visit.resource.tsx +146 -0
- package/translations/am.json +209 -0
- package/translations/ar.json +209 -0
- package/translations/ar_SY.json +209 -0
- package/translations/bn.json +209 -0
- package/translations/cs.json +209 -0
- package/translations/de.json +209 -0
- package/translations/en.json +209 -0
- package/translations/en_US.json +209 -0
- package/translations/es.json +209 -0
- package/translations/es_MX.json +209 -0
- package/translations/fr.json +209 -0
- package/translations/he.json +209 -0
- package/translations/hi.json +209 -0
- package/translations/hi_IN.json +209 -0
- package/translations/id.json +209 -0
- package/translations/it.json +209 -0
- package/translations/ka.json +209 -0
- package/translations/km.json +209 -0
- package/translations/ku.json +209 -0
- package/translations/ky.json +209 -0
- package/translations/lg.json +209 -0
- package/translations/ne.json +209 -0
- package/translations/pl.json +209 -0
- package/translations/pt.json +209 -0
- package/translations/pt_BR.json +209 -0
- package/translations/qu.json +209 -0
- package/translations/ro_RO.json +209 -0
- package/translations/ru_RU.json +209 -0
- package/translations/si.json +209 -0
- package/translations/sq.json +209 -0
- package/translations/sw.json +209 -0
- package/translations/sw_KE.json +209 -0
- package/translations/tr.json +209 -0
- package/translations/tr_TR.json +209 -0
- package/translations/uk.json +209 -0
- package/translations/uz.json +209 -0
- package/translations/uz@Latn.json +209 -0
- package/translations/uz_UZ.json +209 -0
- package/translations/vi.json +209 -0
- package/translations/zh.json +209 -0
- package/translations/zh_CN.json +209 -0
- package/translations/zh_TW.json +209 -0
- package/tsconfig.json +4 -0
- package/vitest.config.ts +4 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*
|
|
4
|
+
* happy-dom's `Date` and `AbortController` instances do not satisfy
|
|
5
|
+
* `instanceof` against the host realm's constructors, which breaks
|
|
6
|
+
* `expect.any(Date)` and `toHaveBeenCalledWith(new AbortController(), ...)`
|
|
7
|
+
* matchers used here. Run under jsdom (which shares the host realm's globals).
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import { vi, describe, expect, test, beforeEach } from 'vitest';
|
|
11
|
+
import userEvent from '@testing-library/user-event';
|
|
12
|
+
import { screen, render } from '@testing-library/react';
|
|
13
|
+
import { showSnackbar, updateVisit, useVisit, type Visit, type FetchResponse } from '@openmrs/esm-framework';
|
|
14
|
+
import { mockCurrentVisit } from '__mocks__';
|
|
15
|
+
import EndVisitDialog from './end-visit-dialog.modal';
|
|
16
|
+
import { usePatientChartStore } from '@openmrs/esm-patient-common-lib';
|
|
17
|
+
|
|
18
|
+
const endVisitPayload = {
|
|
19
|
+
stopDatetime: expect.any(Date),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const mockCloseModal = vi.fn();
|
|
23
|
+
const mockMutate = vi.fn();
|
|
24
|
+
const mockShowSnackbar = vi.mocked(showSnackbar);
|
|
25
|
+
const mockUseVisit = vi.mocked(useVisit);
|
|
26
|
+
const mockUpdateVisit = vi.mocked(updateVisit);
|
|
27
|
+
|
|
28
|
+
const mockUsePatientChartStore = vi.mocked(usePatientChartStore);
|
|
29
|
+
const mockSetVisitContext = vi.fn();
|
|
30
|
+
|
|
31
|
+
vi.mock('@openmrs/esm-patient-common-lib', () => ({
|
|
32
|
+
usePatientChartStore: vi.fn(),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
mockUsePatientChartStore.mockReturnValue({
|
|
36
|
+
patientUuid: 'patient-123',
|
|
37
|
+
patient: null,
|
|
38
|
+
visitContext: mockCurrentVisit,
|
|
39
|
+
mutateVisitContext: vi.fn(),
|
|
40
|
+
setPatient: vi.fn(),
|
|
41
|
+
setVisitContext: mockSetVisitContext,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('End visit dialog', () => {
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
mockUseVisit.mockReturnValue({
|
|
47
|
+
activeVisit: mockCurrentVisit,
|
|
48
|
+
currentVisit: mockCurrentVisit,
|
|
49
|
+
currentVisitIsRetrospective: false,
|
|
50
|
+
error: null,
|
|
51
|
+
isLoading: false,
|
|
52
|
+
isValidating: false,
|
|
53
|
+
mutate: mockMutate,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('displays a success snackbar when the visit is ended successfully', async () => {
|
|
58
|
+
const user = userEvent.setup();
|
|
59
|
+
|
|
60
|
+
mockUpdateVisit.mockResolvedValue({
|
|
61
|
+
status: 200,
|
|
62
|
+
data: {
|
|
63
|
+
visitType: {
|
|
64
|
+
display: 'Facility Visit',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
} as unknown as FetchResponse<Visit>);
|
|
68
|
+
|
|
69
|
+
render(<EndVisitDialog patientUuid="some-patient-uuid" closeModal={mockCloseModal} />);
|
|
70
|
+
|
|
71
|
+
const closeModalButton = screen.getByRole('button', { name: /close/i });
|
|
72
|
+
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
|
73
|
+
const endVisitButton = screen.getByRole('button', { name: /end visit/i });
|
|
74
|
+
|
|
75
|
+
expect(closeModalButton).toBeInTheDocument();
|
|
76
|
+
expect(cancelButton).toBeInTheDocument();
|
|
77
|
+
expect(endVisitButton).toBeInTheDocument();
|
|
78
|
+
expect(
|
|
79
|
+
screen.getByRole('heading', { name: /are you sure you want to end this active visit?/i }),
|
|
80
|
+
).toBeInTheDocument();
|
|
81
|
+
expect(
|
|
82
|
+
screen.getByText(/You can add additional encounters to this visit in the visit summary/i),
|
|
83
|
+
).toBeInTheDocument();
|
|
84
|
+
|
|
85
|
+
await user.click(endVisitButton);
|
|
86
|
+
|
|
87
|
+
expect(updateVisit).toHaveBeenCalledWith(mockCurrentVisit.uuid, endVisitPayload, expect.anything());
|
|
88
|
+
|
|
89
|
+
expect(mockShowSnackbar).toHaveBeenCalledWith({
|
|
90
|
+
isLowContrast: true,
|
|
91
|
+
subtitle: 'Facility Visit ended successfully',
|
|
92
|
+
kind: 'success',
|
|
93
|
+
title: 'Visit ended',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(mockSetVisitContext).toHaveBeenCalledTimes(1);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('displays an error snackbar if there was a problem ending a visit', async () => {
|
|
100
|
+
const user = userEvent.setup();
|
|
101
|
+
|
|
102
|
+
const error = {
|
|
103
|
+
message: 'Internal error message',
|
|
104
|
+
response: {
|
|
105
|
+
status: 500,
|
|
106
|
+
statusText: 'Internal server error',
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
mockUpdateVisit.mockRejectedValue(error);
|
|
111
|
+
|
|
112
|
+
render(<EndVisitDialog patientUuid="some-patient-uuid" closeModal={mockCloseModal} />);
|
|
113
|
+
|
|
114
|
+
expect(
|
|
115
|
+
screen.getByText(/You can add additional encounters to this visit in the visit summary/i),
|
|
116
|
+
).toBeInTheDocument();
|
|
117
|
+
|
|
118
|
+
const endVisitButton = screen.getByRole('button', { name: /End Visit/i });
|
|
119
|
+
expect(endVisitButton).toBeInTheDocument();
|
|
120
|
+
|
|
121
|
+
await user.click(endVisitButton);
|
|
122
|
+
|
|
123
|
+
expect(updateVisit).toHaveBeenCalledWith(mockCurrentVisit.uuid, endVisitPayload, new AbortController());
|
|
124
|
+
expect(mockShowSnackbar).toHaveBeenCalledWith({
|
|
125
|
+
subtitle: 'Internal error message',
|
|
126
|
+
kind: 'error',
|
|
127
|
+
title: 'Error ending visit',
|
|
128
|
+
isLowContrast: false,
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button, ModalHeader, ModalBody, ModalFooter } from '@carbon/react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import styles from './start-visit-dialog.scss';
|
|
5
|
+
|
|
6
|
+
interface ModifyVisitDateConfirmationModalProps {
|
|
7
|
+
onDiscard: () => void;
|
|
8
|
+
onConfirmation: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const ModifyVisitDateConfirmationModal: React.FC<ModifyVisitDateConfirmationModalProps> = ({
|
|
12
|
+
onDiscard,
|
|
13
|
+
onConfirmation,
|
|
14
|
+
}) => {
|
|
15
|
+
const { t } = useTranslation();
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div>
|
|
19
|
+
<ModalHeader closeModal={onDiscard} title={t('modifyVisitDate', 'Modify visit date')} />
|
|
20
|
+
<ModalBody>
|
|
21
|
+
<p className={styles.body}>
|
|
22
|
+
{t(
|
|
23
|
+
'confirmModifyingVisitDateToAccomodateEncounter',
|
|
24
|
+
'The encounter date falls outside the designated visit date range. Would you like to modify the visit date to accommodate the new encounter date?',
|
|
25
|
+
)}
|
|
26
|
+
</p>
|
|
27
|
+
</ModalBody>
|
|
28
|
+
<ModalFooter>
|
|
29
|
+
<Button kind="secondary" onClick={onDiscard}>
|
|
30
|
+
{t('cancel', 'Cancel')}
|
|
31
|
+
</Button>
|
|
32
|
+
<Button kind="danger" onClick={onConfirmation}>
|
|
33
|
+
{t('confirm', 'Confirm')}
|
|
34
|
+
</Button>
|
|
35
|
+
</ModalFooter>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default ModifyVisitDateConfirmationModal;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
|
|
4
|
+
import { launchWorkspace2 } from '@openmrs/esm-framework';
|
|
5
|
+
import { launchPatientChartWithWorkspaceOpen } from '@openmrs/esm-patient-common-lib';
|
|
6
|
+
import styles from './start-visit-dialog.scss';
|
|
7
|
+
|
|
8
|
+
interface StartVisitDialogProps {
|
|
9
|
+
patientUuid: string;
|
|
10
|
+
closeModal: () => void;
|
|
11
|
+
launchPatientChart?: boolean;
|
|
12
|
+
onVisitStarted?: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const StartVisitDialog: React.FC<StartVisitDialogProps> = ({
|
|
16
|
+
patientUuid,
|
|
17
|
+
closeModal,
|
|
18
|
+
launchPatientChart,
|
|
19
|
+
onVisitStarted,
|
|
20
|
+
}) => {
|
|
21
|
+
const { t } = useTranslation();
|
|
22
|
+
|
|
23
|
+
const handleStartNewVisit = useCallback(() => {
|
|
24
|
+
if (launchPatientChart) {
|
|
25
|
+
launchPatientChartWithWorkspaceOpen({
|
|
26
|
+
patientUuid,
|
|
27
|
+
workspaceName: 'start-visit-workspace-form',
|
|
28
|
+
additionalProps: { openedFrom: 'patient-chart-start-visit' },
|
|
29
|
+
});
|
|
30
|
+
} else {
|
|
31
|
+
launchWorkspace2('start-visit-workspace-form', { openedFrom: 'patient-chart-start-visit', onVisitStarted });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
closeModal();
|
|
35
|
+
}, [closeModal, patientUuid, launchPatientChart, onVisitStarted]);
|
|
36
|
+
|
|
37
|
+
const modalHeaderText = t('noActiveVisit', 'No active visit');
|
|
38
|
+
|
|
39
|
+
const modalBodyText = t(
|
|
40
|
+
'noActiveVisitNoRDEText',
|
|
41
|
+
"You can't add data to the patient chart without an active visit. Would you like to start a new visit?",
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div>
|
|
46
|
+
<ModalHeader closeModal={closeModal}>
|
|
47
|
+
<span className={styles.header}>{modalHeaderText}</span>
|
|
48
|
+
</ModalHeader>
|
|
49
|
+
<ModalBody>
|
|
50
|
+
<p className={styles.body}>{modalBodyText}</p>
|
|
51
|
+
</ModalBody>
|
|
52
|
+
<ModalFooter>
|
|
53
|
+
<Button kind="secondary" onClick={closeModal}>
|
|
54
|
+
{t('cancel', 'Cancel')}
|
|
55
|
+
</Button>
|
|
56
|
+
<Button kind="primary" onClick={handleStartNewVisit}>
|
|
57
|
+
{t('startNewVisit', 'Start new visit')}
|
|
58
|
+
</Button>
|
|
59
|
+
</ModalFooter>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export default StartVisitDialog;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { vi, describe, expect, test } from 'vitest';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
5
|
+
import { launchWorkspace2 } from '@openmrs/esm-framework';
|
|
6
|
+
import StartVisitDialog from './start-visit-dialog.modal';
|
|
7
|
+
|
|
8
|
+
const defaultProps = {
|
|
9
|
+
patientUuid: 'some-uuid',
|
|
10
|
+
closeModal: vi.fn(),
|
|
11
|
+
visitType: null,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const mockLaunchWorkspace = vi.mocked(launchWorkspace2);
|
|
15
|
+
|
|
16
|
+
describe('StartVisit', () => {
|
|
17
|
+
test('should launch start visit form', async () => {
|
|
18
|
+
const user = userEvent.setup();
|
|
19
|
+
|
|
20
|
+
renderStartVisitDialog();
|
|
21
|
+
|
|
22
|
+
expect(
|
|
23
|
+
screen.getByText(
|
|
24
|
+
`You can't add data to the patient chart without an active visit. Would you like to start a new visit?`,
|
|
25
|
+
),
|
|
26
|
+
).toBeInTheDocument();
|
|
27
|
+
|
|
28
|
+
const startNewVisitButton = screen.getByRole('button', { name: /Start new visit/i });
|
|
29
|
+
|
|
30
|
+
await user.click(startNewVisitButton);
|
|
31
|
+
|
|
32
|
+
expect(mockLaunchWorkspace).toHaveBeenCalledWith('start-visit-workspace-form', {
|
|
33
|
+
openedFrom: 'patient-chart-start-visit',
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
function renderStartVisitDialog(props = {}) {
|
|
39
|
+
render(<StartVisitDialog {...defaultProps} {...props} />);
|
|
40
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import React, { type ComponentProps, useCallback } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Button, MenuButton, MenuItem } from '@carbon/react';
|
|
4
|
+
import { AddIcon, type Visit } from '@openmrs/esm-framework';
|
|
5
|
+
import { showModal, useLayoutType } from '@openmrs/esm-framework';
|
|
6
|
+
import { useLaunchWorkspaceRequiringVisit } from '@openmrs/esm-patient-common-lib';
|
|
7
|
+
import styles from './active-visit-buttons.scss';
|
|
8
|
+
|
|
9
|
+
export interface ActiveVisitActionsInterface {
|
|
10
|
+
visit: Visit;
|
|
11
|
+
patientUuid: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This is an extension that is used not in the refapp, but in other distributions.
|
|
16
|
+
*/
|
|
17
|
+
const ActiveVisitActions: React.FC<ActiveVisitActionsInterface> = ({ visit, patientUuid }) => {
|
|
18
|
+
const { t } = useTranslation();
|
|
19
|
+
const layout = useLayoutType();
|
|
20
|
+
const isTablet = layout === 'tablet';
|
|
21
|
+
const isMobile = layout === 'phone';
|
|
22
|
+
|
|
23
|
+
const launchAllergiesFormWorkspace = useLaunchWorkspaceRequiringVisit(patientUuid, 'patient-allergy-form-workspace');
|
|
24
|
+
const launchAppointmentsFormWorkspace = useLaunchWorkspaceRequiringVisit(patientUuid, 'appointments-form-workspace');
|
|
25
|
+
const launchClinicalFormsWorkspace = useLaunchWorkspaceRequiringVisit(patientUuid, 'clinical-forms-workspace');
|
|
26
|
+
const launchConditionsFormWorkspace = useLaunchWorkspaceRequiringVisit(patientUuid, 'conditions-form-workspace');
|
|
27
|
+
const launchOrderBasketFormWorkspace = useLaunchWorkspaceRequiringVisit(patientUuid, 'order-basket');
|
|
28
|
+
const launchVisitNotesFormWorkspace = useLaunchWorkspaceRequiringVisit(patientUuid, 'visit-notes-form-workspace');
|
|
29
|
+
const launchVitalsAndBiometricsFormWorkspace = useLaunchWorkspaceRequiringVisit(
|
|
30
|
+
patientUuid,
|
|
31
|
+
'patient-vitals-biometrics-form-workspace',
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div>
|
|
36
|
+
{isTablet || isMobile ? (
|
|
37
|
+
<div className={styles.buttonsContainer}>
|
|
38
|
+
<VisitActionsComponent patientUuid={patientUuid} />
|
|
39
|
+
|
|
40
|
+
<MenuButton label={t('more', 'More')} kind="ghost">
|
|
41
|
+
<MenuItem
|
|
42
|
+
kind="default"
|
|
43
|
+
label={t('addNote', 'Add note')}
|
|
44
|
+
onClick={launchVisitNotesFormWorkspace}
|
|
45
|
+
renderIcon={AddIcon}
|
|
46
|
+
/>
|
|
47
|
+
<MenuItem
|
|
48
|
+
kind="default"
|
|
49
|
+
label={t('addLabOrPrescription', 'Add lab or prescription')}
|
|
50
|
+
onClick={launchOrderBasketFormWorkspace}
|
|
51
|
+
renderIcon={AddIcon}
|
|
52
|
+
/>
|
|
53
|
+
<MenuItem
|
|
54
|
+
kind="default"
|
|
55
|
+
label={t('addVitals', 'Add vitals')}
|
|
56
|
+
onClick={launchVitalsAndBiometricsFormWorkspace}
|
|
57
|
+
renderIcon={AddIcon}
|
|
58
|
+
/>
|
|
59
|
+
<MenuItem
|
|
60
|
+
kind="default"
|
|
61
|
+
label={t('addCondition', 'Add condition')}
|
|
62
|
+
onClick={launchConditionsFormWorkspace}
|
|
63
|
+
renderIcon={AddIcon}
|
|
64
|
+
/>
|
|
65
|
+
<MenuItem
|
|
66
|
+
kind="default"
|
|
67
|
+
label={t('addAllergy', 'Add allergy')}
|
|
68
|
+
onClick={launchAllergiesFormWorkspace}
|
|
69
|
+
renderIcon={AddIcon}
|
|
70
|
+
/>
|
|
71
|
+
<MenuItem
|
|
72
|
+
kind="default"
|
|
73
|
+
label={t('addAppointment', 'Add appointment')}
|
|
74
|
+
onClick={launchAppointmentsFormWorkspace}
|
|
75
|
+
renderIcon={AddIcon}
|
|
76
|
+
/>
|
|
77
|
+
<MenuItem
|
|
78
|
+
kind="default"
|
|
79
|
+
label={t('otherForm', 'Other form')}
|
|
80
|
+
onClick={launchClinicalFormsWorkspace}
|
|
81
|
+
renderIcon={AddIcon}
|
|
82
|
+
/>
|
|
83
|
+
</MenuButton>
|
|
84
|
+
</div>
|
|
85
|
+
) : (
|
|
86
|
+
<div className={styles.buttonsContainer}>
|
|
87
|
+
<Button
|
|
88
|
+
kind="ghost"
|
|
89
|
+
renderIcon={(props: ComponentProps<typeof AddIcon>) => <AddIcon size={16} {...props} />}
|
|
90
|
+
iconDescription="Add visit note"
|
|
91
|
+
onClick={launchVisitNotesFormWorkspace}
|
|
92
|
+
>
|
|
93
|
+
{t('addNote', 'Add note')}
|
|
94
|
+
</Button>
|
|
95
|
+
<Button
|
|
96
|
+
kind="ghost"
|
|
97
|
+
renderIcon={(props: ComponentProps<typeof AddIcon>) => <AddIcon size={16} {...props} />}
|
|
98
|
+
iconDescription="Add lab or prescription"
|
|
99
|
+
onClick={launchOrderBasketFormWorkspace}
|
|
100
|
+
>
|
|
101
|
+
{t('addLabOrPrescription', 'Add lab or prescription')}
|
|
102
|
+
</Button>
|
|
103
|
+
|
|
104
|
+
<VisitActionsComponent patientUuid={patientUuid} />
|
|
105
|
+
|
|
106
|
+
<MenuButton label={t('more', 'More')} kind="ghost">
|
|
107
|
+
<MenuItem
|
|
108
|
+
kind="default"
|
|
109
|
+
label={t('addVitals', 'Add vitals')}
|
|
110
|
+
onClick={launchVitalsAndBiometricsFormWorkspace}
|
|
111
|
+
renderIcon={AddIcon}
|
|
112
|
+
/>
|
|
113
|
+
<MenuItem
|
|
114
|
+
kind="default"
|
|
115
|
+
label={t('addCondition', 'Add condition')}
|
|
116
|
+
onClick={launchConditionsFormWorkspace}
|
|
117
|
+
renderIcon={AddIcon}
|
|
118
|
+
/>
|
|
119
|
+
<MenuItem
|
|
120
|
+
kind="default"
|
|
121
|
+
label={t('addAllergy', 'Add allergy')}
|
|
122
|
+
onClick={launchAllergiesFormWorkspace}
|
|
123
|
+
renderIcon={AddIcon}
|
|
124
|
+
/>
|
|
125
|
+
<MenuItem
|
|
126
|
+
kind="default"
|
|
127
|
+
label={t('addAppointment', 'Add appointment')}
|
|
128
|
+
onClick={launchAppointmentsFormWorkspace}
|
|
129
|
+
renderIcon={AddIcon}
|
|
130
|
+
/>
|
|
131
|
+
<MenuItem
|
|
132
|
+
kind="default"
|
|
133
|
+
label={t('otherForm', 'Other form')}
|
|
134
|
+
onClick={launchClinicalFormsWorkspace}
|
|
135
|
+
renderIcon={AddIcon}
|
|
136
|
+
/>
|
|
137
|
+
</MenuButton>
|
|
138
|
+
</div>
|
|
139
|
+
)}
|
|
140
|
+
</div>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export default ActiveVisitActions;
|
|
145
|
+
|
|
146
|
+
interface VisitActionsProps {
|
|
147
|
+
patientUuid: string;
|
|
148
|
+
}
|
|
149
|
+
const VisitActionsComponent: React.FC<VisitActionsProps> = ({ patientUuid }) => {
|
|
150
|
+
const { t } = useTranslation();
|
|
151
|
+
|
|
152
|
+
const openModal = useCallback(
|
|
153
|
+
(modalName: string) => {
|
|
154
|
+
const dispose = showModal(modalName, {
|
|
155
|
+
closeModal: () => dispose(),
|
|
156
|
+
patientUuid,
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
[patientUuid],
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<MenuButton label={t('endVisit', 'End visit')} kind="ghost">
|
|
164
|
+
<MenuItem
|
|
165
|
+
kind="default"
|
|
166
|
+
label={t('endVisit', 'End visit')}
|
|
167
|
+
onClick={() => openModal('end-visit-dialog')}
|
|
168
|
+
renderIcon={AddIcon}
|
|
169
|
+
/>
|
|
170
|
+
<MenuItem
|
|
171
|
+
kind="default"
|
|
172
|
+
label={t('deleteVisit', 'Delete visit')}
|
|
173
|
+
onClick={() => openModal('delete-visit-dialog')}
|
|
174
|
+
renderIcon={AddIcon}
|
|
175
|
+
/>
|
|
176
|
+
</MenuButton>
|
|
177
|
+
);
|
|
178
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { launchWorkspace2 } from '@openmrs/esm-framework';
|
|
4
|
+
import { CardHeader, EmptyState, usePatientChartStore } from '@openmrs/esm-patient-common-lib';
|
|
5
|
+
import VisitSummary from './past-visits-components/visit-summary.component';
|
|
6
|
+
import styles from './current-visit-summary.scss';
|
|
7
|
+
|
|
8
|
+
interface CurrentVisitSummaryProps {
|
|
9
|
+
patientUuid: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* This extension is not used in the refapp.
|
|
14
|
+
* This extension uses the patient chart store and SHOULD only be mounted within the patient chart
|
|
15
|
+
*/
|
|
16
|
+
const CurrentVisitSummary: React.FC<CurrentVisitSummaryProps> = ({ patientUuid }) => {
|
|
17
|
+
const { t } = useTranslation();
|
|
18
|
+
const { patientUuid: storePatientUuid, visitContext } = usePatientChartStore(patientUuid);
|
|
19
|
+
|
|
20
|
+
if (patientUuid !== storePatientUuid) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!visitContext) {
|
|
25
|
+
return (
|
|
26
|
+
<EmptyState
|
|
27
|
+
headerTitle={t('currentVisit', 'Current visit')}
|
|
28
|
+
displayText={t('noActiveVisitMessage', 'active visits')}
|
|
29
|
+
launchForm={() =>
|
|
30
|
+
launchWorkspace2('start-visit-workspace-form', { openedFrom: 'patient-chart-current-visit-summary' })
|
|
31
|
+
}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className={styles.container}>
|
|
38
|
+
<CardHeader title={t('currentVisit', 'Current visit')}>
|
|
39
|
+
<span />
|
|
40
|
+
</CardHeader>
|
|
41
|
+
<div className={styles.visitSummaryCard}>
|
|
42
|
+
<VisitSummary visit={visitContext} patientUuid={patientUuid} />
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default CurrentVisitSummary;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { vi, describe, expect, test } from 'vitest';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import { getConfig } from '@openmrs/esm-framework';
|
|
5
|
+
import { mockPatient, waitForLoadingToFinish } from 'tools';
|
|
6
|
+
import { usePatientChartStore } from '@openmrs/esm-patient-common-lib';
|
|
7
|
+
import CurrentVisitSummary from './current-visit-summary.extension';
|
|
8
|
+
|
|
9
|
+
const mockGetConfig = vi.mocked(getConfig);
|
|
10
|
+
const mockUsePatientChartStore = vi.mocked(usePatientChartStore);
|
|
11
|
+
|
|
12
|
+
vi.mock('@openmrs/esm-patient-common-lib', async () => ({
|
|
13
|
+
...((await vi.importActual('@openmrs/esm-patient-common-lib')) as object),
|
|
14
|
+
usePatientChartStore: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
describe('CurrentVisitSummary', () => {
|
|
18
|
+
test('renders an empty state when there is no active visit', () => {
|
|
19
|
+
mockUsePatientChartStore.mockReturnValue({
|
|
20
|
+
patientUuid: mockPatient.id,
|
|
21
|
+
patient: mockPatient,
|
|
22
|
+
visitContext: null,
|
|
23
|
+
mutateVisitContext: null,
|
|
24
|
+
setPatient: vi.fn(),
|
|
25
|
+
setVisitContext: vi.fn(),
|
|
26
|
+
});
|
|
27
|
+
render(<CurrentVisitSummary patientUuid={mockPatient.id} />);
|
|
28
|
+
expect(screen.getByText(/current visit/i)).toBeInTheDocument();
|
|
29
|
+
expect(screen.getByText('There are no active visits to display for this patient')).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('returns null when patientUuid does not match store patientUuid', () => {
|
|
33
|
+
mockUsePatientChartStore.mockReturnValue({
|
|
34
|
+
patientUuid: 'different-patient-id',
|
|
35
|
+
patient: mockPatient,
|
|
36
|
+
visitContext: null,
|
|
37
|
+
mutateVisitContext: null,
|
|
38
|
+
setPatient: vi.fn(),
|
|
39
|
+
setVisitContext: vi.fn(),
|
|
40
|
+
});
|
|
41
|
+
render(<CurrentVisitSummary patientUuid={mockPatient.id} />);
|
|
42
|
+
expect(screen.queryByText(/current visit/i)).not.toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('renders a visit summary when visit context exists', async () => {
|
|
46
|
+
mockGetConfig.mockResolvedValue({ htmlFormEntryForms: [] });
|
|
47
|
+
mockUsePatientChartStore.mockReturnValue({
|
|
48
|
+
patientUuid: mockPatient.id,
|
|
49
|
+
patient: mockPatient,
|
|
50
|
+
visitContext: {
|
|
51
|
+
uuid: 'some-uuid',
|
|
52
|
+
display: 'Visit 1',
|
|
53
|
+
startDatetime: '2021-03-23T10:00:00.000+0300',
|
|
54
|
+
stopDatetime: null,
|
|
55
|
+
location: {
|
|
56
|
+
uuid: 'some-uuid',
|
|
57
|
+
display: 'Location 1',
|
|
58
|
+
},
|
|
59
|
+
visitType: {
|
|
60
|
+
uuid: 'some-uuid',
|
|
61
|
+
display: 'Visit Type 1',
|
|
62
|
+
},
|
|
63
|
+
encounters: [],
|
|
64
|
+
patient: {
|
|
65
|
+
uuid: mockPatient.id,
|
|
66
|
+
display: 'Test Patient',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
mutateVisitContext: null,
|
|
70
|
+
setPatient: vi.fn(),
|
|
71
|
+
setVisitContext: vi.fn(),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
render(<CurrentVisitSummary patientUuid={mockPatient.id} />);
|
|
75
|
+
|
|
76
|
+
await waitForLoadingToFinish();
|
|
77
|
+
|
|
78
|
+
expect(screen.getByText(/current visit/i)).toBeInTheDocument();
|
|
79
|
+
expect(screen.getByText('Diagnoses')).toBeInTheDocument();
|
|
80
|
+
const buttonNames = ['Notes', 'Tests', 'Medications', 'Encounters'];
|
|
81
|
+
buttonNames.forEach((buttonName) => {
|
|
82
|
+
expect(screen.getByRole('tab', { name: buttonName })).toBeInTheDocument();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { SkeletonText } from '@carbon/react';
|
|
4
|
+
import { type Obs, useConfig } from '@openmrs/esm-framework';
|
|
5
|
+
import styles from './styles.scss';
|
|
6
|
+
|
|
7
|
+
interface EncounterObservationsProps {
|
|
8
|
+
observations: Array<Obs>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const EncounterObservations: React.FC<EncounterObservationsProps> = ({ observations }) => {
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
const { obsConceptUuidsToHide = [] } = useConfig();
|
|
14
|
+
|
|
15
|
+
function getAnswerFromDisplay(display: string): string {
|
|
16
|
+
const colonIndex = display.indexOf(':');
|
|
17
|
+
if (colonIndex === -1) {
|
|
18
|
+
return '';
|
|
19
|
+
} else {
|
|
20
|
+
return display.substring(colonIndex + 1).trim();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const filteredObservations = !!obsConceptUuidsToHide.length
|
|
25
|
+
? observations?.filter((obs) => {
|
|
26
|
+
return !obsConceptUuidsToHide.includes(obs?.concept?.uuid);
|
|
27
|
+
})
|
|
28
|
+
: observations;
|
|
29
|
+
|
|
30
|
+
if (!filteredObservations || filteredObservations.length == 0) {
|
|
31
|
+
return (
|
|
32
|
+
<div className={styles.observation}>
|
|
33
|
+
<p>{t('noObservationsFound', 'No observations found')}</p>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className={styles.observation}>
|
|
40
|
+
{filteredObservations?.map((obs, index) => {
|
|
41
|
+
if (obs.groupMembers) {
|
|
42
|
+
return (
|
|
43
|
+
<React.Fragment key={index}>
|
|
44
|
+
<span className={styles.parentConcept}>{obs.concept.display}</span>
|
|
45
|
+
<span />
|
|
46
|
+
{obs.groupMembers.map((member) => (
|
|
47
|
+
<React.Fragment key={index}>
|
|
48
|
+
<span className={styles.childConcept}>{member.concept.display}</span>
|
|
49
|
+
<span>{getAnswerFromDisplay(member.display)}</span>
|
|
50
|
+
</React.Fragment>
|
|
51
|
+
))}
|
|
52
|
+
</React.Fragment>
|
|
53
|
+
);
|
|
54
|
+
} else {
|
|
55
|
+
return (
|
|
56
|
+
<React.Fragment key={index}>
|
|
57
|
+
<span>{obs.concept.display}</span>
|
|
58
|
+
<span>{getAnswerFromDisplay(obs.display)}</span>
|
|
59
|
+
</React.Fragment>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
})}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default EncounterObservations;
|