@openmrs/esm-patient-programs-app 3.0.3 → 3.1.1-pre.1090
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/dist/119.js +2 -0
- package/dist/119.js.map +1 -0
- package/dist/169.js +2 -0
- package/dist/169.js.map +1 -0
- package/dist/206.js +3 -0
- package/dist/{314.openmrs-esm-patient-programs-app.js.LICENSE.txt → 206.js.LICENSE.txt} +0 -0
- package/dist/206.js.map +1 -0
- package/dist/313.js +2 -0
- package/dist/313.js.map +1 -0
- package/dist/339.js +3 -0
- package/dist/339.js.LICENSE.txt +1 -0
- package/dist/339.js.map +1 -0
- package/dist/363.js +2 -0
- package/dist/363.js.map +1 -0
- package/dist/364.js +3 -0
- package/dist/{545.openmrs-esm-patient-programs-app.js.LICENSE.txt → 364.js.LICENSE.txt} +0 -0
- package/dist/364.js.map +1 -0
- package/dist/373.js +2 -0
- package/dist/373.js.map +1 -0
- package/dist/402.js +2 -0
- package/dist/402.js.map +1 -0
- package/dist/440.js +2 -0
- package/dist/440.js.map +1 -0
- package/dist/47.js +3 -0
- package/dist/47.js.LICENSE.txt +20 -0
- package/dist/47.js.map +1 -0
- package/dist/539.js +2 -0
- package/dist/539.js.map +1 -0
- package/dist/574.js +1 -0
- package/dist/600.js +2 -0
- package/dist/600.js.map +1 -0
- package/dist/635.js +3 -0
- package/dist/635.js.LICENSE.txt +16 -0
- package/dist/635.js.map +1 -0
- package/dist/678.js +2 -0
- package/dist/678.js.map +1 -0
- package/dist/754.js +2 -0
- package/dist/754.js.map +1 -0
- package/dist/{757.openmrs-esm-patient-programs-app.js → 757.js} +0 -0
- package/dist/78.js +3 -0
- package/dist/{946.openmrs-esm-patient-programs-app.js.LICENSE.txt → 78.js.LICENSE.txt} +0 -0
- package/dist/78.js.map +1 -0
- package/dist/784.js +3 -0
- package/dist/784.js.LICENSE.txt +14 -0
- package/dist/784.js.map +1 -0
- package/dist/879.js +2 -0
- package/dist/879.js.map +1 -0
- package/dist/932.js +2 -0
- package/dist/932.js.map +1 -0
- package/dist/openmrs-esm-patient-programs-app.js +1 -2
- package/dist/openmrs-esm-patient-programs-app.js.buildmanifest.json +461 -54
- package/dist/openmrs-esm-patient-programs-app.js.map +1 -1
- package/package.json +4 -3
- package/src/index.ts +3 -5
- package/src/programs/programs-detailed-summary.component.tsx +37 -8
- package/src/programs/programs-detailed-summary.scss +0 -16
- package/src/programs/programs-detailed-summary.test.tsx +28 -1
- package/src/programs/programs-form.component.tsx +79 -89
- package/src/programs/programs-form.scss +42 -6
- package/src/programs/programs-form.test.tsx +5 -15
- package/src/programs/programs-overview.component.tsx +49 -15
- package/src/programs/programs-overview.scss +0 -16
- package/src/programs/programs-overview.test.tsx +2 -0
- package/src/programs/programs.component.tsx +157 -17
- package/src/programs/programs.resource.tsx +4 -2
- package/translations/en.json +4 -6
- package/dist/314.openmrs-esm-patient-programs-app.js +0 -3
- package/dist/314.openmrs-esm-patient-programs-app.js.map +0 -1
- package/dist/545.openmrs-esm-patient-programs-app.js +0 -3
- package/dist/545.openmrs-esm-patient-programs-app.js.map +0 -1
- package/dist/574.openmrs-esm-patient-programs-app.js +0 -1
- package/dist/639.openmrs-esm-patient-programs-app.js +0 -2
- package/dist/639.openmrs-esm-patient-programs-app.js.map +0 -1
- package/dist/839.openmrs-esm-patient-programs-app.js +0 -2
- package/dist/839.openmrs-esm-patient-programs-app.js.map +0 -1
- package/dist/943.openmrs-esm-patient-programs-app.js +0 -2
- package/dist/943.openmrs-esm-patient-programs-app.js.map +0 -1
- package/dist/946.openmrs-esm-patient-programs-app.js +0 -3
- package/dist/946.openmrs-esm-patient-programs-app.js.map +0 -1
- package/dist/openmrs-esm-patient-programs-app.js.LICENSE.txt +0 -5
- package/src/programs/program-record.component.tsx +0 -93
- package/src/programs/program-record.css +0 -42
- package/src/programs/program-record.test.outdated.tsx +0 -57
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-patient-programs-app",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1-pre.1090",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "Patient programs microfrontend for the OpenMRS SPA",
|
|
6
6
|
"browser": "dist/openmrs-esm-patient-programs-app.js",
|
|
@@ -36,13 +36,14 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@carbon/charts-react": "^0.49.4",
|
|
38
38
|
"@carbon/icons-react": "^10.18.0",
|
|
39
|
-
"@openmrs/esm-patient-common-lib": "^3.
|
|
39
|
+
"@openmrs/esm-patient-common-lib": "^3.1.1-pre.1090",
|
|
40
40
|
"carbon-components-react": "^7.25.0",
|
|
41
41
|
"d3": "^7.0.3",
|
|
42
42
|
"lodash-es": "^4.17.15"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@openmrs/esm-framework": "3.x",
|
|
46
|
+
"@openmrs/esm-patient-common-lib": "3.x",
|
|
46
47
|
"carbon-components": "10.x",
|
|
47
48
|
"carbon-icons": "7.x",
|
|
48
49
|
"dayjs": "1.x",
|
|
@@ -51,5 +52,5 @@
|
|
|
51
52
|
"react-router-dom": "5.x",
|
|
52
53
|
"rxjs": "6.x"
|
|
53
54
|
},
|
|
54
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "0e2864a46bd5ccf97dbb833c862eb38e6cdb5140"
|
|
55
56
|
}
|
package/src/index.ts
CHANGED
|
@@ -8,10 +8,6 @@ const backendDependencies = {
|
|
|
8
8
|
'webservices.rest': '^2.2.0',
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
const frontendDependencies = {
|
|
12
|
-
'@openmrs/esm-framework': process.env.FRAMEWORK_VERSION,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
11
|
function setupOpenMRS() {
|
|
16
12
|
const moduleName = '@openmrs/esm-patient-programs-app';
|
|
17
13
|
|
|
@@ -27,6 +23,7 @@ function setupOpenMRS() {
|
|
|
27
23
|
{
|
|
28
24
|
id: 'programs-overview-widget',
|
|
29
25
|
slot: 'patient-chart-summary-dashboard-slot',
|
|
26
|
+
order: 0,
|
|
30
27
|
load: getAsyncLifecycle(() => import('./programs/programs-overview.component'), options),
|
|
31
28
|
meta: {
|
|
32
29
|
columnSpan: 4,
|
|
@@ -43,6 +40,7 @@ function setupOpenMRS() {
|
|
|
43
40
|
{
|
|
44
41
|
id: 'programs-summary-dashboard',
|
|
45
42
|
slot: 'patient-chart-dashboard-slot',
|
|
43
|
+
order: 10,
|
|
46
44
|
load: getSyncLifecycle(createDashboardLink(dashboardMeta), options),
|
|
47
45
|
meta: dashboardMeta,
|
|
48
46
|
},
|
|
@@ -57,4 +55,4 @@ function setupOpenMRS() {
|
|
|
57
55
|
};
|
|
58
56
|
}
|
|
59
57
|
|
|
60
|
-
export { backendDependencies,
|
|
58
|
+
export { backendDependencies, importTranslation, setupOpenMRS };
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import dayjs from 'dayjs';
|
|
3
3
|
import Add16 from '@carbon/icons-react/es/add/16';
|
|
4
|
+
import filter from 'lodash-es/filter';
|
|
5
|
+
import includes from 'lodash-es/includes';
|
|
6
|
+
import map from 'lodash-es/map';
|
|
4
7
|
import styles from './programs-detailed-summary.scss';
|
|
5
|
-
import { EmptyState, ErrorState, launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
|
|
8
|
+
import { CardHeader, EmptyState, ErrorState, launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
|
|
6
9
|
import { useTranslation } from 'react-i18next';
|
|
7
|
-
import { useEnrollments } from './programs.resource';
|
|
10
|
+
import { useAvailablePrograms, useEnrollments } from './programs.resource';
|
|
8
11
|
import { useProgramsContext } from './programs.context';
|
|
9
12
|
import {
|
|
10
13
|
Button,
|
|
@@ -20,7 +23,9 @@ import {
|
|
|
20
23
|
TableRow,
|
|
21
24
|
DataTableHeader,
|
|
22
25
|
DataTableRow,
|
|
26
|
+
InlineNotification,
|
|
23
27
|
} from 'carbon-components-react';
|
|
28
|
+
import { formatDate, formatDatetime } from '@openmrs/esm-framework';
|
|
24
29
|
|
|
25
30
|
interface ProgramsDetailedSummaryProps {}
|
|
26
31
|
|
|
@@ -31,6 +36,11 @@ const ProgramsDetailedSummary: React.FC<ProgramsDetailedSummaryProps> = () => {
|
|
|
31
36
|
const headerTitle = t('carePrograms', 'Care Programs');
|
|
32
37
|
|
|
33
38
|
const { data: enrolledPrograms, isError, isLoading, isValidating } = useEnrollments(patientUuid);
|
|
39
|
+
const { data: availablePrograms } = useAvailablePrograms();
|
|
40
|
+
const eligiblePrograms = filter(
|
|
41
|
+
availablePrograms,
|
|
42
|
+
(program) => !includes(map(enrolledPrograms, 'program.uuid'), program.uuid),
|
|
43
|
+
);
|
|
34
44
|
|
|
35
45
|
const tableHeaders: Array<DataTableHeader> = React.useMemo(
|
|
36
46
|
() => [
|
|
@@ -38,6 +48,10 @@ const ProgramsDetailedSummary: React.FC<ProgramsDetailedSummaryProps> = () => {
|
|
|
38
48
|
key: 'display',
|
|
39
49
|
header: t('activePrograms', 'Active programs'),
|
|
40
50
|
},
|
|
51
|
+
{
|
|
52
|
+
key: 'location',
|
|
53
|
+
header: t('location', 'Location'),
|
|
54
|
+
},
|
|
41
55
|
{
|
|
42
56
|
key: 'dateEnrolled',
|
|
43
57
|
header: t('dateEnrolled', 'Date enrolled'),
|
|
@@ -55,9 +69,10 @@ const ProgramsDetailedSummary: React.FC<ProgramsDetailedSummaryProps> = () => {
|
|
|
55
69
|
return {
|
|
56
70
|
id: program.uuid,
|
|
57
71
|
display: program.display,
|
|
58
|
-
|
|
72
|
+
location: program.location?.display,
|
|
73
|
+
dateEnrolled: formatDatetime(new Date(program.dateEnrolled)),
|
|
59
74
|
status: program.dateCompleted
|
|
60
|
-
? `${t('completedOn', 'Completed On')} ${
|
|
75
|
+
? `${t('completedOn', 'Completed On')} ${formatDate(new Date(program.dateCompleted))}`
|
|
61
76
|
: t('active', 'Active'),
|
|
62
77
|
};
|
|
63
78
|
});
|
|
@@ -70,14 +85,28 @@ const ProgramsDetailedSummary: React.FC<ProgramsDetailedSummaryProps> = () => {
|
|
|
70
85
|
if (enrolledPrograms?.length) {
|
|
71
86
|
return (
|
|
72
87
|
<div className={styles.widgetCard}>
|
|
73
|
-
<
|
|
74
|
-
<h4 className={`${styles.productiveHeading03} ${styles.text02}`}>{headerTitle}</h4>
|
|
88
|
+
<CardHeader title={headerTitle}>
|
|
75
89
|
<span>{isValidating ? <InlineLoading /> : null}</span>
|
|
76
|
-
<Button
|
|
90
|
+
<Button
|
|
91
|
+
kind="ghost"
|
|
92
|
+
renderIcon={Add16}
|
|
93
|
+
iconDescription="Add programs"
|
|
94
|
+
onClick={launchProgramsForm}
|
|
95
|
+
disabled={availablePrograms?.length && eligiblePrograms?.length === 0}
|
|
96
|
+
>
|
|
77
97
|
{t('add', 'Add')}
|
|
78
98
|
</Button>
|
|
79
|
-
</
|
|
99
|
+
</CardHeader>
|
|
80
100
|
<TableContainer>
|
|
101
|
+
{availablePrograms?.length && eligiblePrograms?.length === 0 && (
|
|
102
|
+
<InlineNotification
|
|
103
|
+
style={{ minWidth: '100%', margin: '0rem', padding: '0rem' }}
|
|
104
|
+
kind={'info'}
|
|
105
|
+
lowContrast={true}
|
|
106
|
+
subtitle={t('noEligibleEnrollments', 'There are no more programs left to enroll this patient in')}
|
|
107
|
+
title={t('fullyEnrolled', 'Enrolled in all programs')}
|
|
108
|
+
/>
|
|
109
|
+
)}
|
|
81
110
|
<DataTable rows={tableRows} headers={tableHeaders} isSortable={true} size="short">
|
|
82
111
|
{({ rows, headers, getHeaderProps, getTableProps }) => (
|
|
83
112
|
<Table {...getTableProps()} useZebraStyles>
|
|
@@ -6,19 +6,3 @@
|
|
|
6
6
|
.widgetCard {
|
|
7
7
|
border: 1px solid $ui-03;
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
.programsHeader {
|
|
11
|
-
display: flex;
|
|
12
|
-
justify-content: space-between;
|
|
13
|
-
align-items: center;
|
|
14
|
-
padding: $spacing-04 0 $spacing-04 $spacing-05;
|
|
15
|
-
background-color: $ui-background;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.programsHeader > h4:after {
|
|
19
|
-
content: "";
|
|
20
|
-
display: block;
|
|
21
|
-
width: 2rem;
|
|
22
|
-
padding-top: 0.188rem;
|
|
23
|
-
border-bottom: 0.375rem solid $brand-teal-01;
|
|
24
|
-
}
|
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { screen } from '@testing-library/react';
|
|
3
3
|
import userEvent from '@testing-library/user-event';
|
|
4
|
-
import { openmrsFetch } from '@openmrs/esm-framework';
|
|
4
|
+
import { formatDate, formatDatetime, openmrsFetch, usePagination } from '@openmrs/esm-framework';
|
|
5
5
|
import { mockEnrolledProgramsResponse } from '../../../../__mocks__/programs.mock';
|
|
6
6
|
import { swrRender, waitForLoadingToFinish } from '../../../../tools/test-helpers';
|
|
7
7
|
import { launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
|
|
8
8
|
import ProgramsDetailedSummary from './programs-detailed-summary.component';
|
|
9
|
+
import dayjs from 'dayjs';
|
|
9
10
|
|
|
10
11
|
const mockOpenmrsFetch = openmrsFetch as jest.Mock;
|
|
12
|
+
const mockUsePagination = usePagination as jest.Mock;
|
|
13
|
+
const mockFormatDate = formatDate as jest.Mock;
|
|
14
|
+
const mockFormatDateTime = formatDatetime as jest.Mock;
|
|
15
|
+
|
|
16
|
+
jest.mock('@openmrs/esm-framework', () => {
|
|
17
|
+
const originalModule = jest.requireActual('@openmrs/esm-framework');
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
...originalModule,
|
|
21
|
+
formatDate: jest.fn(),
|
|
22
|
+
formatDatetime: jest.fn(),
|
|
23
|
+
openmrsFetch: jest.fn(),
|
|
24
|
+
usePagination: jest.fn().mockImplementation(() => ({
|
|
25
|
+
currentPage: 1,
|
|
26
|
+
goTo: () => {},
|
|
27
|
+
results: [],
|
|
28
|
+
})),
|
|
29
|
+
};
|
|
30
|
+
});
|
|
11
31
|
|
|
12
32
|
jest.mock('@openmrs/esm-patient-common-lib', () => {
|
|
13
33
|
const originalModule = jest.requireActual('@openmrs/esm-patient-common-lib');
|
|
@@ -56,6 +76,13 @@ describe('ProgramsDetailedSummary ', () => {
|
|
|
56
76
|
|
|
57
77
|
it("renders a detailed tabular summary of the patient's program enrollments", async () => {
|
|
58
78
|
mockOpenmrsFetch.mockReturnValueOnce({ data: { results: mockEnrolledProgramsResponse } });
|
|
79
|
+
mockUsePagination.mockImplementation(() => ({
|
|
80
|
+
currentPage: 1,
|
|
81
|
+
goTo: () => {},
|
|
82
|
+
results: mockEnrolledProgramsResponse.slice(0, 5),
|
|
83
|
+
}));
|
|
84
|
+
mockFormatDate.mockImplementation((dateTime) => dayjs(dateTime).format('MMM-YYYY'));
|
|
85
|
+
mockFormatDateTime.mockImplementation((dateTime) => dayjs(dateTime).format('DD-MMM-YYYY HH:mm'));
|
|
59
86
|
|
|
60
87
|
renderProgramsOverview();
|
|
61
88
|
|
|
@@ -6,23 +6,21 @@ import includes from 'lodash-es/includes';
|
|
|
6
6
|
import map from 'lodash-es/map';
|
|
7
7
|
import styles from './programs-form.scss';
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
|
+
import { createErrorHandler, showNotification, showToast, useSessionUser, useLocations } from '@openmrs/esm-framework';
|
|
9
10
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
Button,
|
|
12
|
+
DatePicker,
|
|
13
|
+
DatePickerInput,
|
|
14
|
+
Select,
|
|
15
|
+
SelectItem,
|
|
16
|
+
Form,
|
|
17
|
+
FormGroup,
|
|
18
|
+
ButtonSet,
|
|
19
|
+
} from 'carbon-components-react';
|
|
18
20
|
import { createProgramEnrollment, useAvailablePrograms, useEnrollments } from './programs.resource';
|
|
21
|
+
import { DefaultWorkspaceProps } from '@openmrs/esm-patient-common-lib';
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
patientUuid: string;
|
|
22
|
-
isTablet: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const ProgramsForm: React.FC<ProgramsFormProps> = ({ patientUuid, isTablet }) => {
|
|
23
|
+
const ProgramsForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace, patientUuid, isTablet }) => {
|
|
26
24
|
const { t } = useTranslation();
|
|
27
25
|
const session = useSessionUser();
|
|
28
26
|
const availableLocations = useLocations();
|
|
@@ -44,8 +42,6 @@ const ProgramsForm: React.FC<ProgramsFormProps> = ({ patientUuid, isTablet }) =>
|
|
|
44
42
|
setUserLocation(session?.sessionLocation?.uuid);
|
|
45
43
|
}
|
|
46
44
|
|
|
47
|
-
const closeWorkspace = React.useCallback(() => detach('patient-chart-workspace-slot', 'programs-form-workspace'), []);
|
|
48
|
-
|
|
49
45
|
const handleSubmit = React.useCallback(
|
|
50
46
|
(event: SyntheticEvent<HTMLFormElement>) => {
|
|
51
47
|
event.preventDefault();
|
|
@@ -95,89 +91,83 @@ const ProgramsForm: React.FC<ProgramsFormProps> = ({ patientUuid, isTablet }) =>
|
|
|
95
91
|
);
|
|
96
92
|
|
|
97
93
|
return (
|
|
98
|
-
<Form
|
|
99
|
-
<
|
|
100
|
-
<
|
|
94
|
+
<Form className={styles.form} onSubmit={handleSubmit}>
|
|
95
|
+
<div className={styles.formContainer}>
|
|
96
|
+
<FormGroup style={{ width: '50%' }} legendText={t('program', 'Program')}>
|
|
97
|
+
<div className={styles.selectContainer}>
|
|
98
|
+
<Select
|
|
99
|
+
id="program"
|
|
100
|
+
invalidText={t('required', 'Required')}
|
|
101
|
+
labelText=""
|
|
102
|
+
light={isTablet}
|
|
103
|
+
onChange={(event) => setSelectedProgram(event.target.value)}
|
|
104
|
+
>
|
|
105
|
+
{!selectedProgram ? <SelectItem text={t('chooseProgram', 'Choose a program')} value="" /> : null}
|
|
106
|
+
{eligiblePrograms?.length > 0 &&
|
|
107
|
+
eligiblePrograms.map((program) => (
|
|
108
|
+
<SelectItem key={program.uuid} text={program.display} value={program.uuid}>
|
|
109
|
+
{program.display}
|
|
110
|
+
</SelectItem>
|
|
111
|
+
))}
|
|
112
|
+
</Select>
|
|
113
|
+
</div>
|
|
114
|
+
</FormGroup>
|
|
115
|
+
<FormGroup legendText={t('dateEnrolled', 'Date enrolled')}>
|
|
116
|
+
<DatePicker
|
|
117
|
+
id="enrollmentDate"
|
|
118
|
+
datePickerType="single"
|
|
119
|
+
dateFormat="d/m/Y"
|
|
120
|
+
light={isTablet}
|
|
121
|
+
maxDate={new Date().toISOString()}
|
|
122
|
+
placeholder="dd/mm/yyyy"
|
|
123
|
+
onChange={([date]) => setEnrollmentDate(date)}
|
|
124
|
+
value={enrollmentDate}
|
|
125
|
+
>
|
|
126
|
+
<DatePickerInput id="enrollmentDateInput" labelText="" />
|
|
127
|
+
</DatePicker>
|
|
128
|
+
</FormGroup>
|
|
129
|
+
<FormGroup legendText={t('dateCompleted', 'Date completed')}>
|
|
130
|
+
<DatePicker
|
|
131
|
+
id="completionDate"
|
|
132
|
+
datePickerType="single"
|
|
133
|
+
dateFormat="d/m/Y"
|
|
134
|
+
light={isTablet}
|
|
135
|
+
minDate={new Date(enrollmentDate).toISOString()}
|
|
136
|
+
maxDate={new Date().toISOString()}
|
|
137
|
+
placeholder="dd/mm/yyyy"
|
|
138
|
+
onChange={([date]) => setCompletionDate(date)}
|
|
139
|
+
value={completionDate}
|
|
140
|
+
>
|
|
141
|
+
<DatePickerInput id="completionDateInput" labelText="" />
|
|
142
|
+
</DatePicker>
|
|
143
|
+
</FormGroup>
|
|
144
|
+
<FormGroup style={{ width: '50%' }} legendText={t('enrollmentLocation', 'Enrollment location')}>
|
|
101
145
|
<Select
|
|
102
|
-
id="
|
|
103
|
-
invalidText=
|
|
146
|
+
id="location"
|
|
147
|
+
invalidText="Required"
|
|
104
148
|
labelText=""
|
|
105
149
|
light={isTablet}
|
|
106
|
-
onChange={(event) =>
|
|
150
|
+
onChange={(event) => setUserLocation(event.target.value)}
|
|
151
|
+
value={userLocation}
|
|
107
152
|
>
|
|
108
|
-
{!
|
|
109
|
-
{
|
|
110
|
-
|
|
111
|
-
<SelectItem key={
|
|
112
|
-
{
|
|
153
|
+
{!userLocation ? <SelectItem text={t('chooseLocation', 'Choose a location')} value="" /> : null}
|
|
154
|
+
{availableLocations?.length > 0 &&
|
|
155
|
+
availableLocations.map((location) => (
|
|
156
|
+
<SelectItem key={location.uuid} text={location.display} value={location.uuid}>
|
|
157
|
+
{location.display}
|
|
113
158
|
</SelectItem>
|
|
114
159
|
))}
|
|
115
160
|
</Select>
|
|
116
|
-
</
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
title: t('error', 'Error'),
|
|
121
|
-
kind: 'error',
|
|
122
|
-
critical: true,
|
|
123
|
-
description: t('alreadyEnrolledText', 'This patient is already enrolled in all of the available programs'),
|
|
124
|
-
})}
|
|
125
|
-
</FormGroup>
|
|
126
|
-
<FormGroup legendText={t('dateEnrolled', 'Date enrolled')}>
|
|
127
|
-
<DatePicker
|
|
128
|
-
id="enrollmentDate"
|
|
129
|
-
datePickerType="single"
|
|
130
|
-
dateFormat="d/m/Y"
|
|
131
|
-
light={isTablet}
|
|
132
|
-
maxDate={new Date().toISOString()}
|
|
133
|
-
placeholder="dd/mm/yyyy"
|
|
134
|
-
onChange={([date]) => setEnrollmentDate(date)}
|
|
135
|
-
value={enrollmentDate}
|
|
136
|
-
>
|
|
137
|
-
<DatePickerInput id="enrollmentDateInput" labelText="" />
|
|
138
|
-
</DatePicker>
|
|
139
|
-
</FormGroup>
|
|
140
|
-
<FormGroup legendText={t('dateCompleted', 'Date completed')}>
|
|
141
|
-
<DatePicker
|
|
142
|
-
id="completionDate"
|
|
143
|
-
datePickerType="single"
|
|
144
|
-
dateFormat="d/m/Y"
|
|
145
|
-
light={isTablet}
|
|
146
|
-
minDate={new Date(enrollmentDate).toISOString()}
|
|
147
|
-
maxDate={new Date().toISOString()}
|
|
148
|
-
placeholder="dd/mm/yyyy"
|
|
149
|
-
onChange={([date]) => setCompletionDate(date)}
|
|
150
|
-
value={completionDate}
|
|
151
|
-
>
|
|
152
|
-
<DatePickerInput id="completionDateInput" labelText="" />
|
|
153
|
-
</DatePicker>
|
|
154
|
-
</FormGroup>
|
|
155
|
-
<FormGroup style={{ width: '50%' }} legendText={t('enrollmentLocation', 'Enrollment location')}>
|
|
156
|
-
<Select
|
|
157
|
-
id="location"
|
|
158
|
-
invalidText="Required"
|
|
159
|
-
labelText=""
|
|
160
|
-
light={isTablet}
|
|
161
|
-
onChange={(event) => setUserLocation(event.target.value)}
|
|
162
|
-
value={userLocation}
|
|
163
|
-
>
|
|
164
|
-
{!userLocation ? <SelectItem text={t('chooseLocation', 'Choose a location')} value="" /> : null}
|
|
165
|
-
{availableLocations?.length > 0 &&
|
|
166
|
-
availableLocations.map((location) => (
|
|
167
|
-
<SelectItem key={location.uuid} text={location.display} value={location.uuid}>
|
|
168
|
-
{location.display}
|
|
169
|
-
</SelectItem>
|
|
170
|
-
))}
|
|
171
|
-
</Select>
|
|
172
|
-
</FormGroup>
|
|
173
|
-
<div style={{ marginTop: '1.625rem' }}>
|
|
174
|
-
<Button style={{ width: '50%' }} kind="secondary" type="button" onClick={closeWorkspace}>
|
|
161
|
+
</FormGroup>
|
|
162
|
+
</div>
|
|
163
|
+
<ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
|
|
164
|
+
<Button className={styles.button} kind="secondary" onClick={closeWorkspace}>
|
|
175
165
|
{t('cancel', 'Cancel')}
|
|
176
166
|
</Button>
|
|
177
|
-
<Button
|
|
178
|
-
{t('
|
|
167
|
+
<Button className={styles.button} kind="primary" disabled={!selectedProgram} type="submit">
|
|
168
|
+
{t('saveAndClose', 'Save and close')}
|
|
179
169
|
</Button>
|
|
180
|
-
</
|
|
170
|
+
</ButtonSet>
|
|
181
171
|
</Form>
|
|
182
172
|
);
|
|
183
173
|
};
|
|
@@ -2,12 +2,6 @@
|
|
|
2
2
|
@import "~carbon-components/src/globals/scss/vars";
|
|
3
3
|
@import "~carbon-components/src/globals/scss/mixins";
|
|
4
4
|
|
|
5
|
-
.alreadyEnrolledText {
|
|
6
|
-
@include carbon--type-style("body-short-01");
|
|
7
|
-
color: $text-02;
|
|
8
|
-
min-height: 1rem;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
5
|
.selectContainer {
|
|
12
6
|
display: flex;
|
|
13
7
|
align-items: center;
|
|
@@ -17,4 +11,46 @@
|
|
|
17
11
|
margin-left: 1rem;
|
|
18
12
|
width: 2rem;
|
|
19
13
|
min-height: 2.5rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
.button {
|
|
18
|
+
height: 4rem;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-content: flex-start;
|
|
21
|
+
align-items: baseline;
|
|
22
|
+
min-width: 50%;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.tablet {
|
|
26
|
+
padding: 1.5rem 1rem;
|
|
27
|
+
background-color: $ui-02;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.desktop {
|
|
31
|
+
padding: 0rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.formContainer {
|
|
35
|
+
margin: 1rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.form {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
justify-content: space-between;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Desktop */
|
|
45
|
+
:global(.omrs-breakpoint-gt-tablet) {
|
|
46
|
+
.form {
|
|
47
|
+
height: calc(100vh - 6rem);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Tablet */
|
|
52
|
+
:global(.omrs-breakpoint-lt-desktop) {
|
|
53
|
+
.form {
|
|
54
|
+
height: calc(100vh - 3rem);
|
|
55
|
+
}
|
|
20
56
|
}
|
|
@@ -4,14 +4,7 @@ import * as SWR from 'swr';
|
|
|
4
4
|
import { throwError } from 'rxjs';
|
|
5
5
|
import { of } from 'rxjs/internal/observable/of';
|
|
6
6
|
import { fireEvent, render, screen } from '@testing-library/react';
|
|
7
|
-
import {
|
|
8
|
-
createErrorHandler,
|
|
9
|
-
detach,
|
|
10
|
-
openmrsFetch,
|
|
11
|
-
showNotification,
|
|
12
|
-
showToast,
|
|
13
|
-
useLocations,
|
|
14
|
-
} from '@openmrs/esm-framework';
|
|
7
|
+
import { createErrorHandler, openmrsFetch, showNotification, showToast, useLocations } from '@openmrs/esm-framework';
|
|
15
8
|
import { mockPatient } from '../../../../__mocks__/patient.mock';
|
|
16
9
|
import {
|
|
17
10
|
mockCareProgramsResponse,
|
|
@@ -24,15 +17,14 @@ import ProgramsForm from './programs-form.component';
|
|
|
24
17
|
const testProps = {
|
|
25
18
|
patientUuid: mockPatient.id,
|
|
26
19
|
isTablet: false,
|
|
20
|
+
closeWorkspace: jest.fn(),
|
|
27
21
|
};
|
|
28
22
|
|
|
29
23
|
const mockCreateErrorHandler = createErrorHandler as jest.Mock;
|
|
30
24
|
const mockCreateProgramEnrollment = createProgramEnrollment as jest.Mock;
|
|
31
|
-
const mockDetach = detach as jest.Mock;
|
|
32
25
|
const mockOpenmrsFetch = openmrsFetch as jest.Mock;
|
|
33
26
|
const mockShowNotification = showNotification as jest.Mock;
|
|
34
27
|
const mockShowToast = showToast as jest.Mock;
|
|
35
|
-
const mockUseLocations = useLocations as jest.Mock;
|
|
36
28
|
|
|
37
29
|
jest.mock('@openmrs/esm-framework', () => {
|
|
38
30
|
const originalModule = jest.requireActual('@openmrs/esm-framework');
|
|
@@ -40,7 +32,6 @@ jest.mock('@openmrs/esm-framework', () => {
|
|
|
40
32
|
return {
|
|
41
33
|
...originalModule,
|
|
42
34
|
createErrorHandler: jest.fn(),
|
|
43
|
-
detach: jest.fn(),
|
|
44
35
|
showNotification: jest.fn(),
|
|
45
36
|
showToast: jest.fn(),
|
|
46
37
|
useLocations: jest.fn().mockImplementation(() => mockLocationsResponse),
|
|
@@ -78,7 +69,7 @@ describe('ProgramsForm: ', () => {
|
|
|
78
69
|
expect(screen.getByRole('option', { name: /Laboratory/i })).toBeInTheDocument();
|
|
79
70
|
|
|
80
71
|
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
|
81
|
-
const enrollButton = screen.getByRole('button', { name: /
|
|
72
|
+
const enrollButton = screen.getByRole('button', { name: /save and close/i });
|
|
82
73
|
expect(cancelButton).toBeInTheDocument();
|
|
83
74
|
expect(enrollButton).toBeInTheDocument();
|
|
84
75
|
expect(enrollButton).toBeDisabled();
|
|
@@ -90,8 +81,7 @@ describe('ProgramsForm: ', () => {
|
|
|
90
81
|
const cancelButton = screen.getByRole('button', { name: /Cancel/i });
|
|
91
82
|
fireEvent.click(cancelButton);
|
|
92
83
|
|
|
93
|
-
expect(
|
|
94
|
-
expect(mockDetach).toHaveBeenCalledWith('patient-chart-workspace-slot', 'programs-form-workspace');
|
|
84
|
+
expect(testProps.closeWorkspace).toHaveBeenCalledTimes(1);
|
|
95
85
|
});
|
|
96
86
|
|
|
97
87
|
it('renders a light background for date inputs in the tablet viewport ', () => {
|
|
@@ -116,7 +106,7 @@ describe('ProgramsForm: ', () => {
|
|
|
116
106
|
renderProgramsForm();
|
|
117
107
|
|
|
118
108
|
cancelButton = screen.getByRole('button', { name: /cancel/i });
|
|
119
|
-
enrollButton = screen.getByRole('button', { name: /
|
|
109
|
+
enrollButton = screen.getByRole('button', { name: /save and close/i });
|
|
120
110
|
enrollmentDateInput = screen.getAllByRole('textbox', { name: '' })[0];
|
|
121
111
|
selectLocationInput = screen.getAllByRole('combobox', { name: '' })[1];
|
|
122
112
|
selectProgramInput = screen.getAllByRole('combobox', { name: '' })[0];
|