@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,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useSWRConfig } from 'swr';
|
|
3
|
+
import { useVisit, type Visit } from '@openmrs/esm-framework';
|
|
4
|
+
import {
|
|
5
|
+
invalidateVisitByUuid,
|
|
6
|
+
type PatientWorkspace2DefinitionProps,
|
|
7
|
+
usePatientChartStore,
|
|
8
|
+
} from '@openmrs/esm-patient-common-lib';
|
|
9
|
+
import ExportedVisitForm from './exported-visit-form.workspace';
|
|
10
|
+
|
|
11
|
+
export interface VisitFormProps {
|
|
12
|
+
/**
|
|
13
|
+
* A unique string identifying where the visit form is opened from.
|
|
14
|
+
* This string is passed into various extensions within the form to
|
|
15
|
+
* affect how / if they should be rendered.
|
|
16
|
+
*/
|
|
17
|
+
openedFrom: string;
|
|
18
|
+
showPatientHeader?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* This form is used for starting a new visit and for editing
|
|
23
|
+
* an existing visit
|
|
24
|
+
*
|
|
25
|
+
* This workspace must only be used within the patient chart.
|
|
26
|
+
* @see exported-visit-form.workspace.tsx
|
|
27
|
+
*/
|
|
28
|
+
const VisitForm: React.FC<PatientWorkspace2DefinitionProps<VisitFormProps, {}>> = ({
|
|
29
|
+
workspaceProps: { openedFrom, showPatientHeader = false },
|
|
30
|
+
groupProps: { patient, patientUuid, visitContext },
|
|
31
|
+
...rest
|
|
32
|
+
}) => {
|
|
33
|
+
const { mutate: mutateActiveVisit } = useVisit(patientUuid);
|
|
34
|
+
const { mutate: globalMutate } = useSWRConfig();
|
|
35
|
+
const { setVisitContext } = usePatientChartStore(patientUuid);
|
|
36
|
+
|
|
37
|
+
const onVisitStarted = (visit: Visit) => {
|
|
38
|
+
// For visit creation, we need to update:
|
|
39
|
+
// 1. Current visit data (for critical components like visit summary, action buttons)
|
|
40
|
+
// 2. Visit history table (for the paginated visit list)
|
|
41
|
+
const mutateSavedOrUpdatedVisit = () => invalidateVisitByUuid(globalMutate, visit.uuid);
|
|
42
|
+
mutateActiveVisit();
|
|
43
|
+
setVisitContext?.(visit, mutateSavedOrUpdatedVisit);
|
|
44
|
+
};
|
|
45
|
+
return (
|
|
46
|
+
<ExportedVisitForm
|
|
47
|
+
{...rest}
|
|
48
|
+
workspaceProps={{
|
|
49
|
+
openedFrom,
|
|
50
|
+
showPatientHeader,
|
|
51
|
+
onVisitStarted,
|
|
52
|
+
patient,
|
|
53
|
+
patientUuid,
|
|
54
|
+
visitContext,
|
|
55
|
+
}}
|
|
56
|
+
groupProps={{}}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default VisitForm;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { vi, describe, it, expect, test } from 'vitest';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { useVisitTypes } from '@openmrs/esm-framework';
|
|
5
|
+
import { screen, render } from '@testing-library/react';
|
|
6
|
+
import { mockVisitTypes } from '__mocks__';
|
|
7
|
+
import BaseVisitType from './base-visit-type.component';
|
|
8
|
+
|
|
9
|
+
const mockUseVisitTypes = vi.mocked(useVisitTypes);
|
|
10
|
+
|
|
11
|
+
vi.mock('lodash-es/debounce', () => vi.fn((fn) => fn));
|
|
12
|
+
vi.mock('react-hook-form', async () => ({
|
|
13
|
+
...((await vi.importActual('react-hook-form')) as object),
|
|
14
|
+
useFormContext: vi.fn().mockImplementation(() => ({
|
|
15
|
+
handleSubmit: () => vi.fn(),
|
|
16
|
+
control: {
|
|
17
|
+
register: vi.fn(),
|
|
18
|
+
unregister: vi.fn(),
|
|
19
|
+
getFieldState: vi.fn(),
|
|
20
|
+
_names: {
|
|
21
|
+
array: new Set('test'),
|
|
22
|
+
mount: new Set('test'),
|
|
23
|
+
unMount: new Set('test'),
|
|
24
|
+
watch: new Set('test'),
|
|
25
|
+
focus: 'test',
|
|
26
|
+
watchAll: false,
|
|
27
|
+
},
|
|
28
|
+
_subjects: {
|
|
29
|
+
watch: vi.fn(),
|
|
30
|
+
array: vi.fn(),
|
|
31
|
+
state: vi.fn(),
|
|
32
|
+
},
|
|
33
|
+
_getWatch: vi.fn(),
|
|
34
|
+
_formValues: [],
|
|
35
|
+
_defaultValues: [],
|
|
36
|
+
},
|
|
37
|
+
getValues: () => {
|
|
38
|
+
return [];
|
|
39
|
+
},
|
|
40
|
+
setValue: () => vi.fn(),
|
|
41
|
+
formState: () => vi.fn(),
|
|
42
|
+
watch: () => vi.fn(),
|
|
43
|
+
})),
|
|
44
|
+
Controller: ({ render }) =>
|
|
45
|
+
render({
|
|
46
|
+
field: {
|
|
47
|
+
onChange: vi.fn(),
|
|
48
|
+
onBlur: vi.fn(),
|
|
49
|
+
value: '',
|
|
50
|
+
ref: vi.fn(),
|
|
51
|
+
},
|
|
52
|
+
formState: {
|
|
53
|
+
isSubmitted: false,
|
|
54
|
+
},
|
|
55
|
+
fieldState: {
|
|
56
|
+
isTouched: false,
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
useSubscribe: () => ({
|
|
60
|
+
r: { current: { subject: { subscribe: () => vi.fn() } } },
|
|
61
|
+
}),
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
describe('VisitTypeOverview', () => {
|
|
65
|
+
const renderVisitTypeOverview = () => {
|
|
66
|
+
mockUseVisitTypes.mockReturnValue(mockVisitTypes);
|
|
67
|
+
|
|
68
|
+
render(<BaseVisitType visitTypes={mockVisitTypes} />);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
it('should be able to search for a visit type', async () => {
|
|
72
|
+
const user = userEvent.setup();
|
|
73
|
+
|
|
74
|
+
renderVisitTypeOverview();
|
|
75
|
+
|
|
76
|
+
const hivVisit = screen.getByRole('radio', { name: /HIV Return Visit/i });
|
|
77
|
+
const outpatientVisit = screen.getByRole('radio', { name: /Outpatient Visit/i });
|
|
78
|
+
|
|
79
|
+
expect(outpatientVisit).toBeInTheDocument();
|
|
80
|
+
expect(hivVisit).toBeInTheDocument();
|
|
81
|
+
|
|
82
|
+
const searchInput = screen.getByRole('searchbox');
|
|
83
|
+
await user.type(searchInput, 'HIV');
|
|
84
|
+
|
|
85
|
+
expect(outpatientVisit).toBeEmptyDOMElement();
|
|
86
|
+
expect(hivVisit).toBeInTheDocument();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ExtensionSlot, type Visit } from '@openmrs/esm-framework';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import styles from './visit-actions-cell.scss';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
visit: Visit;
|
|
7
|
+
patient: fhir.Patient;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const VisitActionsCell: React.FC<Props> = ({ visit, patient }) => {
|
|
11
|
+
return (
|
|
12
|
+
<ExtensionSlot
|
|
13
|
+
name="visit-detail-overview-actions"
|
|
14
|
+
className={styles.visitActions}
|
|
15
|
+
state={{ patientUuid: visit.patient.uuid, patient, visit, compact: true }}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default VisitActionsCell;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { formatDate, type Visit } from '@openmrs/esm-framework';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
visit: Visit;
|
|
7
|
+
patient: fhir.Patient;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const VisitDateCell: React.FC<Props> = ({ visit }) => {
|
|
11
|
+
const { t } = useTranslation();
|
|
12
|
+
const { startDatetime, stopDatetime } = visit;
|
|
13
|
+
const fromDate = formatDate(new Date(startDatetime));
|
|
14
|
+
const toDate = stopDatetime ? formatDate(new Date(stopDatetime)) : null;
|
|
15
|
+
|
|
16
|
+
return <>{toDate ? t('fromDateToDate', '{{fromDate}} - {{toDate}}', { fromDate, toDate }) : fromDate}</>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default VisitDateCell;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DiagnosisTags, type Visit } from '@openmrs/esm-framework';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
visit: Visit;
|
|
6
|
+
patient: fhir.Patient;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const VisitDiagnosisCell: React.FC<Props> = ({ visit }) => {
|
|
10
|
+
const diagnoses = visit.encounters
|
|
11
|
+
.flatMap((encounter) => encounter.diagnoses)
|
|
12
|
+
.filter((diagnosis) => !diagnosis.voided)
|
|
13
|
+
.sort((a, b) => a.rank - b.rank);
|
|
14
|
+
|
|
15
|
+
return <DiagnosisTags diagnoses={diagnoses} />;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default VisitDiagnosisCell;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import {
|
|
4
|
+
DataTable,
|
|
5
|
+
DataTableSkeleton,
|
|
6
|
+
Pagination,
|
|
7
|
+
Table,
|
|
8
|
+
TableBody,
|
|
9
|
+
TableCell,
|
|
10
|
+
TableContainer,
|
|
11
|
+
TableExpandedRow,
|
|
12
|
+
TableExpandHeader,
|
|
13
|
+
TableExpandRow,
|
|
14
|
+
TableHead,
|
|
15
|
+
TableHeader,
|
|
16
|
+
TableRow,
|
|
17
|
+
} from '@carbon/react';
|
|
18
|
+
import { ErrorState, isDesktop, useLayoutType } from '@openmrs/esm-framework';
|
|
19
|
+
import { EmptyState } from '@openmrs/esm-patient-common-lib';
|
|
20
|
+
import { usePaginatedVisits } from '../visits-widget/visit.resource';
|
|
21
|
+
import VisitActionsCell from './visit-actions-cell.component';
|
|
22
|
+
import VisitDateCell from './visit-date-cell.component';
|
|
23
|
+
import VisitDiagnosisCell from './visit-diagnoses-cell.component';
|
|
24
|
+
import VisitSummary from '../visits-widget/past-visits-components/visit-summary.component';
|
|
25
|
+
import VisitTypeCell from './visit-type-cell.component';
|
|
26
|
+
import styles from './visit-history-table.scss';
|
|
27
|
+
|
|
28
|
+
interface VisitHistoryTableProps {
|
|
29
|
+
patientUuid: string;
|
|
30
|
+
patient: fhir.Patient;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* This show a list of visit histories in the visit tab in patient chart
|
|
35
|
+
*/
|
|
36
|
+
const VisitHistoryTable: React.FC<VisitHistoryTableProps> = ({ patientUuid, patient }) => {
|
|
37
|
+
const defaultPageSize = 10;
|
|
38
|
+
const [pageSize, setPageSize] = useState(defaultPageSize);
|
|
39
|
+
const pageSizes = [10, 20, 30, 40, 50];
|
|
40
|
+
|
|
41
|
+
const { data: visits, currentPage, error, isLoading, totalCount, goTo } = usePaginatedVisits(patientUuid, pageSize);
|
|
42
|
+
const { t } = useTranslation();
|
|
43
|
+
const desktopLayout = isDesktop(useLayoutType());
|
|
44
|
+
|
|
45
|
+
// TODO: make this configurable
|
|
46
|
+
const columns = [
|
|
47
|
+
{ key: 'visitDate', header: t('date', 'Date'), CellComponent: VisitDateCell },
|
|
48
|
+
{ key: 'visitType', header: t('visitType', 'Visit type'), CellComponent: VisitTypeCell },
|
|
49
|
+
{ key: 'diagnoses', header: t('diagnoses', 'Diagnoses'), CellComponent: VisitDiagnosisCell },
|
|
50
|
+
{ key: 'actions', header: '', CellComponent: VisitActionsCell },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const layout = useLayoutType();
|
|
54
|
+
|
|
55
|
+
const rowData = visits?.map((visit) => {
|
|
56
|
+
const row: Record<string, JSX.Element | string> = { id: visit.uuid };
|
|
57
|
+
for (const { key, CellComponent } of columns) {
|
|
58
|
+
row[key] = <CellComponent key={key} visit={visit} patient={patient} />;
|
|
59
|
+
}
|
|
60
|
+
return row;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (isLoading) {
|
|
64
|
+
return <DataTableSkeleton role="progressbar" zebra />;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (error) {
|
|
68
|
+
return <ErrorState error={error} headerTitle={t('pastVisits', 'Past visits')} />;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (visits.length === 0) {
|
|
72
|
+
return (
|
|
73
|
+
<div className={styles.emptyStateContainer}>
|
|
74
|
+
<EmptyState headerTitle={t('pastVisits', 'Past visits')} displayText={t('visits', 'visits')} />
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return (
|
|
79
|
+
<div className={styles.container}>
|
|
80
|
+
{/* @ts-ignore */}
|
|
81
|
+
<DataTable headers={columns} rows={rowData} size={desktopLayout ? 'sm' : 'lg'} useZebraStyles>
|
|
82
|
+
{({ rows, headers, getTableProps, getHeaderProps, getExpandHeaderProps, getRowProps, getExpandedRowProps }) => (
|
|
83
|
+
<>
|
|
84
|
+
<TableContainer>
|
|
85
|
+
<Table {...getTableProps()}>
|
|
86
|
+
<TableHead>
|
|
87
|
+
<TableRow>
|
|
88
|
+
<TableExpandHeader enableToggle {...getExpandHeaderProps()} />
|
|
89
|
+
{headers.map((header) => (
|
|
90
|
+
<TableHeader
|
|
91
|
+
{...getHeaderProps({
|
|
92
|
+
header,
|
|
93
|
+
className: header.key === 'actions' ? styles.actionsColumn : '',
|
|
94
|
+
})}
|
|
95
|
+
>
|
|
96
|
+
{header.header}
|
|
97
|
+
</TableHeader>
|
|
98
|
+
))}
|
|
99
|
+
</TableRow>
|
|
100
|
+
</TableHead>
|
|
101
|
+
<TableBody>
|
|
102
|
+
{rows.map((row, i) => {
|
|
103
|
+
const visit = visits[i];
|
|
104
|
+
return (
|
|
105
|
+
<React.Fragment key={row.id}>
|
|
106
|
+
<TableExpandRow {...getRowProps({ row })}>
|
|
107
|
+
{row.cells.map((cell) => {
|
|
108
|
+
return <TableCell key={cell.id}>{cell?.value}</TableCell>;
|
|
109
|
+
})}
|
|
110
|
+
</TableExpandRow>
|
|
111
|
+
{row.isExpanded ? (
|
|
112
|
+
<TableExpandedRow {...getExpandedRowProps({ row })} colSpan={headers.length + 2}>
|
|
113
|
+
<VisitSummary visit={visit} patientUuid={patientUuid} />
|
|
114
|
+
</TableExpandedRow>
|
|
115
|
+
) : (
|
|
116
|
+
<TableExpandedRow className={styles.hiddenRow} colSpan={headers.length + 2} />
|
|
117
|
+
)}
|
|
118
|
+
</React.Fragment>
|
|
119
|
+
);
|
|
120
|
+
})}
|
|
121
|
+
</TableBody>
|
|
122
|
+
</Table>
|
|
123
|
+
</TableContainer>
|
|
124
|
+
<Pagination
|
|
125
|
+
forwardText={t('nextPage', 'Next page')}
|
|
126
|
+
backwardText={t('previousPage', 'Previous page')}
|
|
127
|
+
page={currentPage}
|
|
128
|
+
pageSize={pageSize}
|
|
129
|
+
pageSizes={pageSizes}
|
|
130
|
+
totalItems={totalCount}
|
|
131
|
+
onChange={({ pageSize, page }) => {
|
|
132
|
+
setPageSize(pageSize);
|
|
133
|
+
if (page !== currentPage) {
|
|
134
|
+
goTo(page);
|
|
135
|
+
}
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
</>
|
|
139
|
+
)}
|
|
140
|
+
</DataTable>
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export default VisitHistoryTable;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
3
|
+
|
|
4
|
+
.container {
|
|
5
|
+
margin: layout.$spacing-05 0;
|
|
6
|
+
border: 1px solid $ui-03;
|
|
7
|
+
|
|
8
|
+
// fixes padding of encounters table within the expanded visit table row
|
|
9
|
+
:global(tr.cds--parent-row.cds--expandable-row + tr[data-child-row] td) {
|
|
10
|
+
padding-inline-start: layout.$spacing-05;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.emptyStateContainer {
|
|
15
|
+
text-align: center;
|
|
16
|
+
margin: layout.$spacing-05 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.actionsColumn {
|
|
20
|
+
width: 1% !important; // fixes the width of action column to fit content
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.hiddenRow {
|
|
24
|
+
display: none;
|
|
25
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Visit } from '@openmrs/esm-framework';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
visit: Visit;
|
|
6
|
+
patient: fhir.Patient;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const VisitTypeCell: React.FC<Props> = ({ visit }) => {
|
|
10
|
+
const { visitType } = visit;
|
|
11
|
+
|
|
12
|
+
return <>{visitType.display}</>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default VisitTypeCell;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Button, ModalHeader, ModalBody, ModalFooter, InlineLoading } from '@carbon/react';
|
|
4
|
+
import { type Visit } from '@openmrs/esm-framework';
|
|
5
|
+
import { useDeleteVisit } from '../hooks/useDeleteVisit';
|
|
6
|
+
import styles from './start-visit-dialog.scss';
|
|
7
|
+
|
|
8
|
+
interface DeleteVisitDialogProps {
|
|
9
|
+
closeModal: () => void;
|
|
10
|
+
visit: Visit;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const DeleteVisitDialog: React.FC<DeleteVisitDialogProps> = ({ closeModal, visit }) => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const { isDeletingVisit, initiateDeletingVisit } = useDeleteVisit(visit, closeModal);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div>
|
|
19
|
+
<ModalHeader
|
|
20
|
+
closeModal={closeModal}
|
|
21
|
+
title={t('deleteVisitDialogHeader', 'Are you sure you want to delete this visit?')}
|
|
22
|
+
/>
|
|
23
|
+
<ModalBody>
|
|
24
|
+
<p className={styles.body}>
|
|
25
|
+
{t('confirmDeleteVisitText', 'Deleting this {{visit}} will delete its associated encounters.', {
|
|
26
|
+
visit: visit?.visitType?.display ?? t('visit', 'Visit'),
|
|
27
|
+
})}
|
|
28
|
+
</p>
|
|
29
|
+
</ModalBody>
|
|
30
|
+
<ModalFooter>
|
|
31
|
+
<Button kind="secondary" onClick={closeModal}>
|
|
32
|
+
{t('cancel', 'Cancel')}
|
|
33
|
+
</Button>
|
|
34
|
+
<Button kind="danger" onClick={initiateDeletingVisit} disabled={isDeletingVisit}>
|
|
35
|
+
{!isDeletingVisit ? (
|
|
36
|
+
t('deleteVisit', 'Delete visit')
|
|
37
|
+
) : (
|
|
38
|
+
<InlineLoading description={t('deletingVisit', 'Deleting visit')} />
|
|
39
|
+
)}
|
|
40
|
+
</Button>
|
|
41
|
+
</ModalFooter>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default DeleteVisitDialog;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { openmrsFetch, showSnackbar, type FetchResponse } from '@openmrs/esm-framework';
|
|
2
|
+
import { vi, describe, it, expect } from 'vitest';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
5
|
+
import { mockCurrentVisit } from '__mocks__';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import DeleteVisitDialog from './delete-visit-dialog.modal';
|
|
9
|
+
|
|
10
|
+
const mockCloseModal = vi.fn();
|
|
11
|
+
const mockOpenmrsFetch = vi.mocked(openmrsFetch);
|
|
12
|
+
const mockShowSnackbar = vi.mocked(showSnackbar);
|
|
13
|
+
|
|
14
|
+
describe('Delete visit', () => {
|
|
15
|
+
it('voids the visit and voids its associated encounters', async () => {
|
|
16
|
+
const user = userEvent.setup();
|
|
17
|
+
|
|
18
|
+
const response: Partial<FetchResponse> = {
|
|
19
|
+
statusText: 'ok',
|
|
20
|
+
status: 200,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
mockOpenmrsFetch.mockResolvedValue(response as FetchResponse);
|
|
24
|
+
|
|
25
|
+
render(<DeleteVisitDialog visit={mockCurrentVisit} closeModal={mockCloseModal} />);
|
|
26
|
+
|
|
27
|
+
const cancelButton = screen.getByRole('button', { name: /^cancel$/i });
|
|
28
|
+
const deleteVisitButton = screen.getByRole('button', { name: /delete visit$/i });
|
|
29
|
+
const closeModalButton = screen.getByRole('button', { name: /close/i });
|
|
30
|
+
|
|
31
|
+
expect(cancelButton).toBeInTheDocument();
|
|
32
|
+
expect(deleteVisitButton).toBeInTheDocument();
|
|
33
|
+
expect(closeModalButton).toBeInTheDocument();
|
|
34
|
+
|
|
35
|
+
expect(screen.getByRole('heading', { name: /Are you sure you want to delete this visit?/i })).toBeInTheDocument();
|
|
36
|
+
expect(screen.getByText(/Deleting this Facility Visit will delete its associated encounters/i)).toBeInTheDocument();
|
|
37
|
+
|
|
38
|
+
await user.click(deleteVisitButton);
|
|
39
|
+
|
|
40
|
+
expect(mockOpenmrsFetch).toHaveBeenCalledWith(`/ws/rest/v1/visit/${mockCurrentVisit.uuid}`, {
|
|
41
|
+
method: 'DELETE',
|
|
42
|
+
});
|
|
43
|
+
expect(mockShowSnackbar).toHaveBeenCalledWith(
|
|
44
|
+
expect.objectContaining({
|
|
45
|
+
kind: 'success',
|
|
46
|
+
title: 'Facility Visit deleted',
|
|
47
|
+
subtitle: 'Facility Visit deleted successfully',
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('displays an error notification if there was problem with deleting a visit', async () => {
|
|
53
|
+
const user = userEvent.setup();
|
|
54
|
+
|
|
55
|
+
mockOpenmrsFetch.mockRejectedValueOnce({ message: 'Internal server error', status: 500 });
|
|
56
|
+
|
|
57
|
+
render(<DeleteVisitDialog visit={mockCurrentVisit} closeModal={mockCloseModal} />);
|
|
58
|
+
|
|
59
|
+
const cancelButton = screen.getByRole('button', { name: /^cancel$/i });
|
|
60
|
+
const deleteVisitButton = screen.getByRole('button', { name: /delete visit$/i });
|
|
61
|
+
const closeModalButton = screen.getByRole('button', { name: /close/i });
|
|
62
|
+
|
|
63
|
+
expect(cancelButton).toBeInTheDocument();
|
|
64
|
+
expect(deleteVisitButton).toBeInTheDocument();
|
|
65
|
+
expect(closeModalButton).toBeInTheDocument();
|
|
66
|
+
expect(screen.getByText(/Deleting this Facility Visit will delete its associated encounters/i)).toBeInTheDocument();
|
|
67
|
+
|
|
68
|
+
await user.click(deleteVisitButton);
|
|
69
|
+
|
|
70
|
+
expect(mockOpenmrsFetch).toHaveBeenCalledWith(`/ws/rest/v1/visit/${mockCurrentVisit.uuid}`, {
|
|
71
|
+
method: 'DELETE',
|
|
72
|
+
});
|
|
73
|
+
expect(mockShowSnackbar).toHaveBeenCalledWith({
|
|
74
|
+
subtitle: 'An error occurred when deleting visit',
|
|
75
|
+
kind: 'error',
|
|
76
|
+
title: 'Error deleting visit',
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
|
|
4
|
+
import { showSnackbar, updateVisit, useVisit } from '@openmrs/esm-framework';
|
|
5
|
+
import { usePatientChartStore } from '@openmrs/esm-patient-common-lib';
|
|
6
|
+
import styles from './end-visit-dialog.scss';
|
|
7
|
+
|
|
8
|
+
interface EndVisitDialogProps {
|
|
9
|
+
patientUuid: string;
|
|
10
|
+
closeModal: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This modal shows up when user clicks on the "End visit" button in the action menu within the
|
|
15
|
+
* patient banner. It should only show when the patient has an active visit. See stop-visit.component.tsx
|
|
16
|
+
* for the button.
|
|
17
|
+
*
|
|
18
|
+
* This dialog uses the patient chart store and SHOULD only be mounted within the patient chart
|
|
19
|
+
*/
|
|
20
|
+
const EndVisitDialog: React.FC<EndVisitDialogProps> = ({ patientUuid, closeModal }) => {
|
|
21
|
+
const { t } = useTranslation();
|
|
22
|
+
const { activeVisit, mutate } = useVisit(patientUuid);
|
|
23
|
+
const { visitContext, setVisitContext } = usePatientChartStore(patientUuid);
|
|
24
|
+
|
|
25
|
+
const handleEndVisit = () => {
|
|
26
|
+
if (activeVisit) {
|
|
27
|
+
const endVisitPayload = {
|
|
28
|
+
stopDatetime: new Date(),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const abortController = new AbortController();
|
|
32
|
+
|
|
33
|
+
updateVisit(activeVisit.uuid, endVisitPayload, abortController)
|
|
34
|
+
.then((response) => {
|
|
35
|
+
mutate();
|
|
36
|
+
window.dispatchEvent(new CustomEvent('queue-entry-updated'));
|
|
37
|
+
closeModal();
|
|
38
|
+
if (visitContext?.uuid == activeVisit.uuid) {
|
|
39
|
+
setVisitContext(null, null);
|
|
40
|
+
}
|
|
41
|
+
showSnackbar({
|
|
42
|
+
isLowContrast: true,
|
|
43
|
+
kind: 'success',
|
|
44
|
+
subtitle: t('visitEndSuccessfully', `${response?.data?.visitType?.display} ended successfully`),
|
|
45
|
+
title: t('visitEnded', 'Visit ended'),
|
|
46
|
+
});
|
|
47
|
+
})
|
|
48
|
+
.catch((error) => {
|
|
49
|
+
showSnackbar({
|
|
50
|
+
title: t('errorEndingVisit', 'Error ending visit'),
|
|
51
|
+
kind: 'error',
|
|
52
|
+
isLowContrast: false,
|
|
53
|
+
subtitle: error?.message,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div>
|
|
61
|
+
<ModalHeader
|
|
62
|
+
closeModal={closeModal}
|
|
63
|
+
title={t('endActiveVisitConfirmation', 'Are you sure you want to end this active visit?')}
|
|
64
|
+
/>
|
|
65
|
+
<ModalBody>
|
|
66
|
+
<p className={styles.bodyShort02}>
|
|
67
|
+
{t('youCanAddAdditionalEncounters', 'You can add additional encounters to this visit in the visit summary.')}
|
|
68
|
+
</p>
|
|
69
|
+
</ModalBody>
|
|
70
|
+
<ModalFooter>
|
|
71
|
+
<Button kind="secondary" onClick={closeModal}>
|
|
72
|
+
{t('cancel', 'Cancel')}
|
|
73
|
+
</Button>
|
|
74
|
+
<Button kind="danger" onClick={handleEndVisit}>
|
|
75
|
+
{t('endVisit_title', 'End Visit')}
|
|
76
|
+
</Button>
|
|
77
|
+
</ModalFooter>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export default EndVisitDialog;
|