Skip to content

Commit aaaa4d3

Browse files
authoredJul 27, 2021
MF-641: Completed Patient List Modal (#26)
* Completed Patient List Modal * Closing modal workflow fixed
1 parent f7cd597 commit aaaa4d3

File tree

4 files changed

+461
-374
lines changed

4 files changed

+461
-374
lines changed
 

‎packages/esm-patient-list-app/src/AddPatientToList/add-patient-to-list.scss

+33-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
.modalContent {
44
width: 100%;
5-
max-width: 678px;
65
background-color: #f4f4f4;
76
}
87

@@ -14,16 +13,43 @@
1413
padding: 0 1rem;
1514
}
1615

17-
.buttonSet {
18-
display: flex;
19-
justify-content: space-between;
20-
align-items: flex-start;
21-
}
22-
2316
.largeButtons {
2417
padding-bottom: 2rem;
2518
}
2619

2720
.checkbox {
2821
padding-bottom: 0.875rem;
22+
}
23+
24+
.pagination {
25+
width: 100%;
26+
overflow: hidden;
27+
}
28+
29+
.paginationContainer {
30+
display: flex;
31+
justify-content: space-between;
32+
align-items: center;
33+
position: relative;
34+
}
35+
36+
.itemsCountDisplay {
37+
position: absolute;
38+
top: 0;
39+
left: 1rem;
40+
height: 3rem;
41+
display: flex;
42+
align-items: center;
43+
color: #525252
44+
}
45+
46+
.pagination > div:first-child {
47+
visibility: hidden;
48+
width: 0;
49+
}
50+
51+
.buttonSet {
52+
display: flex;
53+
justify-content: space-between;
54+
align-items: flex-start;
2955
}

‎packages/esm-patient-list-app/src/AddPatientToList/index.tsx

+102-49
Original file line numberDiff line numberDiff line change
@@ -2,76 +2,120 @@ import React, { useState, useEffect, useMemo, useCallback } from 'react';
22
import { usePatientListData } from '../patientListData';
33
import { useTranslation } from 'react-i18next';
44
import { addPatientToList, getPatientListsForPatient } from '../patientListData/api';
5-
import { toOmrsIsoString } from '@openmrs/esm-framework';
5+
import { toOmrsIsoString, showToast, showModal, usePagination } from '@openmrs/esm-framework';
66
import Search from 'carbon-components-react/lib/components/Search';
77
import Button from 'carbon-components-react/lib/components/Button';
8+
import Pagination from 'carbon-components-react/lib/components/Pagination';
89
import Checkbox from 'carbon-components-react/lib/components/Checkbox';
910
import SkeletonText from 'carbon-components-react/es/components/SkeletonText';
1011
import styles from './add-patient-to-list.scss';
1112

13+
function getPatientUuidFromUrl(): string {
14+
const match = /\/patient\/([a-zA-Z0-9\-]+)\/?/.exec(location.pathname);
15+
return match && match[1];
16+
}
17+
1218
interface AddPatientProps {
13-
close: () => void;
14-
patientUuid: string;
19+
closeModal: () => void;
20+
}
21+
22+
interface PatientListProp {
23+
name: string;
24+
visible: boolean;
25+
selected: boolean;
1526
}
1627

17-
const AddPatient: React.FC<AddPatientProps> = ({ close, patientUuid }) => {
28+
type PatientListObj = Record<string, PatientListProp>;
29+
30+
const AddPatient: React.FC<AddPatientProps> = ({ closeModal }) => {
1831
const { t } = useTranslation();
1932
const [searchValue, setSearchValue] = useState('');
2033
const { loading, data } = usePatientListData();
21-
const [selectedLists, setSelectedList] = useState({});
34+
const [page, setPage] = useState(1);
35+
const [patientListsObj, setPatientListsObj] = useState<PatientListObj | null>(null);
36+
const patientUuid = getPatientUuidFromUrl();
2237

2338
useEffect(() => {
2439
if (data) {
25-
const lists = {};
40+
const lists: PatientListObj = {};
2641
data.map((patientList) => {
2742
lists[patientList.id] = {
2843
visible: true,
2944
selected: false,
45+
name: patientList?.display,
3046
};
3147
});
3248
getPatientListsForPatient(patientUuid).then((enrolledPatientLists) => {
3349
enrolledPatientLists.forEach((patientList) => {
3450
lists[patientList.cohort.uuid].visible = false;
3551
});
36-
setSelectedList(lists);
52+
setPatientListsObj(lists);
3753
});
3854
}
3955
}, [data]);
4056

41-
const searchResults = useMemo(() => {
42-
if (data) {
43-
if (searchValue && searchValue.trim() !== '') {
44-
const search = searchValue.toLowerCase();
45-
return data.filter((patientList) => patientList.display.toLowerCase().includes(search));
46-
} else {
47-
return data;
48-
}
49-
} else {
50-
return [];
51-
}
52-
}, [searchValue, data]);
53-
5457
const handleChange = useCallback((uuid, e) => {
55-
setSelectedList((selectedLists) => ({
56-
...selectedLists,
58+
setPatientListsObj((patientListsObj) => ({
59+
...patientListsObj,
5760
[uuid]: {
58-
...selectedLists[uuid],
61+
...patientListsObj[uuid],
5962
selected: e,
6063
},
6164
}));
6265
}, []);
6366

67+
const handleClose = useCallback(() => {
68+
closeModal();
69+
}, []);
70+
6471
const handleSubmit = useCallback(() => {
65-
Object.keys(selectedLists).forEach((patientListUuid) => {
66-
if (selectedLists[patientListUuid].selected) {
72+
Object.keys(patientListsObj).forEach((patientListUuid) => {
73+
if (patientListsObj[patientListUuid].selected) {
6774
addPatientToList({
6875
patient: patientUuid,
6976
cohort: patientListUuid,
7077
startDate: toOmrsIsoString(new Date()),
71-
});
78+
})
79+
.then(() =>
80+
showToast({
81+
title: 'Successfully added',
82+
kind: 'success',
83+
description: `Patient added to ${patientListsObj[patientListUuid].name} list successfully.`,
84+
}),
85+
)
86+
.catch(() =>
87+
showToast({
88+
title: 'Error',
89+
kind: 'error',
90+
description: `Patient not added to ${patientListsObj[patientListUuid].name} list.`,
91+
}),
92+
);
7293
}
7394
});
74-
}, [selectedLists]);
95+
handleClose();
96+
}, [patientListsObj]);
97+
98+
const searchResults = useMemo(() => {
99+
if (data && patientListsObj) {
100+
if (searchValue && searchValue.trim() !== '') {
101+
const search = searchValue.toLowerCase();
102+
setPage(1);
103+
return data.filter(
104+
(patientList) =>
105+
patientListsObj[patientList.id]?.visible && patientList.display.toLowerCase().includes(search),
106+
);
107+
} else {
108+
return data.filter((patientList) => patientListsObj[patientList.id]?.visible);
109+
}
110+
} else {
111+
return [];
112+
}
113+
}, [searchValue, data, patientListsObj]);
114+
const { results, goTo, currentPage, paginated } = usePagination(searchResults, 5);
115+
116+
useEffect(() => {
117+
goTo(page);
118+
}, [page]);
75119

76120
return (
77121
<div className={styles.modalContent}>
@@ -89,33 +133,25 @@ const AddPatient: React.FC<AddPatientProps> = ({ close, patientUuid }) => {
89133
onChange={({ target }) => {
90134
setSearchValue(target.value);
91135
}}
92-
onKeyPress={(e) => {
93-
if (e.key === 'Enter') {
94-
// trigger search or search on typing?
95-
}
96-
}}
97136
value={searchValue}
98137
/>
99138
</div>
100139
<div className={styles.patientListList}>
101140
<fieldset className="bx--fieldset">
102141
<p className="bx--label">Patient Lists</p>
103-
{!loading && searchResults ? (
104-
searchResults.length > 0 ? (
105-
searchResults.map(
106-
(patientList, ind) =>
107-
selectedLists[patientList.id]?.visible && (
108-
<div key={ind} className={styles.checkbox}>
109-
<Checkbox
110-
key={ind}
111-
onChange={(e) => handleChange(patientList.id, e)}
112-
checked={selectedLists[patientList.id]?.selected}
113-
labelText={patientList.display}
114-
id={patientList.id}
115-
/>
116-
</div>
117-
),
118-
)
142+
{!loading && patientListsObj && results ? (
143+
results.length > 0 ? (
144+
results.map((patientList, ind) => (
145+
<div key={ind} className={styles.checkbox}>
146+
<Checkbox
147+
key={ind}
148+
onChange={(e) => handleChange(patientList.id, e)}
149+
checked={patientListsObj[patientList.id]?.selected}
150+
labelText={patientList.display}
151+
id={patientList.id}
152+
/>
153+
</div>
154+
))
119155
) : (
120156
<p className={styles.bodyLong01}>No patient list found</p>
121157
)
@@ -124,10 +160,27 @@ const AddPatient: React.FC<AddPatientProps> = ({ close, patientUuid }) => {
124160
)}
125161
</fieldset>
126162
</div>
163+
{paginated && (
164+
<div className={styles.paginationContainer}>
165+
<span className={`${styles.itemsCountDisplay} ${styles.bodyLong01}`}>
166+
{results.length * currentPage} / {searchResults.length} items
167+
</span>
168+
<Pagination
169+
className={styles.pagination}
170+
forwardText=""
171+
backwardText=""
172+
page={currentPage}
173+
pageSize={5}
174+
pageSizes={[5]}
175+
totalItems={searchResults.length}
176+
onChange={({ page }) => setPage(page)}
177+
/>
178+
</div>
179+
)}
127180
<div className={styles.buttonSet}>
128181
<Button kind="ghost">{t('createNewPatientList', 'Create new patient list')}</Button>
129182
<div>
130-
<Button kind="secondary" className={styles.largeButtons} onClick={close}>
183+
<Button kind="secondary" className={styles.largeButtons} onClick={handleClose}>
131184
{t('cancel', 'Cancel')}
132185
</Button>
133186
<Button onClick={handleSubmit} className={styles.largeButtons}>

‎packages/esm-patient-list-app/src/patient-list-action.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ interface AddPastVisitOverflowMenuItemProps {}
77
const AddPastVisitOverflowMenuItem: React.FC<AddPastVisitOverflowMenuItemProps> = () => {
88
const { t } = useTranslation();
99
const openModal = React.useCallback(() => {
10-
showModal('add-patient-to-patient-list-modal', { patientUuid: '' });
10+
const dispose = showModal('add-patient-to-patient-list-modal', {
11+
closeModal: () => dispose(),
12+
});
1113
}, []);
1214

1315
return (

0 commit comments

Comments
 (0)
Failed to load comments.