@openmrs/esm-fast-data-entry-app 1.0.1-pre.93 → 1.1.0
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/__mocks__/react-i18next.js +9 -14
- package/dist/12.js +1 -0
- package/dist/12.js.map +1 -0
- package/dist/132.js +1 -1
- package/dist/151.js +2 -0
- package/dist/151.js.LICENSE.txt +5 -0
- package/dist/151.js.map +1 -0
- package/dist/195.js +1 -0
- package/dist/195.js.map +1 -0
- package/dist/197.js +1 -0
- package/dist/221.js +1 -0
- package/dist/221.js.map +1 -0
- package/dist/259.js +1 -0
- package/dist/259.js.map +1 -0
- package/dist/265.js +1 -0
- package/dist/265.js.map +1 -0
- package/dist/269.js +1 -0
- package/dist/269.js.map +1 -0
- package/dist/300.js +1 -0
- package/dist/335.js +1 -0
- package/dist/367.js +1 -0
- package/dist/367.js.map +1 -0
- package/dist/384.js +1 -0
- package/dist/384.js.map +1 -0
- package/dist/540.js +2 -0
- package/dist/540.js.map +1 -0
- package/dist/55.js +1 -0
- package/dist/579.js +1 -0
- package/dist/579.js.map +1 -0
- package/dist/595.js +1 -1
- package/dist/595.js.LICENSE.txt +34 -2
- package/dist/595.js.map +1 -0
- package/dist/602.js +1 -0
- package/dist/602.js.map +1 -0
- package/dist/616.js +1 -0
- package/dist/616.js.map +1 -0
- package/dist/626.js +2 -0
- package/dist/626.js.map +1 -0
- package/dist/652.js +1 -0
- package/dist/77.js +1 -0
- package/dist/77.js.map +1 -0
- package/dist/773.js +2 -0
- package/dist/{68.js.LICENSE.txt → 773.js.LICENSE.txt} +13 -2
- package/dist/773.js.map +1 -0
- package/dist/88.js +1 -0
- package/dist/88.js.map +1 -0
- package/dist/930.js +1 -0
- package/dist/930.js.map +1 -0
- package/dist/961.js +2 -0
- package/dist/961.js.map +1 -0
- package/dist/983.js +1 -0
- package/dist/983.js.map +1 -0
- package/dist/99.js +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -0
- package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +380 -156
- package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -0
- package/dist/routes.json +1 -0
- package/jest.config.json +2 -1
- package/package.json +41 -35
- package/prettier.config.js +8 -0
- package/src/CancelModal.tsx +9 -15
- package/src/CompleteModal.tsx +7 -18
- package/src/FormBootstrap.tsx +31 -18
- package/src/Root.tsx +7 -12
- package/src/add-group-modal/AddGroupModal.tsx +73 -112
- package/src/add-group-modal/styles.scss +7 -3
- package/src/config-schema.ts +63 -24
- package/src/constant.ts +1 -1
- package/src/context/FormWorkflowContext.tsx +26 -39
- package/src/context/FormWorkflowReducer.ts +50 -74
- package/src/context/GroupFormWorkflowContext.tsx +40 -59
- package/src/context/GroupFormWorkflowReducer.ts +84 -109
- package/src/declarations.d.ts +3 -0
- package/src/empty-state/EmptyDataIllustration.tsx +4 -16
- package/src/empty-state/EmptyState.tsx +8 -13
- package/src/empty-state/styles.scss +14 -14
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +43 -55
- package/src/form-entry-workflow/form-review-card/FormReviewCard.tsx +7 -7
- package/src/form-entry-workflow/form-review-card/index.ts +1 -1
- package/src/form-entry-workflow/form-review-card/styles.scss +9 -11
- package/src/form-entry-workflow/index.ts +1 -1
- package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +5 -5
- package/src/form-entry-workflow/patient-banner/PatientBanner.tsx +14 -27
- package/src/form-entry-workflow/patient-banner/index.ts +1 -1
- package/src/form-entry-workflow/patient-banner/styles.scss +11 -12
- package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +19 -28
- package/src/form-entry-workflow/patient-search-header/index.ts +1 -1
- package/src/form-entry-workflow/patient-search-header/styles.scss +13 -10
- package/src/form-entry-workflow/styles.scss +11 -13
- package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +13 -11
- package/src/form-entry-workflow/workflow-review/index.ts +1 -1
- package/src/form-entry-workflow/workflow-review/styles.scss +0 -4
- package/src/forms-app-menu-link.tsx +4 -6
- package/src/forms-page/FormsPage.tsx +23 -51
- package/src/forms-page/forms-table/FormsTable.tsx +22 -42
- package/src/forms-page/forms-table/index.ts +1 -1
- package/src/forms-page/forms-table/styles.scss +4 -5
- package/src/forms-page/index.ts +1 -1
- package/src/forms-page/styles.scss +3 -5
- package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +9 -9
- package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +77 -117
- package/src/group-form-entry-workflow/SessionDetailsForm.tsx +73 -50
- package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +20 -28
- package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +15 -29
- package/src/group-form-entry-workflow/attendance-table/index.ts +1 -1
- package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +45 -0
- package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.test.tsx +5 -5
- package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +13 -21
- package/src/group-form-entry-workflow/group-display-header/index.ts +1 -1
- package/src/group-form-entry-workflow/group-display-header/styles.scss +20 -20
- package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +24 -35
- package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +13 -15
- package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +22 -38
- package/src/group-form-entry-workflow/group-search/compact-group-result.scss +16 -17
- package/src/group-form-entry-workflow/group-search/compact-group-search.scss +7 -8
- package/src/group-form-entry-workflow/group-search/group-search.scss +20 -23
- package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +20 -21
- package/src/group-form-entry-workflow/group-search-header/index.ts +1 -1
- package/src/group-form-entry-workflow/group-search-header/styles.scss +8 -8
- package/src/group-form-entry-workflow/index.ts +1 -1
- package/src/group-form-entry-workflow/styles.scss +13 -16
- package/src/hooks/index.ts +7 -6
- package/src/hooks/useFormState.ts +3 -3
- package/src/hooks/useGetAllForms.ts +7 -15
- package/src/hooks/useGetEncounter.ts +3 -3
- package/src/hooks/useGetPatient.ts +2 -2
- package/src/hooks/useGetPatients.ts +4 -6
- package/src/hooks/useGetSystemSetting.ts +3 -5
- package/src/hooks/useKeyPress.ts +5 -5
- package/src/hooks/usePostEndpoint.ts +10 -10
- package/src/hooks/useSearchEndpoint.ts +23 -40
- package/src/hooks/useSpecificQuestions.ts +75 -0
- package/src/hooks/useStartVisit.ts +18 -28
- package/src/index.ts +12 -76
- package/src/patient-card/PatientCard.tsx +8 -20
- package/src/patient-card/index.ts +1 -1
- package/src/patient-card/styles.scss +2 -4
- package/src/routes.json +24 -0
- package/src/setup-tests.ts +1 -1
- package/src/types.ts +25 -0
- package/tools/i18next-parser.config.js +19 -19
- package/translations/am.json +75 -0
- package/translations/ar.json +75 -0
- package/translations/en.json +7 -1
- package/translations/es.json +75 -0
- package/translations/fr.json +33 -8
- package/translations/he.json +75 -0
- package/translations/km.json +75 -0
- package/tsconfig.json +2 -1
- package/turbo.json +18 -0
- package/webpack.config.js +1 -1
- package/dist/153.js +0 -1
- package/dist/229.js +0 -1
- package/dist/247.js +0 -1
- package/dist/255.js +0 -1
- package/dist/294.js +0 -2
- package/dist/32.js +0 -1
- package/dist/327.js +0 -1
- package/dist/571.js +0 -1
- package/dist/574.js +0 -1
- package/dist/617.js +0 -1
- package/dist/656.js +0 -2
- package/dist/658.js +0 -2
- package/dist/658.js.LICENSE.txt +0 -27
- package/dist/68.js +0 -2
- package/dist/74.js +0 -1
- package/dist/757.js +0 -1
- package/dist/776.js +0 -1
- package/dist/804.js +0 -1
- package/dist/820.js +0 -1
- package/dist/935.js +0 -2
- package/dist/openmrs-esm-fast-data-entry-app.old +0 -1
- package/src/declarations.d.tsx +0 -2
- /package/dist/{294.js.LICENSE.txt → 540.js.LICENSE.txt} +0 -0
- /package/dist/{656.js.LICENSE.txt → 626.js.LICENSE.txt} +0 -0
- /package/dist/{935.js.LICENSE.txt → 961.js.LICENSE.txt} +0 -0
|
@@ -1,58 +1,31 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
ComposedModal,
|
|
10
|
-
Button,
|
|
11
|
-
ModalHeader,
|
|
12
|
-
ModalFooter,
|
|
13
|
-
ModalBody,
|
|
14
|
-
TextInput,
|
|
15
|
-
FormLabel,
|
|
16
|
-
} from "@carbon/react";
|
|
17
|
-
import { TrashCan } from "@carbon/react/icons";
|
|
18
|
-
import { useTranslation } from "react-i18next";
|
|
19
|
-
import { ExtensionSlot, showToast } from "@openmrs/esm-framework";
|
|
20
|
-
import styles from "./styles.scss";
|
|
21
|
-
import GroupFormWorkflowContext from "../context/GroupFormWorkflowContext";
|
|
22
|
-
import { usePostCohort } from "../hooks";
|
|
1
|
+
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { ComposedModal, Button, ModalHeader, ModalFooter, ModalBody, TextInput, FormLabel } from '@carbon/react';
|
|
3
|
+
import { TrashCan } from '@carbon/react/icons';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { ExtensionSlot, fetchCurrentPatient, showToast, useConfig, usePatient } from '@openmrs/esm-framework';
|
|
6
|
+
import styles from './styles.scss';
|
|
7
|
+
import GroupFormWorkflowContext from '../context/GroupFormWorkflowContext';
|
|
8
|
+
import { usePostCohort } from '../hooks';
|
|
23
9
|
|
|
24
10
|
const MemExtension = React.memo(ExtensionSlot);
|
|
25
11
|
|
|
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
|
-
|
|
36
12
|
const PatientRow = ({ patient, removePatient }) => {
|
|
37
13
|
const { t } = useTranslation();
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
14
|
+
const { patient: patientInfo, error, isLoading } = usePatient(patient?.uuid);
|
|
15
|
+
const onClickHandler = useCallback(() => removePatient(patient?.uuid), [patient, removePatient]);
|
|
16
|
+
|
|
42
17
|
const patientDisplay = useMemo(() => {
|
|
43
|
-
if (!
|
|
44
|
-
return "";
|
|
45
|
-
}
|
|
18
|
+
if (isLoading || error || !patientInfo) return '';
|
|
46
19
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
20
|
+
const { identifier, name } = patientInfo;
|
|
21
|
+
const displayIdentifier = identifier?.[0]?.value || '';
|
|
22
|
+
const givenNames = `${(name?.[0]?.given || []).join(' ')} ${name?.[0]?.family || ''}`;
|
|
50
23
|
|
|
51
|
-
return
|
|
52
|
-
}, [
|
|
24
|
+
return `${displayIdentifier ? `${displayIdentifier} -` : ''}${givenNames ? ` ${givenNames}` : ''}`.trim();
|
|
25
|
+
}, [isLoading, error, patientInfo]);
|
|
53
26
|
|
|
54
27
|
return (
|
|
55
|
-
<li
|
|
28
|
+
<li className={styles.patientRow}>
|
|
56
29
|
<span>
|
|
57
30
|
<Button
|
|
58
31
|
kind="tertiary"
|
|
@@ -62,7 +35,7 @@ const PatientRow = ({ patient, removePatient }) => {
|
|
|
62
35
|
renderIcon={TrashCan}
|
|
63
36
|
tooltipAlignment="start"
|
|
64
37
|
tooltipPosition="top"
|
|
65
|
-
iconDescription={t(
|
|
38
|
+
iconDescription={t('remove', 'Remove')}
|
|
66
39
|
/>
|
|
67
40
|
</span>
|
|
68
41
|
<span className={styles.patientName}>{patientDisplay}</span>
|
|
@@ -71,66 +44,50 @@ const PatientRow = ({ patient, removePatient }) => {
|
|
|
71
44
|
};
|
|
72
45
|
|
|
73
46
|
const NewGroupForm = (props) => {
|
|
74
|
-
const {
|
|
75
|
-
name,
|
|
76
|
-
setName,
|
|
77
|
-
patientList,
|
|
78
|
-
updatePatientList,
|
|
79
|
-
errors,
|
|
80
|
-
validate,
|
|
81
|
-
removePatient,
|
|
82
|
-
} = props;
|
|
47
|
+
const { name, setName, patientList, updatePatientList, errors, validate, removePatient } = props;
|
|
83
48
|
const { t } = useTranslation();
|
|
84
49
|
|
|
85
50
|
return (
|
|
86
51
|
<div
|
|
87
52
|
style={{
|
|
88
|
-
display:
|
|
89
|
-
flexDirection:
|
|
90
|
-
rowGap:
|
|
53
|
+
display: 'flex',
|
|
54
|
+
flexDirection: 'column',
|
|
55
|
+
rowGap: '1rem',
|
|
91
56
|
}}
|
|
92
57
|
>
|
|
93
58
|
<TextInput
|
|
94
|
-
labelText={t(
|
|
59
|
+
labelText={t('newGroupName', 'New Group Name')}
|
|
95
60
|
value={name}
|
|
96
61
|
onChange={(e) => setName(e.target.value)}
|
|
97
|
-
onBlur={() => validate(
|
|
62
|
+
onBlur={() => validate('name')}
|
|
98
63
|
/>
|
|
99
64
|
{errors?.name && (
|
|
100
65
|
<p className={styles.formError}>
|
|
101
|
-
{errors.name ===
|
|
102
|
-
? t("groupNameError", "Please enter a group name.")
|
|
103
|
-
: errors.name}
|
|
66
|
+
{errors.name === 'required' ? t('groupNameError', 'Please enter a group name.') : errors.name}
|
|
104
67
|
</p>
|
|
105
68
|
)}
|
|
106
69
|
<FormLabel>
|
|
107
|
-
{patientList.length} {t(
|
|
70
|
+
{patientList.length} {t('patientsInGroup', 'Patients in group')}
|
|
108
71
|
</FormLabel>
|
|
109
72
|
{errors?.patientList && (
|
|
110
|
-
<p className={styles.formError}>
|
|
111
|
-
{t("noPatientError", "Please enter at least one patient.")}
|
|
112
|
-
</p>
|
|
73
|
+
<p className={styles.formError}>{t('noPatientError', 'Please enter at least one patient.')}</p>
|
|
113
74
|
)}
|
|
114
75
|
{!errors?.patientList && (
|
|
115
76
|
<ul className={styles.patientList}>
|
|
116
77
|
{patientList?.map((patient, index) => (
|
|
117
|
-
<PatientRow
|
|
118
|
-
patient={patient}
|
|
119
|
-
removePatient={removePatient}
|
|
120
|
-
key={index}
|
|
121
|
-
/>
|
|
78
|
+
<PatientRow patient={patient} removePatient={removePatient} key={patient.uuid} />
|
|
122
79
|
))}
|
|
123
80
|
</ul>
|
|
124
81
|
)}
|
|
125
82
|
|
|
126
|
-
<FormLabel>Search for patients to add to group</FormLabel>
|
|
83
|
+
<FormLabel>{t('searchForPatientsToAddToGroup', 'Search for patients to add to group')}</FormLabel>
|
|
127
84
|
<div className={styles.searchBar}>
|
|
128
85
|
<MemExtension
|
|
129
86
|
extensionSlotName="patient-search-bar-slot"
|
|
130
87
|
state={{
|
|
131
88
|
selectPatientAction: updatePatientList,
|
|
132
89
|
buttonProps: {
|
|
133
|
-
kind:
|
|
90
|
+
kind: 'secondary',
|
|
134
91
|
},
|
|
135
92
|
}}
|
|
136
93
|
/>
|
|
@@ -142,10 +99,10 @@ const NewGroupForm = (props) => {
|
|
|
142
99
|
const AddGroupModal = ({
|
|
143
100
|
patients = undefined,
|
|
144
101
|
isCreate = undefined,
|
|
145
|
-
groupName =
|
|
102
|
+
groupName = '',
|
|
146
103
|
cohortUuid = undefined,
|
|
147
104
|
isOpen,
|
|
148
|
-
|
|
105
|
+
onPostCancel,
|
|
149
106
|
onPostSubmit,
|
|
150
107
|
}) => {
|
|
151
108
|
const { setGroup } = useContext(GroupFormWorkflowContext);
|
|
@@ -154,33 +111,32 @@ const AddGroupModal = ({
|
|
|
154
111
|
const [name, setName] = useState(groupName);
|
|
155
112
|
const [patientList, setPatientList] = useState(patients || []);
|
|
156
113
|
const { post, result, error } = usePostCohort();
|
|
114
|
+
const config = useConfig();
|
|
157
115
|
|
|
158
116
|
const removePatient = useCallback(
|
|
159
117
|
(patientUuid: string) =>
|
|
160
|
-
setPatientList((patientList) =>
|
|
161
|
-
|
|
162
|
-
),
|
|
163
|
-
[setPatientList]
|
|
118
|
+
setPatientList((patientList) => patientList.filter((patient) => patient.uuid !== patientUuid)),
|
|
119
|
+
[setPatientList],
|
|
164
120
|
);
|
|
165
121
|
|
|
166
122
|
const validate = useCallback(
|
|
167
123
|
(field?: string | undefined) => {
|
|
168
124
|
let valid = true;
|
|
169
125
|
if (field) {
|
|
170
|
-
valid = field ===
|
|
126
|
+
valid = field === 'name' ? !!name : !!patientList.length;
|
|
171
127
|
setErrors((errors) => ({
|
|
172
128
|
...errors,
|
|
173
|
-
[field]: valid ? null :
|
|
129
|
+
[field]: valid ? null : 'required',
|
|
174
130
|
}));
|
|
175
131
|
} else {
|
|
176
132
|
if (!name) {
|
|
177
|
-
setErrors((errors) => ({ ...errors, name:
|
|
133
|
+
setErrors((errors) => ({ ...errors, name: 'required' }));
|
|
178
134
|
valid = false;
|
|
179
135
|
} else {
|
|
180
136
|
setErrors((errors) => ({ ...errors, name: null }));
|
|
181
137
|
}
|
|
182
138
|
if (!patientList.length) {
|
|
183
|
-
setErrors((errors) => ({ ...errors, patientList:
|
|
139
|
+
setErrors((errors) => ({ ...errors, patientList: 'required' }));
|
|
184
140
|
valid = false;
|
|
185
141
|
} else {
|
|
186
142
|
setErrors((errors) => ({ ...errors, patientList: null }));
|
|
@@ -188,21 +144,29 @@ const AddGroupModal = ({
|
|
|
188
144
|
}
|
|
189
145
|
return valid;
|
|
190
146
|
},
|
|
191
|
-
[name, patientList.length]
|
|
147
|
+
[name, patientList.length],
|
|
192
148
|
);
|
|
193
149
|
|
|
194
150
|
const updatePatientList = useCallback(
|
|
195
|
-
(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
151
|
+
(patientUuid) => {
|
|
152
|
+
function getPatientName(patient) {
|
|
153
|
+
return [patient?.name?.[0]?.given, patient?.name?.[0]?.family].join(' ');
|
|
154
|
+
}
|
|
155
|
+
if (!patientList.find((p) => p.uuid === patientUuid)) {
|
|
156
|
+
fetchCurrentPatient(patientUuid).then((result) => {
|
|
157
|
+
const newPatient = { uuid: patientUuid, ...result };
|
|
158
|
+
setPatientList(
|
|
159
|
+
[...patientList, newPatient].sort((a, b) =>
|
|
160
|
+
getPatientName(a).localeCompare(getPatientName(b), undefined, {
|
|
161
|
+
sensitivity: 'base',
|
|
162
|
+
}),
|
|
163
|
+
),
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
203
167
|
setErrors((errors) => ({ ...errors, patientList: null }));
|
|
204
168
|
},
|
|
205
|
-
[setPatientList]
|
|
169
|
+
[patientList, setPatientList],
|
|
206
170
|
);
|
|
207
171
|
|
|
208
172
|
const handleSubmit = () => {
|
|
@@ -210,6 +174,7 @@ const AddGroupModal = ({
|
|
|
210
174
|
post({
|
|
211
175
|
uuid: cohortUuid,
|
|
212
176
|
name: name,
|
|
177
|
+
cohortType: config?.groupSessionConcepts?.cohortTypeId,
|
|
213
178
|
cohortMembers: patientList.map((p) => ({ patient: p.uuid })),
|
|
214
179
|
});
|
|
215
180
|
if (onPostSubmit) {
|
|
@@ -218,6 +183,13 @@ const AddGroupModal = ({
|
|
|
218
183
|
}
|
|
219
184
|
};
|
|
220
185
|
|
|
186
|
+
const handleCancel = () => {
|
|
187
|
+
setPatientList(patients || []);
|
|
188
|
+
if (onPostCancel) {
|
|
189
|
+
onPostCancel();
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
221
193
|
useEffect(() => {
|
|
222
194
|
if (result) {
|
|
223
195
|
setGroup({
|
|
@@ -232,20 +204,13 @@ const AddGroupModal = ({
|
|
|
232
204
|
useEffect(() => {
|
|
233
205
|
if (error) {
|
|
234
206
|
showToast({
|
|
235
|
-
kind:
|
|
236
|
-
title: t(
|
|
237
|
-
description:
|
|
238
|
-
error.message ??
|
|
239
|
-
t("unknownPostError", "An unknown error occurred while saving data"),
|
|
207
|
+
kind: 'error',
|
|
208
|
+
title: t('postError', 'POST Error'),
|
|
209
|
+
description: error.message ?? t('unknownPostError', 'An unknown error occurred while saving data'),
|
|
240
210
|
});
|
|
241
211
|
if (error.fieldErrors) {
|
|
242
212
|
setErrors(
|
|
243
|
-
Object.fromEntries(
|
|
244
|
-
Object.entries(error.fieldErrors).map(([key, value]) => [
|
|
245
|
-
key,
|
|
246
|
-
value?.[0]?.message,
|
|
247
|
-
])
|
|
248
|
-
)
|
|
213
|
+
Object.fromEntries(Object.entries(error.fieldErrors).map(([key, value]) => [key, value?.[0]?.message])),
|
|
249
214
|
);
|
|
250
215
|
}
|
|
251
216
|
}
|
|
@@ -254,11 +219,7 @@ const AddGroupModal = ({
|
|
|
254
219
|
return (
|
|
255
220
|
<div className={styles.modal}>
|
|
256
221
|
<ComposedModal open={isOpen} onClose={handleCancel}>
|
|
257
|
-
<ModalHeader>
|
|
258
|
-
{isCreate
|
|
259
|
-
? t("createNewGroup", "Create New Group")
|
|
260
|
-
: t("editGroup", "Edit Group")}
|
|
261
|
-
</ModalHeader>
|
|
222
|
+
<ModalHeader>{isCreate ? t('createNewGroup', 'Create New Group') : t('editGroup', 'Edit Group')}</ModalHeader>
|
|
262
223
|
<ModalBody>
|
|
263
224
|
<NewGroupForm
|
|
264
225
|
{...{
|
|
@@ -274,10 +235,10 @@ const AddGroupModal = ({
|
|
|
274
235
|
</ModalBody>
|
|
275
236
|
<ModalFooter>
|
|
276
237
|
<Button kind="secondary" onClick={handleCancel}>
|
|
277
|
-
{t(
|
|
238
|
+
{t('cancel', 'Cancel')}
|
|
278
239
|
</Button>
|
|
279
240
|
<Button kind="primary" onClick={handleSubmit}>
|
|
280
|
-
{isCreate ? t(
|
|
241
|
+
{isCreate ? t('createGroup', 'Create Group') : t('save', 'Save')}
|
|
281
242
|
</Button>
|
|
282
243
|
</ModalFooter>
|
|
283
244
|
</ComposedModal>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
@use '@carbon/styles/scss/spacing';
|
|
2
1
|
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
3
|
|
|
4
4
|
.modal {
|
|
5
5
|
:global(.cds--modal) {
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
width: 100%
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
.searchBar > div button {
|
|
21
|
+
height: auto;
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
.formError {
|
|
21
25
|
color: red;
|
|
22
26
|
}
|
|
@@ -32,7 +36,7 @@
|
|
|
32
36
|
|
|
33
37
|
.patientName {
|
|
34
38
|
flex-grow: 1;
|
|
35
|
-
padding-left:
|
|
39
|
+
padding-left: layout.$spacing-05;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
.loading {
|
|
@@ -41,5 +45,5 @@
|
|
|
41
45
|
flex-direction: column;
|
|
42
46
|
justify-content: center;
|
|
43
47
|
align-items: center;
|
|
44
|
-
row-gap:
|
|
48
|
+
row-gap: layout.$spacing-05;
|
|
45
49
|
}
|
package/src/config-schema.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Type } from
|
|
1
|
+
import { Type } from '@openmrs/esm-framework';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* This is the config schema.
|
|
@@ -8,44 +8,43 @@ import { Type } from "@openmrs/esm-framework";
|
|
|
8
8
|
export const configSchema = {
|
|
9
9
|
formCategories: {
|
|
10
10
|
_type: Type.Array,
|
|
11
|
-
_description:
|
|
12
|
-
"Organize forms into categories. A form can belong to multiple categories.",
|
|
11
|
+
_description: 'Organize forms into categories. A form can belong to multiple categories.',
|
|
13
12
|
_elements: {
|
|
14
13
|
name: {
|
|
15
14
|
_type: Type.String,
|
|
16
|
-
_description:
|
|
15
|
+
_description: 'Category name',
|
|
17
16
|
},
|
|
18
17
|
forms: {
|
|
19
18
|
_type: Type.Array,
|
|
20
|
-
_description:
|
|
19
|
+
_description: 'List of forms for this category.',
|
|
21
20
|
_elements: {
|
|
22
21
|
formUUID: {
|
|
23
22
|
_type: Type.UUID,
|
|
24
|
-
_description:
|
|
23
|
+
_description: 'UUID of form',
|
|
25
24
|
},
|
|
26
25
|
name: {
|
|
27
26
|
_type: Type.String,
|
|
28
|
-
_description:
|
|
27
|
+
_description: 'Name of form',
|
|
29
28
|
},
|
|
30
29
|
},
|
|
31
30
|
},
|
|
32
31
|
},
|
|
33
32
|
_default: [
|
|
34
33
|
{
|
|
35
|
-
name:
|
|
34
|
+
name: 'ICRC Forms',
|
|
36
35
|
forms: [
|
|
37
36
|
{
|
|
38
|
-
formUUID:
|
|
39
|
-
name:
|
|
37
|
+
formUUID: '0cefb866-110c-4f16-af58-560932a1db1f',
|
|
38
|
+
name: 'Adult Triage',
|
|
40
39
|
},
|
|
41
40
|
],
|
|
42
41
|
},
|
|
43
42
|
{
|
|
44
|
-
name:
|
|
43
|
+
name: 'Distress Scales',
|
|
45
44
|
forms: [
|
|
46
45
|
{
|
|
47
|
-
formUUID:
|
|
48
|
-
name:
|
|
46
|
+
formUUID: '9f26aad4-244a-46ca-be49-1196df1a8c9a',
|
|
47
|
+
name: 'POC Sample Form 1',
|
|
49
48
|
},
|
|
50
49
|
],
|
|
51
50
|
},
|
|
@@ -53,34 +52,74 @@ export const configSchema = {
|
|
|
53
52
|
},
|
|
54
53
|
formCategoriesToShow: {
|
|
55
54
|
_type: Type.Array,
|
|
56
|
-
_description:
|
|
55
|
+
_description: 'Forms to show by default on the forms app home page.',
|
|
57
56
|
_elements: {
|
|
58
57
|
_type: Type.String,
|
|
59
|
-
_description:
|
|
58
|
+
_description: 'Name of category',
|
|
60
59
|
},
|
|
61
|
-
_default: [
|
|
60
|
+
_default: ['ICRC Forms', 'Distress Scales'],
|
|
62
61
|
},
|
|
63
62
|
groupSessionConcepts: {
|
|
64
63
|
sessionName: {
|
|
65
64
|
_type: Type.UUID,
|
|
66
|
-
_description:
|
|
67
|
-
_default:
|
|
65
|
+
_description: 'UUID of concept for Session Name',
|
|
66
|
+
_default: 'e2559620-900b-4f66-ae41-0b9c4adfb654',
|
|
68
67
|
},
|
|
69
68
|
sessionDate: {
|
|
70
69
|
_type: Type.UUID,
|
|
71
|
-
_description:
|
|
72
|
-
_default:
|
|
70
|
+
_description: 'UUID of concept for Session Date',
|
|
71
|
+
_default: 'ceaca505-6dff-4940-8a43-8c060a0924d7',
|
|
73
72
|
},
|
|
74
73
|
practitionerName: {
|
|
75
74
|
_type: Type.UUID,
|
|
76
|
-
_description:
|
|
77
|
-
_default:
|
|
75
|
+
_description: 'UUID of concept for Practitioner Name',
|
|
76
|
+
_default: 'f1a2d58c-1a0e-4148-931a-aac224649fdc',
|
|
78
77
|
},
|
|
79
78
|
sessionNotes: {
|
|
80
79
|
_type: Type.UUID,
|
|
81
|
-
_description:
|
|
82
|
-
_default:
|
|
80
|
+
_description: 'UUID of concept for Session Notes',
|
|
81
|
+
_default: 'fa8fedc0-c066-4da3-8dc1-2ad8621fc480',
|
|
83
82
|
},
|
|
83
|
+
cohortTypeId: {
|
|
84
|
+
_type: Type.UUID,
|
|
85
|
+
_description: 'UUID of cohort type',
|
|
86
|
+
_default: 'eee9970e-7ca0-4e8c-a280-c33e9d5f6a04',
|
|
87
|
+
},
|
|
88
|
+
cohortId: {
|
|
89
|
+
_type: Type.UUID,
|
|
90
|
+
_description: 'UUID of concept for cohort identifier',
|
|
91
|
+
_default: '5461f231-7e59-4be8-93a4-6d49fd13c00a',
|
|
92
|
+
},
|
|
93
|
+
cohortName: {
|
|
94
|
+
_type: Type.UUID,
|
|
95
|
+
_description: 'UUID of concept for cohort name',
|
|
96
|
+
_default: '6029f289-92a6-4a68-80f1-3078d0152449',
|
|
97
|
+
},
|
|
98
|
+
sessionUuid: {
|
|
99
|
+
_type: Type.UUID,
|
|
100
|
+
_description: 'UUID of concept for session identifier',
|
|
101
|
+
_default: '6a803908-8a5b-4598-adea-19358c83529a',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
specificQuestions: {
|
|
105
|
+
_type: Type.Array,
|
|
106
|
+
_description: 'List of specific questions to populate forms.',
|
|
107
|
+
_elements: {
|
|
108
|
+
forms: {
|
|
109
|
+
_type: Type.Array,
|
|
110
|
+
_description: 'List of form UUIDs for which the question applies.',
|
|
111
|
+
_elements: {
|
|
112
|
+
_type: Type.UUID,
|
|
113
|
+
},
|
|
114
|
+
_default: [],
|
|
115
|
+
},
|
|
116
|
+
questionId: {
|
|
117
|
+
_type: Type.String,
|
|
118
|
+
_description: 'ID of the question.',
|
|
119
|
+
_default: '',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
_default: [],
|
|
84
123
|
},
|
|
85
124
|
};
|
|
86
125
|
|
package/src/constant.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useReducer } from
|
|
2
|
-
import reducer from
|
|
3
|
-
import { useParams, useLocation } from
|
|
4
|
-
import useGetSystemSetting from
|
|
5
|
-
import { useSession } from
|
|
1
|
+
import React, { useEffect, useMemo, useReducer } from 'react';
|
|
2
|
+
import reducer from './FormWorkflowReducer';
|
|
3
|
+
import { useParams, useLocation } from 'react-router-dom';
|
|
4
|
+
import useGetSystemSetting from '../hooks/useGetSystemSetting';
|
|
5
|
+
import { useSession } from '@openmrs/esm-framework';
|
|
6
6
|
interface ParamTypes {
|
|
7
7
|
formUuid?: string;
|
|
8
8
|
}
|
|
@@ -44,46 +44,41 @@ const FormWorkflowContext = React.createContext({
|
|
|
44
44
|
const FormWorkflowProvider = ({ children }) => {
|
|
45
45
|
const { user } = useSession();
|
|
46
46
|
const { formUuid } = useParams() as ParamTypes;
|
|
47
|
-
const activeFormUuid = formUuid.split(
|
|
47
|
+
const activeFormUuid = formUuid.split('&')[0];
|
|
48
48
|
const { search } = useLocation();
|
|
49
|
-
const newPatientUuid = new URLSearchParams(search).get(
|
|
49
|
+
const newPatientUuid = new URLSearchParams(search).get('patientUuid');
|
|
50
50
|
const [state, dispatch] = useReducer(reducer, {
|
|
51
51
|
...initialWorkflowState,
|
|
52
52
|
...initialActions,
|
|
53
53
|
});
|
|
54
|
-
const systemSetting = useGetSystemSetting(
|
|
55
|
-
|
|
56
|
-
);
|
|
57
|
-
const singleSessionVisitTypeUuid =
|
|
58
|
-
systemSetting?.result?.data?.results?.[0]?.value;
|
|
54
|
+
const systemSetting = useGetSystemSetting('@openmrs/esm-fast-data-entry-app.groupSessionVisitTypeUuid');
|
|
55
|
+
const singleSessionVisitTypeUuid = systemSetting?.result?.data?.results?.[0]?.value;
|
|
59
56
|
|
|
60
57
|
const actions = useMemo(
|
|
61
58
|
() => ({
|
|
62
59
|
initializeWorkflowState: ({ activeFormUuid, newPatientUuid }) =>
|
|
63
60
|
dispatch({
|
|
64
|
-
type:
|
|
61
|
+
type: 'INITIALIZE_WORKFLOW_STATE',
|
|
65
62
|
activeFormUuid,
|
|
66
63
|
newPatientUuid,
|
|
67
64
|
userUuid: user.uuid,
|
|
68
65
|
}),
|
|
69
|
-
addPatient: (patientUuid) =>
|
|
70
|
-
|
|
71
|
-
openPatientSearch: () => dispatch({ type: "OPEN_PATIENT_SEARCH" }),
|
|
66
|
+
addPatient: (patientUuid) => dispatch({ type: 'ADD_PATIENT', patientUuid }),
|
|
67
|
+
openPatientSearch: () => dispatch({ type: 'OPEN_PATIENT_SEARCH' }),
|
|
72
68
|
saveEncounter: (encounterUuid) =>
|
|
73
69
|
dispatch({
|
|
74
|
-
type:
|
|
70
|
+
type: 'SAVE_ENCOUNTER',
|
|
75
71
|
encounterUuid,
|
|
76
72
|
}),
|
|
77
|
-
submitForNext: () => dispatch({ type:
|
|
78
|
-
submitForReview: () => dispatch({ type:
|
|
79
|
-
submitForComplete: () => dispatch({ type:
|
|
80
|
-
editEncounter: (patientUuid) =>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
closeSession: () => dispatch({ type: "CLOSE_SESSION" }),
|
|
73
|
+
submitForNext: () => dispatch({ type: 'SUBMIT_FOR_NEXT' }),
|
|
74
|
+
submitForReview: () => dispatch({ type: 'SUBMIT_FOR_REVIEW' }),
|
|
75
|
+
submitForComplete: () => dispatch({ type: 'SUBMIT_FOR_COMPLETE' }),
|
|
76
|
+
editEncounter: (patientUuid) => dispatch({ type: 'EDIT_ENCOUNTER', patientUuid }),
|
|
77
|
+
goToReview: () => dispatch({ type: 'GO_TO_REVIEW' }),
|
|
78
|
+
destroySession: () => dispatch({ type: 'DESTROY_SESSION' }),
|
|
79
|
+
closeSession: () => dispatch({ type: 'CLOSE_SESSION' }),
|
|
85
80
|
}),
|
|
86
|
-
[user]
|
|
81
|
+
[user],
|
|
87
82
|
);
|
|
88
83
|
|
|
89
84
|
// if formUuid isn't a part of state yet, grab it from the url params
|
|
@@ -99,21 +94,13 @@ const FormWorkflowProvider = ({ children }) => {
|
|
|
99
94
|
value={{
|
|
100
95
|
...state,
|
|
101
96
|
...actions,
|
|
102
|
-
workflowState:
|
|
103
|
-
state.forms?.[state.activeFormUuid]?.workflowState ??
|
|
104
|
-
initialWorkflowState.workflowState,
|
|
97
|
+
workflowState: state.forms?.[state.activeFormUuid]?.workflowState ?? initialWorkflowState.workflowState,
|
|
105
98
|
activePatientUuid:
|
|
106
|
-
state.forms?.[state.activeFormUuid]?.activePatientUuid ??
|
|
107
|
-
initialWorkflowState.activePatientUuid,
|
|
99
|
+
state.forms?.[state.activeFormUuid]?.activePatientUuid ?? initialWorkflowState.activePatientUuid,
|
|
108
100
|
activeEncounterUuid:
|
|
109
|
-
state.forms?.[state.activeFormUuid]?.activeEncounterUuid ??
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
state.forms?.[state.activeFormUuid]?.patientUuids ??
|
|
113
|
-
initialWorkflowState.patientUuids,
|
|
114
|
-
encounters:
|
|
115
|
-
state.forms?.[state.activeFormUuid]?.encounters ??
|
|
116
|
-
initialWorkflowState.encounters,
|
|
101
|
+
state.forms?.[state.activeFormUuid]?.activeEncounterUuid ?? initialWorkflowState.activeEncounterUuid,
|
|
102
|
+
patientUuids: state.forms?.[state.activeFormUuid]?.patientUuids ?? initialWorkflowState.patientUuids,
|
|
103
|
+
encounters: state.forms?.[state.activeFormUuid]?.encounters ?? initialWorkflowState.encounters,
|
|
117
104
|
singleSessionVisitTypeUuid,
|
|
118
105
|
}}
|
|
119
106
|
>
|