@openmrs/esm-patient-chart-app 11.3.1-patch.9064 → 11.3.1-patch.9310
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/.turbo/turbo-build.log +24 -21
- package/dist/1815.js +2 -0
- package/dist/1815.js.map +1 -0
- package/dist/2761.js +1 -1
- package/dist/2761.js.map +1 -1
- package/dist/2859.js +1 -1
- package/dist/2859.js.map +1 -1
- package/dist/3697.js +1 -0
- package/dist/3697.js.map +1 -0
- package/dist/4055.js +1 -1
- package/dist/4300.js +1 -1
- package/dist/4718.js +1 -1
- package/dist/4754.js +1 -1
- package/dist/5205.js +1 -1
- package/dist/5670.js +1 -1
- package/dist/5670.js.map +1 -1
- package/dist/5827.js +1 -0
- package/dist/5827.js.map +1 -0
- package/dist/6336.js +1 -0
- package/dist/6336.js.map +1 -0
- package/dist/6411.js +1 -1
- package/dist/6411.js.map +1 -1
- package/dist/6529.js +1 -1
- package/dist/6568.js +1 -0
- package/dist/6568.js.map +1 -0
- package/dist/6924.js +1 -0
- package/dist/6924.js.map +1 -0
- package/dist/7816.js +2 -0
- package/dist/7816.js.map +1 -0
- package/dist/7818.js +1 -0
- package/dist/7818.js.map +1 -0
- package/dist/7822.js +1 -1
- package/dist/7822.js.map +1 -1
- package/dist/8260.js +1 -0
- package/dist/8260.js.map +1 -0
- package/dist/8278.js +1 -0
- package/dist/8278.js.map +1 -0
- package/dist/8454.js +1 -1
- package/dist/8454.js.map +1 -1
- package/dist/8709.js +1 -1
- package/dist/8709.js.map +1 -1
- package/dist/{4727.js → 9294.js} +1 -1
- package/dist/9294.js.map +1 -0
- package/dist/9329.js +1 -0
- package/dist/9329.js.map +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-patient-chart-app.js +1 -1
- package/dist/openmrs-esm-patient-chart-app.js.buildmanifest.json +312 -287
- package/dist/openmrs-esm-patient-chart-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +3 -3
- package/src/actions-buttons/delete-visit.component.tsx +8 -3
- package/src/actions-buttons/mark-patient-deceased.component.tsx +2 -2
- package/src/actions-buttons/start-visit.component.tsx +10 -5
- package/src/actions-buttons/start-visit.test.tsx +9 -5
- package/src/actions-buttons/stop-visit.component.tsx +1 -1
- package/src/clinical-views/encounter-list/{encounter-list-tabs.component.tsx → encounter-list-tabs.extension.tsx} +10 -6
- package/src/clinical-views/encounter-list/tag.component.test.tsx +306 -0
- package/src/clinical-views/encounter-list/tag.component.tsx +27 -28
- package/src/clinical-views/utils/helpers.ts +2 -2
- package/src/config-schema.ts +0 -7
- package/src/index.ts +21 -22
- package/src/mark-patient-deceased/mark-patient-deceased-form.test.tsx +22 -11
- package/src/mark-patient-deceased/mark-patient-deceased-form.workspace.tsx +147 -138
- package/src/patient-banner-tags/{visit-attribute-tags.component.tsx → visit-attribute-tags.extension.tsx} +9 -4
- package/src/patient-chart/chart-review/dashboard-view.component.tsx +2 -2
- package/src/patient-chart/patient-chart.component.tsx +19 -36
- package/src/patient-chart/patient-chart.resources.ts +150 -0
- package/src/routes.json +17 -6
- package/src/visit/hooks/useDeleteVisit.test.tsx +39 -42
- package/src/visit/hooks/useDeleteVisit.tsx +33 -17
- package/src/visit/start-visit-button.component.tsx +2 -2
- package/src/visit/start-visit-button.test.tsx +2 -2
- package/src/visit/visit-action-items/edit-visit-details.component.tsx +29 -8
- package/src/visit/visit-form/base-visit-type.component.tsx +2 -2
- package/src/visit/visit-form/exported-visit-form.workspace.tsx +697 -0
- package/src/visit/visit-form/visit-attribute-type.component.tsx +2 -1
- package/src/visit/visit-form/visit-form.resource.ts +2 -1
- package/src/visit/visit-form/visit-form.test.tsx +28 -25
- package/src/visit/visit-form/visit-form.workspace.tsx +63 -643
- package/src/visit/visit-history-table/visit-actions-cell.component.tsx +3 -2
- package/src/visit/visit-history-table/visit-date-cell.component.tsx +1 -0
- package/src/visit/visit-history-table/visit-diagnoses-cell.component.tsx +1 -0
- package/src/visit/visit-history-table/visit-history-table.component.tsx +3 -2
- package/src/visit/visit-history-table/visit-type-cell.component.tsx +1 -0
- package/src/visit/visit-prompt/{delete-visit-dialog.component.tsx → delete-visit-dialog.modal.tsx} +10 -4
- package/src/visit/visit-prompt/delete-visit-dialog.test.tsx +21 -3
- package/src/visit/visit-prompt/{end-visit-dialog.component.tsx → end-visit-dialog.modal.tsx} +7 -1
- package/src/visit/visit-prompt/end-visit-dialog.test.tsx +20 -1
- package/src/visit/visit-prompt/{start-visit-dialog.component.tsx → start-visit-dialog.modal.tsx} +10 -4
- package/src/visit/visit-prompt/start-visit-dialog.test.tsx +3 -3
- package/src/visit/visits-widget/active-visit-buttons/active-visit-buttons.tsx +7 -6
- package/src/visit/visits-widget/current-visit-summary.extension.tsx +48 -0
- package/src/visit/visits-widget/current-visit-summary.test.tsx +45 -25
- package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.component.tsx +15 -37
- package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.resource.ts +0 -1
- package/src/visit/visits-widget/visit-context/retrospective-data-date-time-picker/retrospective-date-time-picker.component.tsx +6 -7
- package/src/visit/visits-widget/visit-context/{visit-context-header.component.tsx → visit-context-header.extension.tsx} +17 -15
- package/src/visit/visits-widget/visit-context/visit-context-header.test.tsx +35 -29
- package/src/visit/visits-widget/visit-context/visit-context-switcher.modal.tsx +15 -13
- package/src/visit/visits-widget/visit-context/visit-context-switcher.test.tsx +31 -9
- package/src/visit/visits-widget/visit-detail-overview.component.tsx +3 -2
- package/src/visit/visits-widget/visit-detail-overview.test.tsx +4 -4
- package/src/visit/visits-widget/visit.resource.tsx +1 -1
- package/translations/en.json +1 -2
- package/translations/fr.json +15 -15
- package/dist/1568.js +0 -2
- package/dist/1568.js.map +0 -1
- package/dist/2442.js +0 -1
- package/dist/2442.js.map +0 -1
- package/dist/2537.js +0 -1
- package/dist/2537.js.map +0 -1
- package/dist/276.js +0 -1
- package/dist/276.js.map +0 -1
- package/dist/3042.js +0 -1
- package/dist/3042.js.map +0 -1
- package/dist/3119.js +0 -1
- package/dist/3119.js.map +0 -1
- package/dist/3905.js +0 -1
- package/dist/3905.js.map +0 -1
- package/dist/4713.js +0 -1
- package/dist/4713.js.map +0 -1
- package/dist/4727.js.map +0 -1
- package/dist/5048.js +0 -1
- package/dist/5048.js.map +0 -1
- package/dist/6650.js +0 -2
- package/dist/6650.js.map +0 -1
- package/src/visit/visits-widget/current-visit-summary.component.tsx +0 -55
- /package/dist/{1568.js.LICENSE.txt → 1815.js.LICENSE.txt} +0 -0
- /package/dist/{6650.js.LICENSE.txt → 7816.js.LICENSE.txt} +0 -0
|
@@ -4,14 +4,15 @@ import styles from './visit-actions-cell.scss';
|
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
visit: Visit;
|
|
7
|
+
patient: fhir.Patient;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
const VisitActionsCell: React.FC<Props> = ({ visit }) => {
|
|
10
|
+
const VisitActionsCell: React.FC<Props> = ({ visit, patient }) => {
|
|
10
11
|
return (
|
|
11
12
|
<ExtensionSlot
|
|
12
13
|
name="visit-detail-overview-actions"
|
|
13
14
|
className={styles.visitActions}
|
|
14
|
-
state={{ patientUuid: visit.patient.uuid, visit, compact: true }}
|
|
15
|
+
state={{ patientUuid: visit.patient.uuid, patient, visit, compact: true }}
|
|
15
16
|
/>
|
|
16
17
|
);
|
|
17
18
|
};
|
|
@@ -27,12 +27,13 @@ import styles from './visit-history-table.scss';
|
|
|
27
27
|
|
|
28
28
|
interface VisitHistoryTableProps {
|
|
29
29
|
patientUuid: string;
|
|
30
|
+
patient: fhir.Patient;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* This show a list of visit histories in the visit tab in patient chart
|
|
34
35
|
*/
|
|
35
|
-
const VisitHistoryTable: React.FC<VisitHistoryTableProps> = ({ patientUuid }) => {
|
|
36
|
+
const VisitHistoryTable: React.FC<VisitHistoryTableProps> = ({ patientUuid, patient }) => {
|
|
36
37
|
const defaultPageSize = 10;
|
|
37
38
|
const [pageSize, setPageSize] = useState(defaultPageSize);
|
|
38
39
|
const pageSizes = [10, 20, 30, 40, 50];
|
|
@@ -54,7 +55,7 @@ const VisitHistoryTable: React.FC<VisitHistoryTableProps> = ({ patientUuid }) =>
|
|
|
54
55
|
const rowData = visits?.map((visit) => {
|
|
55
56
|
const row: Record<string, JSX.Element | string> = { id: visit.uuid };
|
|
56
57
|
for (const { key, CellComponent } of columns) {
|
|
57
|
-
row[key] = <CellComponent key={key} visit={visit} />;
|
|
58
|
+
row[key] = <CellComponent key={key} visit={visit} patient={patient} />;
|
|
58
59
|
}
|
|
59
60
|
return row;
|
|
60
61
|
});
|
package/src/visit/visit-prompt/{delete-visit-dialog.component.tsx → delete-visit-dialog.modal.tsx}
RENAMED
|
@@ -8,12 +8,18 @@ import styles from './start-visit-dialog.scss';
|
|
|
8
8
|
interface DeleteVisitDialogProps {
|
|
9
9
|
closeModal: () => void;
|
|
10
10
|
patientUuid: string;
|
|
11
|
-
|
|
11
|
+
activeVisit: Visit;
|
|
12
|
+
mutateActiveVisit: () => void;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
const DeleteVisitDialog: React.FC<DeleteVisitDialogProps> = ({
|
|
15
|
+
const DeleteVisitDialog: React.FC<DeleteVisitDialogProps> = ({
|
|
16
|
+
closeModal,
|
|
17
|
+
mutateActiveVisit,
|
|
18
|
+
patientUuid,
|
|
19
|
+
activeVisit,
|
|
20
|
+
}) => {
|
|
15
21
|
const { t } = useTranslation();
|
|
16
|
-
const { isDeletingVisit, initiateDeletingVisit } = useDeleteVisit(
|
|
22
|
+
const { isDeletingVisit, initiateDeletingVisit } = useDeleteVisit(activeVisit, mutateActiveVisit, closeModal);
|
|
17
23
|
|
|
18
24
|
return (
|
|
19
25
|
<div>
|
|
@@ -24,7 +30,7 @@ const DeleteVisitDialog: React.FC<DeleteVisitDialogProps> = ({ closeModal, patie
|
|
|
24
30
|
<ModalBody>
|
|
25
31
|
<p className={styles.body}>
|
|
26
32
|
{t('confirmDeleteVisitText', 'Deleting this {{visit}} will delete its associated encounters.', {
|
|
27
|
-
visit:
|
|
33
|
+
visit: activeVisit?.visitType?.display ?? t('visit', 'Visit'),
|
|
28
34
|
})}
|
|
29
35
|
</p>
|
|
30
36
|
</ModalBody>
|
|
@@ -4,11 +4,12 @@ import userEvent from '@testing-library/user-event';
|
|
|
4
4
|
import { mockCurrentVisit } from '__mocks__';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { mockPatient } from 'tools';
|
|
7
|
-
import DeleteVisitDialog from './delete-visit-dialog.
|
|
7
|
+
import DeleteVisitDialog from './delete-visit-dialog.modal';
|
|
8
8
|
|
|
9
9
|
const mockCloseModal = jest.fn();
|
|
10
10
|
const mockOpenmrsFetch = jest.mocked(openmrsFetch);
|
|
11
11
|
const mockShowSnackbar = jest.mocked(showSnackbar);
|
|
12
|
+
const mockActiveVisit = jest.fn();
|
|
12
13
|
|
|
13
14
|
describe('Delete visit', () => {
|
|
14
15
|
it('voids the visit and voids its associated encounters', async () => {
|
|
@@ -21,7 +22,14 @@ describe('Delete visit', () => {
|
|
|
21
22
|
|
|
22
23
|
mockOpenmrsFetch.mockResolvedValue(response as FetchResponse);
|
|
23
24
|
|
|
24
|
-
render(
|
|
25
|
+
render(
|
|
26
|
+
<DeleteVisitDialog
|
|
27
|
+
activeVisit={mockCurrentVisit}
|
|
28
|
+
mutateActiveVisit={mockActiveVisit}
|
|
29
|
+
closeModal={mockCloseModal}
|
|
30
|
+
patientUuid={mockPatient.id}
|
|
31
|
+
/>,
|
|
32
|
+
);
|
|
25
33
|
|
|
26
34
|
const cancelButton = screen.getByRole('button', { name: /^cancel$/i });
|
|
27
35
|
const deleteVisitButton = screen.getByRole('button', { name: /delete visit$/i });
|
|
@@ -46,6 +54,7 @@ describe('Delete visit', () => {
|
|
|
46
54
|
subtitle: 'Facility Visit deleted successfully',
|
|
47
55
|
}),
|
|
48
56
|
);
|
|
57
|
+
expect(mockActiveVisit).toHaveBeenCalledTimes(1);
|
|
49
58
|
});
|
|
50
59
|
|
|
51
60
|
it('displays an error notification if there was problem with deleting a visit', async () => {
|
|
@@ -53,7 +62,14 @@ describe('Delete visit', () => {
|
|
|
53
62
|
|
|
54
63
|
mockOpenmrsFetch.mockRejectedValueOnce({ message: 'Internal server error', status: 500 });
|
|
55
64
|
|
|
56
|
-
render(
|
|
65
|
+
render(
|
|
66
|
+
<DeleteVisitDialog
|
|
67
|
+
activeVisit={mockCurrentVisit}
|
|
68
|
+
mutateActiveVisit={mockActiveVisit}
|
|
69
|
+
closeModal={mockCloseModal}
|
|
70
|
+
patientUuid={mockPatient.id}
|
|
71
|
+
/>,
|
|
72
|
+
);
|
|
57
73
|
|
|
58
74
|
const cancelButton = screen.getByRole('button', { name: /^cancel$/i });
|
|
59
75
|
const deleteVisitButton = screen.getByRole('button', { name: /delete visit$/i });
|
|
@@ -74,5 +90,7 @@ describe('Delete visit', () => {
|
|
|
74
90
|
kind: 'error',
|
|
75
91
|
title: 'Error deleting visit',
|
|
76
92
|
});
|
|
93
|
+
|
|
94
|
+
expect(mockActiveVisit).toHaveBeenCalledTimes(1);
|
|
77
95
|
});
|
|
78
96
|
});
|
package/src/visit/visit-prompt/{end-visit-dialog.component.tsx → end-visit-dialog.modal.tsx}
RENAMED
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
|
|
4
4
|
import { showSnackbar, updateVisit, useVisit } from '@openmrs/esm-framework';
|
|
5
|
+
import { usePatientChartStore } from '@openmrs/esm-patient-common-lib';
|
|
5
6
|
import styles from './end-visit-dialog.scss';
|
|
6
7
|
|
|
7
8
|
interface EndVisitDialogProps {
|
|
@@ -13,10 +14,13 @@ interface EndVisitDialogProps {
|
|
|
13
14
|
* This modal shows up when user clicks on the "End visit" button in the action menu within the
|
|
14
15
|
* patient banner. It should only show when the patient has an active visit. See stop-visit.component.tsx
|
|
15
16
|
* for the button.
|
|
17
|
+
*
|
|
18
|
+
* This dialog uses the patient chart store and SHOULD only be mounted within the patient chart
|
|
16
19
|
*/
|
|
17
20
|
const EndVisitDialog: React.FC<EndVisitDialogProps> = ({ patientUuid, closeModal }) => {
|
|
18
21
|
const { t } = useTranslation();
|
|
19
22
|
const { activeVisit, mutate } = useVisit(patientUuid);
|
|
23
|
+
const { visitContext, setVisitContext } = usePatientChartStore(patientUuid);
|
|
20
24
|
|
|
21
25
|
const handleEndVisit = () => {
|
|
22
26
|
if (activeVisit) {
|
|
@@ -31,7 +35,9 @@ const EndVisitDialog: React.FC<EndVisitDialogProps> = ({ patientUuid, closeModal
|
|
|
31
35
|
mutate();
|
|
32
36
|
window.dispatchEvent(new CustomEvent('queue-entry-updated'));
|
|
33
37
|
closeModal();
|
|
34
|
-
|
|
38
|
+
if (visitContext?.uuid == activeVisit.uuid) {
|
|
39
|
+
setVisitContext(null, null);
|
|
40
|
+
}
|
|
35
41
|
showSnackbar({
|
|
36
42
|
isLowContrast: true,
|
|
37
43
|
kind: 'success',
|
|
@@ -3,7 +3,8 @@ import userEvent from '@testing-library/user-event';
|
|
|
3
3
|
import { screen, render } from '@testing-library/react';
|
|
4
4
|
import { showSnackbar, updateVisit, useVisit, type Visit, type FetchResponse } from '@openmrs/esm-framework';
|
|
5
5
|
import { mockCurrentVisit } from '__mocks__';
|
|
6
|
-
import EndVisitDialog from './end-visit-dialog.
|
|
6
|
+
import EndVisitDialog from './end-visit-dialog.modal';
|
|
7
|
+
import { usePatientChartStore } from '@openmrs/esm-patient-common-lib';
|
|
7
8
|
|
|
8
9
|
const endVisitPayload = {
|
|
9
10
|
stopDatetime: expect.any(Date),
|
|
@@ -15,6 +16,22 @@ const mockShowSnackbar = jest.mocked(showSnackbar);
|
|
|
15
16
|
const mockUseVisit = jest.mocked(useVisit);
|
|
16
17
|
const mockUpdateVisit = jest.mocked(updateVisit);
|
|
17
18
|
|
|
19
|
+
const mockUsePatientChartStore = jest.mocked(usePatientChartStore);
|
|
20
|
+
const mockSetVisitContext = jest.fn();
|
|
21
|
+
|
|
22
|
+
jest.mock('@openmrs/esm-patient-common-lib', () => ({
|
|
23
|
+
usePatientChartStore: jest.fn(),
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
mockUsePatientChartStore.mockReturnValue({
|
|
27
|
+
patientUuid: 'patient-123',
|
|
28
|
+
patient: null,
|
|
29
|
+
visitContext: mockCurrentVisit,
|
|
30
|
+
mutateVisitContext: jest.fn(),
|
|
31
|
+
setPatient: jest.fn(),
|
|
32
|
+
setVisitContext: mockSetVisitContext,
|
|
33
|
+
});
|
|
34
|
+
|
|
18
35
|
describe('End visit dialog', () => {
|
|
19
36
|
beforeEach(() => {
|
|
20
37
|
mockUseVisit.mockReturnValue({
|
|
@@ -66,6 +83,8 @@ describe('End visit dialog', () => {
|
|
|
66
83
|
kind: 'success',
|
|
67
84
|
title: 'Visit ended',
|
|
68
85
|
});
|
|
86
|
+
|
|
87
|
+
expect(mockSetVisitContext).toHaveBeenCalledTimes(1);
|
|
69
88
|
});
|
|
70
89
|
|
|
71
90
|
test('displays an error snackbar if there was a problem ending a visit', async () => {
|
package/src/visit/visit-prompt/{start-visit-dialog.component.tsx → start-visit-dialog.modal.tsx}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useCallback } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
|
|
4
|
-
import {
|
|
4
|
+
import { launchWorkspace2 } from '@openmrs/esm-framework';
|
|
5
5
|
import { launchPatientChartWithWorkspaceOpen } from '@openmrs/esm-patient-common-lib';
|
|
6
6
|
import styles from './start-visit-dialog.scss';
|
|
7
7
|
|
|
@@ -9,9 +9,15 @@ interface StartVisitDialogProps {
|
|
|
9
9
|
patientUuid: string;
|
|
10
10
|
closeModal: () => void;
|
|
11
11
|
launchPatientChart?: boolean;
|
|
12
|
+
onVisitStarted?: () => void;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
const StartVisitDialog: React.FC<StartVisitDialogProps> = ({
|
|
15
|
+
const StartVisitDialog: React.FC<StartVisitDialogProps> = ({
|
|
16
|
+
patientUuid,
|
|
17
|
+
closeModal,
|
|
18
|
+
launchPatientChart,
|
|
19
|
+
onVisitStarted,
|
|
20
|
+
}) => {
|
|
15
21
|
const { t } = useTranslation();
|
|
16
22
|
|
|
17
23
|
const handleStartNewVisit = useCallback(() => {
|
|
@@ -22,11 +28,11 @@ const StartVisitDialog: React.FC<StartVisitDialogProps> = ({ patientUuid, closeM
|
|
|
22
28
|
additionalProps: { openedFrom: 'patient-chart-start-visit' },
|
|
23
29
|
});
|
|
24
30
|
} else {
|
|
25
|
-
|
|
31
|
+
launchWorkspace2('start-visit-workspace-form', { openedFrom: 'patient-chart-start-visit', onVisitStarted });
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
closeModal();
|
|
29
|
-
}, [closeModal, patientUuid, launchPatientChart]);
|
|
35
|
+
}, [closeModal, patientUuid, launchPatientChart, onVisitStarted]);
|
|
30
36
|
|
|
31
37
|
const modalHeaderText = t('noActiveVisit', 'No active visit');
|
|
32
38
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import userEvent from '@testing-library/user-event';
|
|
4
|
-
import {
|
|
5
|
-
import StartVisitDialog from './start-visit-dialog.
|
|
4
|
+
import { launchWorkspace2 } from '@openmrs/esm-framework';
|
|
5
|
+
import StartVisitDialog from './start-visit-dialog.modal';
|
|
6
6
|
|
|
7
7
|
const defaultProps = {
|
|
8
8
|
patientUuid: 'some-uuid',
|
|
@@ -10,7 +10,7 @@ const defaultProps = {
|
|
|
10
10
|
visitType: null,
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
const mockLaunchWorkspace = jest.mocked(
|
|
13
|
+
const mockLaunchWorkspace = jest.mocked(launchWorkspace2);
|
|
14
14
|
|
|
15
15
|
describe('StartVisit', () => {
|
|
16
16
|
test('should launch start visit form', async () => {
|
|
@@ -20,13 +20,14 @@ const ActiveVisitActions: React.FC<ActiveVisitActionsInterface> = ({ visit, pati
|
|
|
20
20
|
const isTablet = layout === 'tablet';
|
|
21
21
|
const isMobile = layout === 'phone';
|
|
22
22
|
|
|
23
|
-
const launchAllergiesFormWorkspace = useLaunchWorkspaceRequiringVisit('patient-allergy-form-workspace');
|
|
24
|
-
const launchAppointmentsFormWorkspace = useLaunchWorkspaceRequiringVisit('appointments-form-workspace');
|
|
25
|
-
const launchClinicalFormsWorkspace = useLaunchWorkspaceRequiringVisit('clinical-forms-workspace');
|
|
26
|
-
const launchConditionsFormWorkspace = useLaunchWorkspaceRequiringVisit('conditions-form-workspace');
|
|
27
|
-
const launchOrderBasketFormWorkspace = useLaunchWorkspaceRequiringVisit('order-basket');
|
|
28
|
-
const launchVisitNotesFormWorkspace = useLaunchWorkspaceRequiringVisit('visit-notes-form-workspace');
|
|
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
29
|
const launchVitalsAndBiometricsFormWorkspace = useLaunchWorkspaceRequiringVisit(
|
|
30
|
+
patientUuid,
|
|
30
31
|
'patient-vitals-biometrics-form-workspace',
|
|
31
32
|
);
|
|
32
33
|
|
|
@@ -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;
|
|
@@ -1,34 +1,52 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import {
|
|
4
|
-
import { waitForLoadingToFinish } from 'tools';
|
|
5
|
-
import
|
|
3
|
+
import { getConfig } from '@openmrs/esm-framework';
|
|
4
|
+
import { mockPatient, waitForLoadingToFinish } from 'tools';
|
|
5
|
+
import { usePatientChartStore } from '@openmrs/esm-patient-common-lib';
|
|
6
|
+
import CurrentVisitSummary from './current-visit-summary.extension';
|
|
6
7
|
|
|
7
8
|
const mockGetConfig = jest.mocked(getConfig);
|
|
8
|
-
const
|
|
9
|
+
const mockUsePatientChartStore = jest.mocked(usePatientChartStore);
|
|
10
|
+
|
|
11
|
+
jest.mock('@openmrs/esm-patient-common-lib', () => ({
|
|
12
|
+
...jest.requireActual('@openmrs/esm-patient-common-lib'),
|
|
13
|
+
usePatientChartStore: jest.fn(),
|
|
14
|
+
}));
|
|
9
15
|
|
|
10
16
|
describe('CurrentVisitSummary', () => {
|
|
11
17
|
test('renders an empty state when there is no active visit', () => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
mutate: jest.fn(),
|
|
18
|
+
mockUsePatientChartStore.mockReturnValue({
|
|
19
|
+
patientUuid: mockPatient.id,
|
|
20
|
+
patient: mockPatient,
|
|
21
|
+
visitContext: null,
|
|
22
|
+
mutateVisitContext: null,
|
|
23
|
+
setPatient: jest.fn(),
|
|
24
|
+
setVisitContext: jest.fn(),
|
|
20
25
|
});
|
|
21
|
-
|
|
22
|
-
render(<CurrentVisitSummary patientUuid="some-uuid" />);
|
|
26
|
+
render(<CurrentVisitSummary patientUuid={mockPatient.id} />);
|
|
23
27
|
expect(screen.getByText(/current visit/i)).toBeInTheDocument();
|
|
24
|
-
expect(screen.getByText('There are no active
|
|
28
|
+
expect(screen.getByText('There are no active visits to display for this patient')).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('returns null when patientUuid does not match store patientUuid', () => {
|
|
32
|
+
mockUsePatientChartStore.mockReturnValue({
|
|
33
|
+
patientUuid: 'different-patient-id',
|
|
34
|
+
patient: mockPatient,
|
|
35
|
+
visitContext: null,
|
|
36
|
+
mutateVisitContext: null,
|
|
37
|
+
setPatient: jest.fn(),
|
|
38
|
+
setVisitContext: jest.fn(),
|
|
39
|
+
});
|
|
40
|
+
render(<CurrentVisitSummary patientUuid={mockPatient.id} />);
|
|
41
|
+
expect(screen.queryByText(/current visit/i)).not.toBeInTheDocument();
|
|
25
42
|
});
|
|
26
43
|
|
|
27
|
-
test('renders a visit summary when
|
|
44
|
+
test('renders a visit summary when visit context exists', async () => {
|
|
28
45
|
mockGetConfig.mockResolvedValue({ htmlFormEntryForms: [] });
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
46
|
+
mockUsePatientChartStore.mockReturnValue({
|
|
47
|
+
patientUuid: mockPatient.id,
|
|
48
|
+
patient: mockPatient,
|
|
49
|
+
visitContext: {
|
|
32
50
|
uuid: 'some-uuid',
|
|
33
51
|
display: 'Visit 1',
|
|
34
52
|
startDatetime: '2021-03-23T10:00:00.000+0300',
|
|
@@ -42,15 +60,17 @@ describe('CurrentVisitSummary', () => {
|
|
|
42
60
|
display: 'Visit Type 1',
|
|
43
61
|
},
|
|
44
62
|
encounters: [],
|
|
63
|
+
patient: {
|
|
64
|
+
uuid: mockPatient.id,
|
|
65
|
+
display: 'Test Patient',
|
|
66
|
+
},
|
|
45
67
|
},
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
isValidating: false,
|
|
50
|
-
mutate: jest.fn(),
|
|
68
|
+
mutateVisitContext: null,
|
|
69
|
+
setPatient: jest.fn(),
|
|
70
|
+
setVisitContext: jest.fn(),
|
|
51
71
|
});
|
|
52
72
|
|
|
53
|
-
render(<CurrentVisitSummary patientUuid=
|
|
73
|
+
render(<CurrentVisitSummary patientUuid={mockPatient.id} />);
|
|
54
74
|
|
|
55
75
|
await waitForLoadingToFinish();
|
|
56
76
|
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
import {
|
|
28
28
|
EditIcon,
|
|
29
29
|
isDesktop,
|
|
30
|
-
|
|
30
|
+
launchWorkspace2,
|
|
31
31
|
showModal,
|
|
32
32
|
showSnackbar,
|
|
33
33
|
TrashCanIcon,
|
|
@@ -35,16 +35,11 @@ import {
|
|
|
35
35
|
useLayoutType,
|
|
36
36
|
userHasAccess,
|
|
37
37
|
useSession,
|
|
38
|
-
useVisit,
|
|
39
38
|
type EncounterType,
|
|
40
39
|
ExtensionSlot,
|
|
41
40
|
useFeatureFlag,
|
|
42
41
|
} from '@openmrs/esm-framework';
|
|
43
|
-
import {
|
|
44
|
-
type HtmlFormEntryForm,
|
|
45
|
-
launchFormEntryOrHtmlForms,
|
|
46
|
-
invalidateVisitAndEncounterData,
|
|
47
|
-
} from '@openmrs/esm-patient-common-lib';
|
|
42
|
+
import { invalidateVisitAndEncounterData, usePatientChartStore } from '@openmrs/esm-patient-common-lib';
|
|
48
43
|
import { jsonSchemaResourceName } from '../../../../constants';
|
|
49
44
|
import {
|
|
50
45
|
deleteEncounter,
|
|
@@ -80,17 +75,12 @@ const EncountersTable: React.FC<EncountersTableProps> = ({
|
|
|
80
75
|
const pageSizes = [10, 20, 30, 40, 50];
|
|
81
76
|
const desktopLayout = isDesktop(useLayoutType());
|
|
82
77
|
const session = useSession();
|
|
83
|
-
const {
|
|
78
|
+
const { mutateVisitContext } = usePatientChartStore(patientUuid);
|
|
84
79
|
const { mutate } = useSWRConfig();
|
|
85
80
|
const responsiveSize = desktopLayout ? 'sm' : 'lg';
|
|
86
81
|
const { data: encounterTypes, isLoading: isLoadingEncounterTypes } = useEncounterTypes();
|
|
87
82
|
const enableEmbeddedFormView = useFeatureFlag('enable-embedded-form-view');
|
|
88
|
-
|
|
89
83
|
const { encounterEditableDuration, encounterEditableDurationOverridePrivileges } = useConfig<ChartConfig>();
|
|
90
|
-
const formsConfig: { htmlFormEntryForms: HtmlFormEntryForm[] } = useConfig({
|
|
91
|
-
externalModuleName: '@openmrs/esm-patient-forms-app',
|
|
92
|
-
});
|
|
93
|
-
const { htmlFormEntryForms } = formsConfig;
|
|
94
84
|
const paginatedMappedEncounters = useMemo(
|
|
95
85
|
() => (paginatedEncounters ?? []).map(mapEncounter).filter(Boolean),
|
|
96
86
|
[paginatedEncounters],
|
|
@@ -133,7 +123,7 @@ const EncountersTable: React.FC<EncountersTableProps> = ({
|
|
|
133
123
|
deleteEncounter(encounterUuid, abortController)
|
|
134
124
|
.then(() => {
|
|
135
125
|
// Update current visit data for critical components
|
|
136
|
-
|
|
126
|
+
mutateVisitContext?.();
|
|
137
127
|
|
|
138
128
|
// Also invalidate visit history and encounter tables since the encounter was deleted
|
|
139
129
|
invalidateVisitAndEncounterData(mutate, patientUuid);
|
|
@@ -160,7 +150,7 @@ const EncountersTable: React.FC<EncountersTableProps> = ({
|
|
|
160
150
|
},
|
|
161
151
|
});
|
|
162
152
|
},
|
|
163
|
-
[mutate,
|
|
153
|
+
[mutate, mutateVisitContext, patientUuid, t],
|
|
164
154
|
);
|
|
165
155
|
|
|
166
156
|
if (isLoadingEncounterTypes || isLoading) {
|
|
@@ -269,22 +259,16 @@ const EncountersTable: React.FC<EncountersTableProps> = ({
|
|
|
269
259
|
itemText={t('editThisEncounter', 'Edit this encounter')}
|
|
270
260
|
onClick={() => {
|
|
271
261
|
if (isVisitNoteEncounter(encounter)) {
|
|
272
|
-
|
|
262
|
+
launchWorkspace2('visit-notes-form-workspace', {
|
|
273
263
|
encounter,
|
|
274
264
|
formContext: 'editing',
|
|
275
265
|
patientUuid,
|
|
276
266
|
});
|
|
277
267
|
} else {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
encounter.visitUuid,
|
|
283
|
-
encounter.id,
|
|
284
|
-
encounter.visitTypeUuid,
|
|
285
|
-
encounter.visitStartDatetime,
|
|
286
|
-
encounter.visitStopDatetime,
|
|
287
|
-
);
|
|
268
|
+
launchWorkspace2('patient-form-entry-workspace', {
|
|
269
|
+
form: encounter.form,
|
|
270
|
+
encounterUuid: encounter.id,
|
|
271
|
+
});
|
|
288
272
|
}
|
|
289
273
|
}}
|
|
290
274
|
/>
|
|
@@ -326,22 +310,16 @@ const EncountersTable: React.FC<EncountersTableProps> = ({
|
|
|
326
310
|
kind="ghost"
|
|
327
311
|
onClick={() => {
|
|
328
312
|
if (isVisitNoteEncounter(encounter)) {
|
|
329
|
-
|
|
313
|
+
launchWorkspace2('visit-notes-form-workspace', {
|
|
330
314
|
encounter,
|
|
331
315
|
formContext: 'editing',
|
|
332
316
|
patientUuid,
|
|
333
317
|
});
|
|
334
318
|
} else {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
encounter.visitUuid,
|
|
340
|
-
encounter.id,
|
|
341
|
-
encounter.visitTypeUuid,
|
|
342
|
-
encounter.visitStartDatetime,
|
|
343
|
-
encounter.visitStopDatetime,
|
|
344
|
-
);
|
|
319
|
+
launchWorkspace2('patient-form-entry-workspace', {
|
|
320
|
+
form: encounter.form,
|
|
321
|
+
encounterUuid: encounter.id,
|
|
322
|
+
});
|
|
345
323
|
}
|
|
346
324
|
}}
|
|
347
325
|
renderIcon={(props: ComponentProps<typeof EditIcon>) => (
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { SelectItem, TimePickerSelect, TimePicker, Checkbox } from '@carbon/react';
|
|
2
|
-
import { OpenmrsDatePicker, ResponsiveWrapper, useFeatureFlag,
|
|
2
|
+
import { OpenmrsDatePicker, ResponsiveWrapper, useFeatureFlag, type Visit } from '@openmrs/esm-framework';
|
|
3
3
|
import React, { useEffect, useState } from 'react';
|
|
4
4
|
import { type Control, Controller, useForm } from 'react-hook-form';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import styles from './restrospective-date-time-picker.scss';
|
|
7
|
-
import { useSystemVisitSetting } from '@openmrs/esm-patient-common-lib';
|
|
8
7
|
|
|
9
8
|
type FormValues = {
|
|
10
9
|
retrospectiveDate: Date;
|
|
@@ -14,22 +13,22 @@ type FormValues = {
|
|
|
14
13
|
|
|
15
14
|
type RetrospectiveDateTimePickerProps = {
|
|
16
15
|
patientUuid: string;
|
|
16
|
+
visitContext: Visit;
|
|
17
17
|
control?: Control<FormValues>;
|
|
18
18
|
onChange?: (data: FormValues) => void;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const RetrospectiveDateTimePicker = ({
|
|
22
|
-
|
|
22
|
+
visitContext,
|
|
23
23
|
control: propControl,
|
|
24
24
|
onChange,
|
|
25
25
|
}: RetrospectiveDateTimePickerProps) => {
|
|
26
26
|
const { t } = useTranslation();
|
|
27
27
|
const isRdeEnabled = useFeatureFlag('rde');
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const minDate = currentVisit?.startDatetime;
|
|
29
|
+
const isActiveVisit = !Boolean(visitContext && visitContext.stopDatetime);
|
|
30
|
+
const maxDate = visitContext?.stopDatetime;
|
|
31
|
+
const minDate = visitContext?.startDatetime;
|
|
33
32
|
|
|
34
33
|
const [manuallyEnableDateTimePicker, setManuallyEnableDateTimePicker] = useState<boolean>(false);
|
|
35
34
|
|