@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.
@@ -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 { data: enrollments, isError, isLoading, isValidating } = useEnrollments(patientUuid);
39
- const { data: availablePrograms } = useAvailablePrograms();
40
- const eligiblePrograms = filter(
41
- availablePrograms,
42
- (program) => !includes(map(enrollments, 'program.uuid'), program.uuid),
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: Array<DataTableRow> = React.useMemo(() => {
72
- return enrollments?.map((program) => {
73
- return {
74
- id: program.uuid,
75
- display: program.display,
76
- location: program.location?.display,
77
- dateEnrolled: formatDatetime(new Date(program.dateEnrolled)),
78
- status: program.dateCompleted
79
- ? `${t('completedOn', 'Completed On')} ${formatDate(new Date(program.dateCompleted))}`
80
- : t('active', 'Active'),
81
- actions: <ProgramEditButton programEnrollmentId={program.uuid} />,
82
- };
83
- });
84
- }, [enrollments, t]);
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 { useAvailablePrograms, useEnrollments } from './programs.resource';
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 { data: enrollments, isError, isLoading, isValidating } = useEnrollments(patientUuid);
46
- const activeEnrollments = enrollments?.filter((enrollment) => !enrollment.dateCompleted);
47
-
48
- const { data: availablePrograms } = useAvailablePrograms();
49
-
50
- const eligiblePrograms = filter(
48
+ const {
49
+ enrollments,
50
+ isLoading,
51
+ isError,
52
+ activeEnrollments,
53
+ isValidating,
51
54
  availablePrograms,
52
- (program) => !includes(map(enrollments, 'program.uuid'), program.uuid),
53
- );
55
+ eligiblePrograms,
56
+ configurablePrograms,
57
+ } = usePrograms(patientUuid);
54
58
 
55
- const { results: paginatedEnrollments, goTo, currentPage } = usePagination(enrollments ?? [], programsCount);
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: enrollment.dateCompleted
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 rows={tableRows} headers={tableHeaders} isSortable={true} size="short">
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={enrollments.length}
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: data?.data?.results?.length ? data.data.results : null,
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
- map(({ data }) => data),
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
+ };
@@ -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
+ }
@@ -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",