@openmrs/esm-patient-programs-app 3.2.1-pre.201 → 3.2.1-pre.212
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 +36 -35
- package/dist/145.js +1 -1
- package/dist/186.js +1 -1
- package/dist/336.js +1 -1
- package/dist/435.js +1 -0
- package/dist/478.js +2 -0
- package/dist/478.js.LICENSE.txt +8 -0
- package/dist/574.js +1 -1
- package/dist/60.js +1 -0
- package/dist/692.js +1 -1
- package/dist/707.js +2 -0
- package/dist/{294.js.LICENSE.txt → 707.js.LICENSE.txt} +0 -9
- package/dist/963.js +2 -0
- package/dist/{252.js.LICENSE.txt → 963.js.LICENSE.txt} +0 -0
- package/dist/openmrs-esm-patient-programs-app.js +1 -1
- package/dist/openmrs-esm-patient-programs-app.js.buildmanifest.json +101 -77
- package/dist/openmrs-esm-patient-programs-app.old +1 -1
- package/package.json +4 -4
- package/src/config-schema.ts +12 -0
- package/src/index.ts +2 -1
- package/src/programs/program-action-button/program-action-button.component.tsx +47 -0
- package/src/programs/programs-detailed-summary.component.tsx +35 -22
- package/src/programs/programs-overview.component.tsx +41 -21
- package/src/programs/programs.resource.tsx +61 -6
- package/src/types/index.ts +10 -0
- package/translations/en.json +3 -0
- package/dist/252.js +0 -2
- package/dist/294.js +0 -2
- package/dist/45.js +0 -1
- package/dist/76.js +0 -1
|
@@ -7,7 +7,7 @@ import map from 'lodash-es/map';
|
|
|
7
7
|
import styles from './programs-detailed-summary.scss';
|
|
8
8
|
import { CardHeader, EmptyState, ErrorState, launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
|
|
9
9
|
import { useTranslation } from 'react-i18next';
|
|
10
|
-
import { useAvailablePrograms, useEnrollments } from './programs.resource';
|
|
10
|
+
import { useAvailablePrograms, useEnrollments, usePrograms } from './programs.resource';
|
|
11
11
|
import {
|
|
12
12
|
Button,
|
|
13
13
|
DataTable,
|
|
@@ -24,7 +24,11 @@ import {
|
|
|
24
24
|
DataTableRow,
|
|
25
25
|
InlineNotification,
|
|
26
26
|
} from 'carbon-components-react';
|
|
27
|
-
import { formatDate, formatDatetime } from '@openmrs/esm-framework';
|
|
27
|
+
import { formatDate, formatDatetime, useConfig, usePagination } from '@openmrs/esm-framework';
|
|
28
|
+
import { ConfigObject } from '../config-schema';
|
|
29
|
+
import { ConfigurableProgram } from '../types';
|
|
30
|
+
import capitalize from 'lodash-es/capitalize';
|
|
31
|
+
import ProgramActionButton from './program-action-button/program-action-button.component';
|
|
28
32
|
|
|
29
33
|
interface ProgramsDetailedSummaryProps {
|
|
30
34
|
patientUuid: string;
|
|
@@ -34,13 +38,18 @@ const ProgramsDetailedSummary: React.FC<ProgramsDetailedSummaryProps> = ({ patie
|
|
|
34
38
|
const { t } = useTranslation();
|
|
35
39
|
const displayText = t('programEnrollments', 'Program enrollments');
|
|
36
40
|
const headerTitle = t('carePrograms', 'Care Programs');
|
|
41
|
+
const config = useConfig() as ConfigObject;
|
|
42
|
+
const programsCount = 5;
|
|
43
|
+
const isConfigurable = config.customUrl ? true : false;
|
|
37
44
|
|
|
38
|
-
const {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
const { enrollments, isLoading, isError, isValidating, availablePrograms, eligiblePrograms, configurablePrograms } =
|
|
46
|
+
usePrograms(patientUuid);
|
|
47
|
+
|
|
48
|
+
const {
|
|
49
|
+
results: paginatedEnrollments,
|
|
50
|
+
goTo,
|
|
51
|
+
currentPage,
|
|
52
|
+
} = usePagination(isConfigurable ? configurablePrograms : enrollments ?? [], programsCount);
|
|
44
53
|
|
|
45
54
|
const tableHeaders: Array<DataTableHeader> = React.useMemo(
|
|
46
55
|
() => [
|
|
@@ -68,20 +77,24 @@ const ProgramsDetailedSummary: React.FC<ProgramsDetailedSummaryProps> = ({ patie
|
|
|
68
77
|
[t],
|
|
69
78
|
);
|
|
70
79
|
|
|
71
|
-
const tableRows
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
const tableRows = React.useMemo(() => {
|
|
81
|
+
return paginatedEnrollments?.map((enrollment: ConfigurableProgram) => ({
|
|
82
|
+
id: enrollment.uuid,
|
|
83
|
+
display: enrollment.display,
|
|
84
|
+
location: enrollment.location?.display,
|
|
85
|
+
dateEnrolled: enrollment.dateEnrolled ? formatDatetime(new Date(enrollment.dateEnrolled)) : '--',
|
|
86
|
+
status: isConfigurable
|
|
87
|
+
? capitalize(enrollment.enrollmentStatus)
|
|
88
|
+
: enrollment.dateCompleted
|
|
89
|
+
? `${t('completedOn', 'Completed On')} ${formatDate(new Date(enrollment.dateCompleted))}`
|
|
90
|
+
: t('active', 'Active'),
|
|
91
|
+
actions: isConfigurable ? (
|
|
92
|
+
<ProgramActionButton enrollment={enrollment} />
|
|
93
|
+
) : (
|
|
94
|
+
<ProgramEditButton programEnrollmentId={enrollment.uuid} />
|
|
95
|
+
),
|
|
96
|
+
}));
|
|
97
|
+
}, [isConfigurable, paginatedEnrollments, t]);
|
|
85
98
|
|
|
86
99
|
const launchProgramsForm = React.useCallback(() => launchPatientWorkspace('programs-form-workspace'), []);
|
|
87
100
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import Add16 from '@carbon/icons-react/es/add/16';
|
|
3
3
|
import styles from './programs-overview.scss';
|
|
4
|
-
import { formatDate, formatDatetime, usePagination } from '@openmrs/esm-framework';
|
|
4
|
+
import { formatDate, formatDatetime, useConfig, usePagination } from '@openmrs/esm-framework';
|
|
5
5
|
import {
|
|
6
6
|
DataTable,
|
|
7
7
|
DataTableSkeleton,
|
|
@@ -16,9 +16,6 @@ import {
|
|
|
16
16
|
TableRow,
|
|
17
17
|
InlineNotification,
|
|
18
18
|
} from 'carbon-components-react';
|
|
19
|
-
import filter from 'lodash-es/filter';
|
|
20
|
-
import includes from 'lodash-es/includes';
|
|
21
|
-
import map from 'lodash-es/map';
|
|
22
19
|
import {
|
|
23
20
|
CardHeader,
|
|
24
21
|
EmptyState,
|
|
@@ -27,7 +24,11 @@ import {
|
|
|
27
24
|
launchPatientWorkspace,
|
|
28
25
|
} from '@openmrs/esm-patient-common-lib';
|
|
29
26
|
import { useTranslation } from 'react-i18next';
|
|
30
|
-
import {
|
|
27
|
+
import { usePrograms } from './programs.resource';
|
|
28
|
+
import { ConfigObject } from '../config-schema';
|
|
29
|
+
import { capitalize } from 'lodash';
|
|
30
|
+
import ProgramActionButton from './program-action-button/program-action-button.component';
|
|
31
|
+
import { ConfigurableProgram } from '../types';
|
|
31
32
|
|
|
32
33
|
interface ProgramsOverviewProps {
|
|
33
34
|
basePath: string;
|
|
@@ -36,23 +37,30 @@ interface ProgramsOverviewProps {
|
|
|
36
37
|
|
|
37
38
|
const ProgramsOverview: React.FC<ProgramsOverviewProps> = ({ basePath, patientUuid }) => {
|
|
38
39
|
const programsCount = 5;
|
|
40
|
+
const config = useConfig() as ConfigObject;
|
|
39
41
|
const { t } = useTranslation();
|
|
40
42
|
const displayText = t('programs', 'Program enrollments');
|
|
41
43
|
const headerTitle = t('carePrograms', 'Care Programs');
|
|
42
44
|
const urlLabel = t('seeAll', 'See all');
|
|
43
45
|
const pageUrl = window.spaBase + basePath + '/programs';
|
|
46
|
+
const isConfigurable = config.customUrl ? true : false;
|
|
44
47
|
|
|
45
|
-
const {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
const {
|
|
49
|
+
enrollments,
|
|
50
|
+
isLoading,
|
|
51
|
+
isError,
|
|
52
|
+
activeEnrollments,
|
|
53
|
+
isValidating,
|
|
51
54
|
availablePrograms,
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
eligiblePrograms,
|
|
56
|
+
configurablePrograms,
|
|
57
|
+
} = usePrograms(patientUuid);
|
|
54
58
|
|
|
55
|
-
const {
|
|
59
|
+
const {
|
|
60
|
+
results: paginatedEnrollments,
|
|
61
|
+
goTo,
|
|
62
|
+
currentPage,
|
|
63
|
+
} = usePagination(isConfigurable ? configurablePrograms : enrollments ?? [], programsCount);
|
|
56
64
|
|
|
57
65
|
const launchProgramsForm = React.useCallback(() => launchPatientWorkspace('programs-form-workspace'), []);
|
|
58
66
|
|
|
@@ -73,23 +81,30 @@ const ProgramsOverview: React.FC<ProgramsOverviewProps> = ({ basePath, patientUu
|
|
|
73
81
|
key: 'status',
|
|
74
82
|
header: t('status', 'Status'),
|
|
75
83
|
},
|
|
84
|
+
{
|
|
85
|
+
key: 'actions',
|
|
86
|
+
header: t('actions', 'Actions'),
|
|
87
|
+
},
|
|
76
88
|
];
|
|
77
89
|
|
|
78
90
|
const tableRows = React.useMemo(() => {
|
|
79
|
-
return paginatedEnrollments?.map((enrollment) => ({
|
|
91
|
+
return paginatedEnrollments?.map((enrollment: ConfigurableProgram) => ({
|
|
80
92
|
id: enrollment.uuid,
|
|
81
93
|
display: enrollment.display,
|
|
82
94
|
location: enrollment.location?.display,
|
|
83
|
-
dateEnrolled: formatDatetime(new Date(enrollment.dateEnrolled)),
|
|
84
|
-
status:
|
|
95
|
+
dateEnrolled: enrollment.dateEnrolled ? formatDatetime(new Date(enrollment.dateEnrolled)) : '--',
|
|
96
|
+
status: isConfigurable
|
|
97
|
+
? capitalize(enrollment.enrollmentStatus)
|
|
98
|
+
: enrollment.dateCompleted
|
|
85
99
|
? `${t('completedOn', 'Completed On')} ${formatDate(new Date(enrollment.dateCompleted))}`
|
|
86
100
|
: t('active', 'Active'),
|
|
101
|
+
actions: <ProgramActionButton enrollment={enrollment} />,
|
|
87
102
|
}));
|
|
88
|
-
}, [paginatedEnrollments, t]);
|
|
103
|
+
}, [isConfigurable, paginatedEnrollments, t]);
|
|
89
104
|
|
|
90
105
|
if (isLoading) return <DataTableSkeleton role="progressbar" />;
|
|
91
106
|
if (isError) return <ErrorState error={isError} headerTitle={headerTitle} />;
|
|
92
|
-
if (activeEnrollments?.length) {
|
|
107
|
+
if (isConfigurable ? configurablePrograms.length : activeEnrollments?.length) {
|
|
93
108
|
return (
|
|
94
109
|
<div className={styles.widgetCard}>
|
|
95
110
|
<CardHeader title={headerTitle}>
|
|
@@ -114,7 +129,12 @@ const ProgramsOverview: React.FC<ProgramsOverviewProps> = ({ basePath, patientUu
|
|
|
114
129
|
title={t('fullyEnrolled', 'Enrolled in all programs')}
|
|
115
130
|
/>
|
|
116
131
|
)}
|
|
117
|
-
<DataTable
|
|
132
|
+
<DataTable
|
|
133
|
+
rows={tableRows}
|
|
134
|
+
headers={isConfigurable ? tableHeaders : tableHeaders.filter((header) => header.key !== 'actions')}
|
|
135
|
+
isSortable={true}
|
|
136
|
+
size="short"
|
|
137
|
+
>
|
|
118
138
|
{({ rows, headers, getHeaderProps, getTableProps }) => (
|
|
119
139
|
<Table {...getTableProps()} useZebraStyles>
|
|
120
140
|
<TableHead>
|
|
@@ -150,7 +170,7 @@ const ProgramsOverview: React.FC<ProgramsOverviewProps> = ({ basePath, patientUu
|
|
|
150
170
|
onPageNumberChange={({ page }) => goTo(page)}
|
|
151
171
|
pageNumber={currentPage}
|
|
152
172
|
pageSize={programsCount}
|
|
153
|
-
totalItems={
|
|
173
|
+
totalItems={isConfigurable ? configurablePrograms.length : enrollments?.length}
|
|
154
174
|
dashboardLinkUrl={pageUrl}
|
|
155
175
|
dashboardLinkLabel={urlLabel}
|
|
156
176
|
/>
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import useSWR from 'swr';
|
|
2
|
-
import { map } from 'rxjs/operators';
|
|
3
|
-
import { openmrsFetch, openmrsObservableFetch } from '@openmrs/esm-framework';
|
|
4
|
-
import { PatientProgram, Program, ProgramsFetchResponse } from '../types';
|
|
2
|
+
import { map as rxjsMap } from 'rxjs/operators';
|
|
3
|
+
import { openmrsFetch, openmrsObservableFetch, useConfig } from '@openmrs/esm-framework';
|
|
4
|
+
import { ConfigurableProgram, PatientProgram, Program, ProgramsFetchResponse } from '../types';
|
|
5
5
|
import uniqBy from 'lodash-es/uniqBy';
|
|
6
|
+
import filter from 'lodash-es/filter';
|
|
7
|
+
import includes from 'lodash-es/includes';
|
|
8
|
+
import map from 'lodash-es/map';
|
|
9
|
+
import { ConfigObject } from '../config-schema';
|
|
6
10
|
|
|
7
11
|
export const customRepresentation = `custom:(uuid,display,program,dateEnrolled,dateCompleted,location:(uuid,display))`;
|
|
8
12
|
|
|
@@ -17,30 +21,41 @@ export function useEnrollments(patientUuid: string) {
|
|
|
17
21
|
? data?.data.results.sort((a, b) => (b.dateEnrolled > a.dateEnrolled ? 1 : -1))
|
|
18
22
|
: null;
|
|
19
23
|
|
|
24
|
+
const activeEnrollments = formattedEnrollments?.filter((enrollment) => !enrollment.dateCompleted);
|
|
25
|
+
|
|
20
26
|
return {
|
|
21
27
|
data: data ? uniqBy(formattedEnrollments, (program) => program?.program?.uuid) : null,
|
|
22
28
|
isError: error,
|
|
23
29
|
isLoading: !data && !error,
|
|
24
30
|
isValidating,
|
|
31
|
+
activeEnrollments,
|
|
25
32
|
};
|
|
26
33
|
}
|
|
27
34
|
|
|
28
|
-
export function useAvailablePrograms() {
|
|
35
|
+
export function useAvailablePrograms(enrollments?: Array<PatientProgram>) {
|
|
29
36
|
const { data, error } = useSWR<{ data: { results: Array<Program> } }, Error>(
|
|
30
37
|
`/ws/rest/v1/program?v=custom:(uuid,display,allWorkflows,concept:(uuid,display))`,
|
|
31
38
|
openmrsFetch,
|
|
32
39
|
);
|
|
33
40
|
|
|
41
|
+
const availablePrograms = data?.data?.results ?? null;
|
|
42
|
+
|
|
43
|
+
const eligiblePrograms = filter(
|
|
44
|
+
availablePrograms,
|
|
45
|
+
(program) => !includes(map(enrollments, 'program.uuid'), program.uuid),
|
|
46
|
+
);
|
|
47
|
+
|
|
34
48
|
return {
|
|
35
|
-
data:
|
|
49
|
+
data: availablePrograms,
|
|
36
50
|
isError: error,
|
|
37
51
|
isLoading: !data && !error,
|
|
52
|
+
eligiblePrograms,
|
|
38
53
|
};
|
|
39
54
|
}
|
|
40
55
|
|
|
41
56
|
export function getPatientProgramByUuid(programUuid: string) {
|
|
42
57
|
return openmrsObservableFetch<PatientProgram>(`/ws/rest/v1/programenrollment/${programUuid}`).pipe(
|
|
43
|
-
|
|
58
|
+
rxjsMap(({ data }) => data),
|
|
44
59
|
);
|
|
45
60
|
}
|
|
46
61
|
|
|
@@ -73,3 +88,43 @@ export function updateProgramEnrollment(programEnrollmentUuid: string, payload,
|
|
|
73
88
|
signal: abortController.signal,
|
|
74
89
|
});
|
|
75
90
|
}
|
|
91
|
+
|
|
92
|
+
export const useConfigurableProgram = (patientUuid: string) => {
|
|
93
|
+
const { customUrl } = useConfig() as ConfigObject;
|
|
94
|
+
const { data, error } = useSWR<{ data: Array<ConfigurableProgram> }>(
|
|
95
|
+
customUrl ? `${customUrl}${patientUuid}` : null,
|
|
96
|
+
openmrsFetch,
|
|
97
|
+
);
|
|
98
|
+
const configurablePrograms = data?.data ?? [];
|
|
99
|
+
return {
|
|
100
|
+
configurablePrograms,
|
|
101
|
+
isLoading: !data && !error,
|
|
102
|
+
error: error,
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const usePrograms = (patientUuid: string) => {
|
|
107
|
+
const { customUrl } = useConfig() as ConfigObject;
|
|
108
|
+
const {
|
|
109
|
+
data: enrollments,
|
|
110
|
+
isError: enrollError,
|
|
111
|
+
isLoading: enrolLoading,
|
|
112
|
+
isValidating,
|
|
113
|
+
activeEnrollments,
|
|
114
|
+
} = useEnrollments(patientUuid);
|
|
115
|
+
const { data: availablePrograms, eligiblePrograms } = useAvailablePrograms(enrollments);
|
|
116
|
+
const { configurablePrograms, isLoading: configLoading, error: configError } = useConfigurableProgram(patientUuid);
|
|
117
|
+
|
|
118
|
+
const status = customUrl
|
|
119
|
+
? { isLoading: configLoading, isError: configError }
|
|
120
|
+
: { isLoading: enrolLoading, isError: enrollError };
|
|
121
|
+
return {
|
|
122
|
+
enrollments,
|
|
123
|
+
...status,
|
|
124
|
+
isValidating,
|
|
125
|
+
activeEnrollments,
|
|
126
|
+
availablePrograms,
|
|
127
|
+
eligiblePrograms,
|
|
128
|
+
configurablePrograms,
|
|
129
|
+
};
|
|
130
|
+
};
|
package/src/types/index.ts
CHANGED
|
@@ -99,3 +99,13 @@ export interface SessionData {
|
|
|
99
99
|
retired: false;
|
|
100
100
|
links: Links;
|
|
101
101
|
}
|
|
102
|
+
|
|
103
|
+
export interface ConfigurableProgram extends PatientProgram {
|
|
104
|
+
uuid: string;
|
|
105
|
+
display: string;
|
|
106
|
+
enrollmentFormUuid: string;
|
|
107
|
+
discontinuationFormUuid: string;
|
|
108
|
+
enrollmentStatus: string;
|
|
109
|
+
dateEnrolled: string;
|
|
110
|
+
dateCompleted: string;
|
|
111
|
+
}
|
package/translations/en.json
CHANGED
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"completedOn": "Completed on",
|
|
11
11
|
"dateCompleted": "Date completed",
|
|
12
12
|
"dateEnrolled": "Date enrolled",
|
|
13
|
+
"discontinue": "Discontinue",
|
|
14
|
+
"enroll": "Enroll",
|
|
15
|
+
"enrollment": "Enrollment",
|
|
13
16
|
"enrollmentLocation": "Enrollment location",
|
|
14
17
|
"enrollmentNowVisible": "It is now visible in the Programs table",
|
|
15
18
|
"enrollmentSaved": "Program enrollment saved",
|