@openmrs/esm-fast-data-entry-app 1.0.1-pre.87 → 1.0.1-pre.93
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/132.js +1 -1
- package/dist/153.js +1 -0
- package/dist/327.js +1 -1
- package/dist/574.js +1 -1
- package/dist/617.js +1 -1
- package/dist/804.js +1 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +15 -15
- package/package.json +1 -1
- package/src/add-group-modal/AddGroupModal.tsx +74 -48
- package/src/group-form-entry-workflow/SessionDetailsForm.tsx +100 -91
- package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +63 -24
- package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +30 -3
- package/src/hooks/useGetPatients.ts +34 -0
- package/src/hooks/usePostEndpoint.ts +7 -1
- package/translations/en.json +3 -1
- package/dist/168.js +0 -1
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
2
8
|
import {
|
|
3
9
|
ComposedModal,
|
|
4
10
|
Button,
|
|
@@ -7,9 +13,8 @@ import {
|
|
|
7
13
|
ModalBody,
|
|
8
14
|
TextInput,
|
|
9
15
|
FormLabel,
|
|
10
|
-
Loading,
|
|
11
16
|
} from "@carbon/react";
|
|
12
|
-
import {
|
|
17
|
+
import { TrashCan } from "@carbon/react/icons";
|
|
13
18
|
import { useTranslation } from "react-i18next";
|
|
14
19
|
import { ExtensionSlot, showToast } from "@openmrs/esm-framework";
|
|
15
20
|
import styles from "./styles.scss";
|
|
@@ -18,23 +23,49 @@ import { usePostCohort } from "../hooks";
|
|
|
18
23
|
|
|
19
24
|
const MemExtension = React.memo(ExtensionSlot);
|
|
20
25
|
|
|
26
|
+
const buildPatientDisplay = (patient) => {
|
|
27
|
+
const givenName = patient?.name?.[0]?.given?.[0];
|
|
28
|
+
const familyName = patient?.name?.[0]?.family;
|
|
29
|
+
const identifier = patient?.identifier?.[0]?.value;
|
|
30
|
+
|
|
31
|
+
let display = identifier ? identifier + " - " : "";
|
|
32
|
+
display += (givenName || "") + " " + (familyName || "");
|
|
33
|
+
return display.replace(/\s+/g, " ");
|
|
34
|
+
};
|
|
35
|
+
|
|
21
36
|
const PatientRow = ({ patient, removePatient }) => {
|
|
22
37
|
const { t } = useTranslation();
|
|
38
|
+
const onClickHandler = useCallback(
|
|
39
|
+
() => removePatient(patient?.uuid),
|
|
40
|
+
[patient, removePatient]
|
|
41
|
+
);
|
|
42
|
+
const patientDisplay = useMemo(() => {
|
|
43
|
+
if (!patient) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (patient.display) {
|
|
48
|
+
return patient.display;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return buildPatientDisplay(patient);
|
|
52
|
+
}, [patient]);
|
|
53
|
+
|
|
23
54
|
return (
|
|
24
|
-
<li key={patient
|
|
55
|
+
<li key={patient?.uuid} className={styles.patientRow}>
|
|
25
56
|
<span>
|
|
26
57
|
<Button
|
|
27
58
|
kind="tertiary"
|
|
28
59
|
size="sm"
|
|
29
60
|
hasIconOnly
|
|
30
|
-
onClick={
|
|
61
|
+
onClick={onClickHandler}
|
|
31
62
|
renderIcon={TrashCan}
|
|
32
63
|
tooltipAlignment="start"
|
|
33
64
|
tooltipPosition="top"
|
|
34
65
|
iconDescription={t("remove", "Remove")}
|
|
35
66
|
/>
|
|
36
67
|
</span>
|
|
37
|
-
<span className={styles.patientName}>{
|
|
68
|
+
<span className={styles.patientName}>{patientDisplay}</span>
|
|
38
69
|
</li>
|
|
39
70
|
);
|
|
40
71
|
};
|
|
@@ -108,18 +139,21 @@ const NewGroupForm = (props) => {
|
|
|
108
139
|
);
|
|
109
140
|
};
|
|
110
141
|
|
|
111
|
-
const AddGroupModal = (
|
|
142
|
+
const AddGroupModal = ({
|
|
143
|
+
patients = undefined,
|
|
144
|
+
isCreate = undefined,
|
|
145
|
+
groupName = "",
|
|
146
|
+
cohortUuid = undefined,
|
|
147
|
+
isOpen,
|
|
148
|
+
handleCancel,
|
|
149
|
+
onPostSubmit,
|
|
150
|
+
}) => {
|
|
112
151
|
const { setGroup } = useContext(GroupFormWorkflowContext);
|
|
113
152
|
const { t } = useTranslation();
|
|
114
|
-
const [open, setOpen] = useState(false);
|
|
115
153
|
const [errors, setErrors] = useState({});
|
|
116
|
-
const [name, setName] = useState(
|
|
117
|
-
const [patientList, setPatientList] = useState([]);
|
|
118
|
-
const { post, result,
|
|
119
|
-
|
|
120
|
-
const handleCancel = () => {
|
|
121
|
-
setOpen(false);
|
|
122
|
-
};
|
|
154
|
+
const [name, setName] = useState(groupName);
|
|
155
|
+
const [patientList, setPatientList] = useState(patients || []);
|
|
156
|
+
const { post, result, error } = usePostCohort();
|
|
123
157
|
|
|
124
158
|
const removePatient = useCallback(
|
|
125
159
|
(patientUuid: string) =>
|
|
@@ -174,9 +208,13 @@ const AddGroupModal = () => {
|
|
|
174
208
|
const handleSubmit = () => {
|
|
175
209
|
if (validate()) {
|
|
176
210
|
post({
|
|
211
|
+
uuid: cohortUuid,
|
|
177
212
|
name: name,
|
|
178
213
|
cohortMembers: patientList.map((p) => ({ patient: p.uuid })),
|
|
179
214
|
});
|
|
215
|
+
if (onPostSubmit) {
|
|
216
|
+
onPostSubmit();
|
|
217
|
+
}
|
|
180
218
|
}
|
|
181
219
|
};
|
|
182
220
|
|
|
@@ -198,7 +236,7 @@ const AddGroupModal = () => {
|
|
|
198
236
|
title: t("postError", "POST Error"),
|
|
199
237
|
description:
|
|
200
238
|
error.message ??
|
|
201
|
-
t("unknownPostError", "An unknown error
|
|
239
|
+
t("unknownPostError", "An unknown error occurred while saving data"),
|
|
202
240
|
});
|
|
203
241
|
if (error.fieldErrors) {
|
|
204
242
|
setErrors(
|
|
@@ -215,43 +253,31 @@ const AddGroupModal = () => {
|
|
|
215
253
|
|
|
216
254
|
return (
|
|
217
255
|
<div className={styles.modal}>
|
|
218
|
-
<
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
</Button>
|
|
225
|
-
<ComposedModal open={open} onClose={() => setOpen(false)}>
|
|
226
|
-
<ModalHeader>{t("createNewGroup", "Create New Group")}</ModalHeader>
|
|
256
|
+
<ComposedModal open={isOpen} onClose={handleCancel}>
|
|
257
|
+
<ModalHeader>
|
|
258
|
+
{isCreate
|
|
259
|
+
? t("createNewGroup", "Create New Group")
|
|
260
|
+
: t("editGroup", "Edit Group")}
|
|
261
|
+
</ModalHeader>
|
|
227
262
|
<ModalBody>
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
setName,
|
|
240
|
-
patientList,
|
|
241
|
-
updatePatientList,
|
|
242
|
-
errors,
|
|
243
|
-
validate,
|
|
244
|
-
removePatient,
|
|
245
|
-
}}
|
|
246
|
-
/>
|
|
247
|
-
)}
|
|
263
|
+
<NewGroupForm
|
|
264
|
+
{...{
|
|
265
|
+
name,
|
|
266
|
+
setName,
|
|
267
|
+
patientList,
|
|
268
|
+
updatePatientList,
|
|
269
|
+
errors,
|
|
270
|
+
validate,
|
|
271
|
+
removePatient,
|
|
272
|
+
}}
|
|
273
|
+
/>
|
|
248
274
|
</ModalBody>
|
|
249
275
|
<ModalFooter>
|
|
250
|
-
<Button kind="secondary" onClick={handleCancel}
|
|
276
|
+
<Button kind="secondary" onClick={handleCancel}>
|
|
251
277
|
{t("cancel", "Cancel")}
|
|
252
278
|
</Button>
|
|
253
|
-
<Button kind="primary" onClick={handleSubmit}
|
|
254
|
-
{t("createGroup", "Create Group")}
|
|
279
|
+
<Button kind="primary" onClick={handleSubmit}>
|
|
280
|
+
{isCreate ? t("createGroup", "Create Group") : t("save", "Save")}
|
|
255
281
|
</Button>
|
|
256
282
|
</ModalFooter>
|
|
257
283
|
</ComposedModal>
|
|
@@ -6,11 +6,13 @@ import {
|
|
|
6
6
|
DatePicker,
|
|
7
7
|
DatePickerInput,
|
|
8
8
|
} from "@carbon/react";
|
|
9
|
-
import React from "react";
|
|
9
|
+
import React, { useContext } from "react";
|
|
10
10
|
import styles from "./styles.scss";
|
|
11
11
|
import { useTranslation } from "react-i18next";
|
|
12
12
|
import { Controller, useFormContext } from "react-hook-form";
|
|
13
13
|
import { AttendanceTable } from "./attendance-table";
|
|
14
|
+
import GroupFormWorkflowContext from "../context/GroupFormWorkflowContext";
|
|
15
|
+
import useGetPatients from "../hooks/useGetPatients";
|
|
14
16
|
|
|
15
17
|
const SessionDetailsForm = () => {
|
|
16
18
|
const { t } = useTranslation();
|
|
@@ -20,101 +22,108 @@ const SessionDetailsForm = () => {
|
|
|
20
22
|
control,
|
|
21
23
|
} = useFormContext();
|
|
22
24
|
|
|
25
|
+
const { patientUuids } = useContext(GroupFormWorkflowContext);
|
|
26
|
+
const { patients, isLoading } = useGetPatients(patientUuids);
|
|
27
|
+
|
|
23
28
|
return (
|
|
24
|
-
<div
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
<div>
|
|
30
|
+
{!isLoading && (
|
|
31
|
+
<div className={styles.formSection}>
|
|
32
|
+
<h4>{t("sessionDetails", "1. Session details")}</h4>
|
|
33
|
+
<div>
|
|
34
|
+
<p>
|
|
35
|
+
{t(
|
|
36
|
+
"allFieldsRequired",
|
|
37
|
+
"All fields are required unless marked optional"
|
|
38
|
+
)}
|
|
39
|
+
</p>
|
|
40
|
+
</div>
|
|
36
41
|
<Layer>
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
42
|
+
<Tile className={styles.formSectionTile}>
|
|
43
|
+
<Layer>
|
|
44
|
+
<div
|
|
45
|
+
style={{
|
|
46
|
+
display: "flex",
|
|
47
|
+
flexDirection: "column",
|
|
48
|
+
rowGap: "1.5rem",
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
<TextInput
|
|
52
|
+
id="text"
|
|
53
|
+
type="text"
|
|
54
|
+
labelText={t("sessionName", "Session Name")}
|
|
55
|
+
{...register("sessionName", { required: true })}
|
|
56
|
+
invalid={errors.sessionName}
|
|
57
|
+
invalidText={"This field is required"}
|
|
58
|
+
/>
|
|
59
|
+
<TextInput
|
|
60
|
+
id="text"
|
|
61
|
+
type="text"
|
|
62
|
+
labelText={t("practitionerName", "Practitioner Name")}
|
|
63
|
+
{...register("practitionerName", { required: true })}
|
|
64
|
+
invalid={errors.practitionerName}
|
|
65
|
+
invalidText={"This field is required"}
|
|
66
|
+
/>
|
|
67
|
+
<Controller
|
|
68
|
+
name="sessionDate"
|
|
69
|
+
control={control}
|
|
70
|
+
rules={{ required: true }}
|
|
71
|
+
render={({ field }) => (
|
|
72
|
+
<DatePicker
|
|
73
|
+
datePickerType="single"
|
|
74
|
+
size="md"
|
|
75
|
+
maxDate={new Date()}
|
|
76
|
+
{...field}
|
|
77
|
+
>
|
|
78
|
+
<DatePickerInput
|
|
79
|
+
id="session-date"
|
|
80
|
+
labelText={t("sessionDate", "Session Date")}
|
|
81
|
+
placeholder="mm/dd/yyyy"
|
|
82
|
+
size="md"
|
|
83
|
+
invalid={errors.sessionDate}
|
|
84
|
+
invalidText={"This field is required"}
|
|
85
|
+
/>
|
|
86
|
+
</DatePicker>
|
|
87
|
+
)}
|
|
88
|
+
/>
|
|
89
|
+
<TextArea
|
|
90
|
+
id="text"
|
|
91
|
+
type="text"
|
|
92
|
+
labelText={t("sessionNotes", "Session Notes")}
|
|
93
|
+
{...register("sessionNotes", { required: true })}
|
|
94
|
+
invalid={errors.sessionNotes}
|
|
95
|
+
invalidText={"This field is required"}
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
</Layer>
|
|
99
|
+
</Tile>
|
|
91
100
|
</Layer>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
</p>
|
|
102
|
-
</div>
|
|
103
|
-
<Layer>
|
|
104
|
-
<Tile className={styles.formSectionTile}>
|
|
101
|
+
<h4>{t("sessionParticipants", "2. Session participants")}</h4>
|
|
102
|
+
<div>
|
|
103
|
+
<p>
|
|
104
|
+
{t(
|
|
105
|
+
"markAbsentPatients",
|
|
106
|
+
"The patients in this group. Patients that are not present in the session should be marked as absent."
|
|
107
|
+
)}
|
|
108
|
+
</p>
|
|
109
|
+
</div>
|
|
105
110
|
<Layer>
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
<Tile className={styles.formSectionTile}>
|
|
112
|
+
<Layer>
|
|
113
|
+
<div
|
|
114
|
+
style={{
|
|
115
|
+
display: "flex",
|
|
116
|
+
flexDirection: "column",
|
|
117
|
+
rowGap: "1.5rem",
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<AttendanceTable patients={patients} />
|
|
121
|
+
</div>
|
|
122
|
+
</Layer>
|
|
123
|
+
</Tile>
|
|
115
124
|
</Layer>
|
|
116
|
-
</
|
|
117
|
-
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
118
127
|
</div>
|
|
119
128
|
);
|
|
120
129
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, { useContext } from "react";
|
|
1
|
+
import React, { useCallback, useContext, useMemo, useState } from "react";
|
|
2
|
+
import { Edit } from "@carbon/react/icons";
|
|
2
3
|
|
|
3
4
|
import {
|
|
4
5
|
Checkbox,
|
|
@@ -9,13 +10,13 @@ import {
|
|
|
9
10
|
TableHeader,
|
|
10
11
|
TableBody,
|
|
11
12
|
TableCell,
|
|
13
|
+
Button,
|
|
12
14
|
} from "@carbon/react";
|
|
13
15
|
import { useTranslation } from "react-i18next";
|
|
14
16
|
import GroupFormWorkflowContext from "../../context/GroupFormWorkflowContext";
|
|
15
|
-
import
|
|
17
|
+
import AddGroupModal from "../../add-group-modal/AddGroupModal";
|
|
16
18
|
|
|
17
|
-
const PatientRow = ({
|
|
18
|
-
const patient = useGetPatient(patientUuid);
|
|
19
|
+
const PatientRow = ({ patient }) => {
|
|
19
20
|
const { patientUuids, addPatientUuid, removePatientUuid } = useContext(
|
|
20
21
|
GroupFormWorkflowContext
|
|
21
22
|
);
|
|
@@ -25,9 +26,9 @@ const PatientRow = ({ patientUuid }) => {
|
|
|
25
26
|
|
|
26
27
|
const handleOnChange = (e, { checked }) => {
|
|
27
28
|
if (checked) {
|
|
28
|
-
addPatientUuid(
|
|
29
|
+
addPatientUuid(patient.id);
|
|
29
30
|
} else {
|
|
30
|
-
removePatientUuid(
|
|
31
|
+
removePatientUuid(patient.id);
|
|
31
32
|
}
|
|
32
33
|
};
|
|
33
34
|
|
|
@@ -57,8 +58,8 @@ const PatientRow = ({ patientUuid }) => {
|
|
|
57
58
|
<TableCell>{identifier}</TableCell>
|
|
58
59
|
<TableCell>
|
|
59
60
|
<Checkbox
|
|
60
|
-
checked={patientUuids.includes(
|
|
61
|
-
labelText={
|
|
61
|
+
checked={patientUuids.includes(patient.id)}
|
|
62
|
+
labelText={patient.id}
|
|
62
63
|
hideLabel
|
|
63
64
|
id={`${identifier}-attendance-checkbox`}
|
|
64
65
|
onChange={handleOnChange}
|
|
@@ -68,37 +69,75 @@ const PatientRow = ({ patientUuid }) => {
|
|
|
68
69
|
);
|
|
69
70
|
};
|
|
70
71
|
|
|
71
|
-
const AttendanceTable = () => {
|
|
72
|
+
const AttendanceTable = ({ patients }) => {
|
|
72
73
|
const { t } = useTranslation();
|
|
73
|
-
const { activeGroupUuid, activeGroupMembers } = useContext(
|
|
74
|
+
const { activeGroupUuid, activeGroupName, activeGroupMembers } = useContext(
|
|
74
75
|
GroupFormWorkflowContext
|
|
75
76
|
);
|
|
76
77
|
|
|
78
|
+
const [isOpen, setOpen] = useState(false);
|
|
79
|
+
|
|
77
80
|
const headers = [
|
|
78
81
|
t("name", "Name"),
|
|
79
82
|
t("identifier", "Patient ID"),
|
|
80
83
|
t("patientIsPresent", "Patient is present"),
|
|
81
84
|
];
|
|
82
85
|
|
|
86
|
+
const handleCancel = useCallback(() => {
|
|
87
|
+
setOpen(false);
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
const onPostSubmit = useCallback(() => {
|
|
91
|
+
setOpen(false);
|
|
92
|
+
}, []);
|
|
93
|
+
|
|
94
|
+
const newArr = useMemo(() => {
|
|
95
|
+
return activeGroupMembers.map(function (value) {
|
|
96
|
+
const patient = patients.find((patient) => patient.id === value);
|
|
97
|
+
return { uuid: value, ...patient };
|
|
98
|
+
});
|
|
99
|
+
}, [activeGroupMembers, patients]);
|
|
100
|
+
|
|
83
101
|
if (!activeGroupUuid) {
|
|
84
102
|
return <div>{t("selectGroupFirst", "Please select a group first")}</div>;
|
|
85
103
|
}
|
|
86
104
|
|
|
87
105
|
return (
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
<div>
|
|
107
|
+
<span style={{ flexGrow: 1 }} />
|
|
108
|
+
<Button kind="ghost" onClick={() => setOpen(true)}>
|
|
109
|
+
{t("editGroup", "Edit Group")}
|
|
110
|
+
<Edit size={20} />
|
|
111
|
+
</Button>
|
|
112
|
+
<AddGroupModal
|
|
113
|
+
{...{
|
|
114
|
+
cohortUuid: activeGroupUuid,
|
|
115
|
+
patients: newArr,
|
|
116
|
+
isCreate: false,
|
|
117
|
+
groupName: activeGroupName,
|
|
118
|
+
isOpen: isOpen,
|
|
119
|
+
handleCancel: handleCancel,
|
|
120
|
+
onPostSubmit: onPostSubmit,
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
123
|
+
<Table>
|
|
124
|
+
<TableHead>
|
|
125
|
+
<TableRow>
|
|
126
|
+
{headers.map((header, index) => (
|
|
127
|
+
<TableHeader key={index}>{header}</TableHeader>
|
|
128
|
+
))}
|
|
129
|
+
</TableRow>
|
|
130
|
+
</TableHead>
|
|
131
|
+
<TableBody>
|
|
132
|
+
{activeGroupMembers.map((patientUuid, index) => {
|
|
133
|
+
const patient = patients.find(
|
|
134
|
+
(patient) => patient.id === patientUuid
|
|
135
|
+
);
|
|
136
|
+
return <PatientRow patient={patient} key={index} />;
|
|
137
|
+
})}
|
|
138
|
+
</TableBody>
|
|
139
|
+
</Table>
|
|
140
|
+
</div>
|
|
102
141
|
);
|
|
103
142
|
};
|
|
104
143
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Close } from "@carbon/react/icons";
|
|
1
|
+
import { Close, Add } from "@carbon/react/icons";
|
|
2
2
|
import { Button } from "@carbon/react";
|
|
3
|
-
import React, { useContext } from "react";
|
|
3
|
+
import React, { useCallback, useContext, useState } from "react";
|
|
4
4
|
import GroupFormWorkflowContext from "../../context/GroupFormWorkflowContext";
|
|
5
5
|
import styles from "./styles.scss";
|
|
6
6
|
import { useTranslation } from "react-i18next";
|
|
@@ -12,10 +12,23 @@ const GroupSearchHeader = () => {
|
|
|
12
12
|
const { activeGroupUuid, setGroup, destroySession } = useContext(
|
|
13
13
|
GroupFormWorkflowContext
|
|
14
14
|
);
|
|
15
|
+
const [isOpen, setOpen] = useState(false);
|
|
15
16
|
const handleSelectGroup = (group) => {
|
|
16
17
|
setGroup(group);
|
|
17
18
|
};
|
|
18
19
|
|
|
20
|
+
const handleCancel = useCallback(() => {
|
|
21
|
+
setOpen(false);
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
24
|
+
const onPostSubmit = useCallback(() => {
|
|
25
|
+
setOpen(false);
|
|
26
|
+
}, []);
|
|
27
|
+
|
|
28
|
+
const handleOpenClick = useCallback(() => {
|
|
29
|
+
setOpen(true);
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
19
32
|
if (activeGroupUuid) return null;
|
|
20
33
|
|
|
21
34
|
return (
|
|
@@ -26,7 +39,21 @@ const GroupSearchHeader = () => {
|
|
|
26
39
|
</span>
|
|
27
40
|
<span className={styles.padded}>{t("or", "or")}</span>
|
|
28
41
|
<span>
|
|
29
|
-
<
|
|
42
|
+
<Button
|
|
43
|
+
onClick={handleOpenClick}
|
|
44
|
+
renderIcon={Add}
|
|
45
|
+
iconDescription="Add"
|
|
46
|
+
>
|
|
47
|
+
{t("createNewGroup", "Create New Group")}
|
|
48
|
+
</Button>
|
|
49
|
+
<AddGroupModal
|
|
50
|
+
{...{
|
|
51
|
+
isCreate: true,
|
|
52
|
+
isOpen: isOpen,
|
|
53
|
+
handleCancel: handleCancel,
|
|
54
|
+
onPostSubmit: onPostSubmit,
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
30
57
|
</span>
|
|
31
58
|
<span style={{ flexGrow: 1 }} />
|
|
32
59
|
<span>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { fetchCurrentPatient } from "@openmrs/esm-framework";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
|
|
4
|
+
const useGetPatients = (patientUuids) => {
|
|
5
|
+
const [patients, setPatients] = useState([]);
|
|
6
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!patientUuids || patientUuids.length === 0) {
|
|
10
|
+
setPatients([]);
|
|
11
|
+
setIsLoading(false);
|
|
12
|
+
} else {
|
|
13
|
+
getPatients(patientUuids);
|
|
14
|
+
}
|
|
15
|
+
}, [patientUuids]);
|
|
16
|
+
|
|
17
|
+
const getPatients = async (uuids) => {
|
|
18
|
+
try {
|
|
19
|
+
setIsLoading(true);
|
|
20
|
+
const results = await Promise.all(
|
|
21
|
+
uuids.map(async (uuid) => await fetchCurrentPatient(uuid))
|
|
22
|
+
);
|
|
23
|
+
setPatients(results);
|
|
24
|
+
setIsLoading(false);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error("Error fetching patients:", error);
|
|
27
|
+
setIsLoading(false);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return { patients, isLoading };
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default useGetPatients;
|
|
@@ -31,7 +31,13 @@ const usePostEndpoint = ({ endpointUrl }) => {
|
|
|
31
31
|
const post = useCallback(
|
|
32
32
|
async (data) => {
|
|
33
33
|
setSubmissionInProgress(true);
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
let path = endpointUrl;
|
|
36
|
+
if (data.uuid) {
|
|
37
|
+
path += "/" + data.uuid;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return openmrsFetch(path, {
|
|
35
41
|
method: "POST",
|
|
36
42
|
headers: {
|
|
37
43
|
"Content-Type": "application/json",
|
package/translations/en.json
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"createNewPatient": "Create new patient",
|
|
15
15
|
"createNewSession": "Create New Session",
|
|
16
16
|
"discard": "Discard",
|
|
17
|
+
"editGroup": "Edit Group",
|
|
17
18
|
"error": "Error",
|
|
18
19
|
"errorCopy": "Sorry, there was an error. You can try to reload this page, or contact the site administrator and quote the error code above.",
|
|
19
20
|
"errorLoadingData": "Error Loading Data",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"remove": "Remove",
|
|
47
48
|
"resumeGroupSession": "Resume Group Session",
|
|
48
49
|
"resumeSession": "Resume Session",
|
|
50
|
+
"save": "Save",
|
|
49
51
|
"saveAndComplete": "Save & Complete",
|
|
50
52
|
"saveExplanation": "Do you want to save the current form and exit the workflow?",
|
|
51
53
|
"saveForm": "Save Form",
|
|
@@ -63,5 +65,5 @@
|
|
|
63
65
|
"startGroupSession": "Start Group Session",
|
|
64
66
|
"trySearchWithPatientUniqueID": "Try searching with the cohort's description",
|
|
65
67
|
"unknown": "Unknown",
|
|
66
|
-
"unknownPostError": "An unknown error
|
|
68
|
+
"unknownPostError": "An unknown error occurred while saving data"
|
|
67
69
|
}
|