@openmrs/esm-fast-data-entry-app 1.0.1-pre.171 → 1.0.1-pre.176
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/101.js.map +1 -1
- package/dist/188.js.map +1 -1
- package/dist/219.js.map +1 -1
- package/dist/326.js.map +1 -1
- package/dist/564.js.map +1 -1
- package/dist/91.js.map +1 -1
- package/dist/99.js.map +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +8 -8
- package/dist/routes.json +1 -1
- package/package.json +1 -3
- package/prettier.config.js +8 -0
- package/src/CancelModal.tsx +9 -15
- package/src/CompleteModal.tsx +7 -18
- package/src/FormBootstrap.tsx +9 -9
- package/src/Root.tsx +7 -12
- package/src/add-group-modal/AddGroupModal.tsx +46 -109
- package/src/config-schema.ts +35 -36
- 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 +36 -61
- package/src/context/GroupFormWorkflowReducer.ts +69 -105
- package/src/declarations.d.ts +3 -3
- package/src/empty-state/EmptyDataIllustration.tsx +4 -16
- package/src/empty-state/EmptyState.tsx +8 -13
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +26 -44
- 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/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-search-header/PatientSearchHeader.tsx +17 -26
- package/src/form-entry-workflow/patient-search-header/index.ts +1 -1
- package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +12 -12
- package/src/form-entry-workflow/workflow-review/index.ts +1 -1
- package/src/forms-app-menu-link.tsx +4 -6
- package/src/forms-page/FormsPage.tsx +22 -50
- package/src/forms-page/forms-table/FormsTable.tsx +22 -42
- package/src/forms-page/forms-table/index.ts +1 -1
- package/src/forms-page/index.ts +1 -1
- package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +8 -8
- package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +27 -58
- package/src/group-form-entry-workflow/SessionDetailsForm.tsx +43 -66
- package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +20 -28
- package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +13 -27
- package/src/group-form-entry-workflow/attendance-table/index.ts +1 -1
- package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +6 -12
- 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-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-header/GroupSearchHeader.tsx +18 -25
- package/src/group-form-entry-workflow/group-search-header/index.ts +1 -1
- package/src/group-form-entry-workflow/index.ts +1 -1
- package/src/hooks/index.ts +7 -13
- package/src/hooks/useForm.ts +13 -30
- package/src/hooks/useFormState.ts +3 -3
- package/src/hooks/useGetAllForms.ts +5 -14
- package/src/hooks/useGetEncounter.ts +2 -2
- 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 +8 -8
- package/src/hooks/useSearchEndpoint.ts +15 -38
- package/src/hooks/useStartVisit.ts +16 -27
- package/src/index.ts +8 -20
- package/src/patient-card/PatientCard.tsx +8 -20
- package/src/patient-card/index.ts +1 -1
- package/src/setup-tests.ts +1 -1
- package/tools/i18next-parser.config.js +19 -19
- package/webpack.config.js +1 -1
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import { useTranslation } from "react-i18next";
|
|
14
|
-
import { Controller, useFormContext } from "react-hook-form";
|
|
15
|
-
import { AttendanceTable } from "./attendance-table";
|
|
16
|
-
import GroupFormWorkflowContext from "../context/GroupFormWorkflowContext";
|
|
17
|
-
import useGetPatients from "../hooks/useGetPatients";
|
|
18
|
-
import ConfigurableQuestionsSection from "./configurable-questions/ConfigurableQuestionsSection";
|
|
19
|
-
import useSpecificQuestions from "../hooks/useForm";
|
|
1
|
+
import { Layer, Tile, TextInput, TextArea, DatePicker, DatePickerInput } from '@carbon/react';
|
|
2
|
+
import React, { useContext } from 'react';
|
|
3
|
+
import { useConfig } from '@openmrs/esm-framework';
|
|
4
|
+
import { useParams } from 'react-router-dom';
|
|
5
|
+
import styles from './styles.scss';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { Controller, useFormContext } from 'react-hook-form';
|
|
8
|
+
import { AttendanceTable } from './attendance-table';
|
|
9
|
+
import GroupFormWorkflowContext from '../context/GroupFormWorkflowContext';
|
|
10
|
+
import useGetPatients from '../hooks/useGetPatients';
|
|
11
|
+
import ConfigurableQuestionsSection from './configurable-questions/ConfigurableQuestionsSection';
|
|
12
|
+
import useSpecificQuestions from '../hooks/useForm';
|
|
20
13
|
|
|
21
14
|
interface ParamTypes {
|
|
22
15
|
formUuid?: string;
|
|
@@ -34,69 +27,56 @@ const SessionDetailsForm = () => {
|
|
|
34
27
|
control,
|
|
35
28
|
} = useFormContext();
|
|
36
29
|
|
|
37
|
-
const { activeGroupMembers} = useContext(GroupFormWorkflowContext);
|
|
30
|
+
const { activeGroupMembers } = useContext(GroupFormWorkflowContext);
|
|
38
31
|
const { patients, isLoading } = useGetPatients(activeGroupMembers);
|
|
39
32
|
|
|
40
33
|
return (
|
|
41
34
|
<div>
|
|
42
35
|
{!isLoading && (
|
|
43
36
|
<div className={styles.formSection}>
|
|
44
|
-
<h4>{t(
|
|
37
|
+
<h4>{t('sessionDetails', '1. Session details')}</h4>
|
|
45
38
|
<div>
|
|
46
|
-
<p>
|
|
47
|
-
{t(
|
|
48
|
-
"allFieldsRequired",
|
|
49
|
-
"All fields are required unless marked optional"
|
|
50
|
-
)}
|
|
51
|
-
</p>
|
|
39
|
+
<p>{t('allFieldsRequired', 'All fields are required unless marked optional')}</p>
|
|
52
40
|
</div>
|
|
53
41
|
<Layer>
|
|
54
42
|
<Tile className={styles.formSectionTile}>
|
|
55
43
|
<Layer>
|
|
56
44
|
<div
|
|
57
45
|
style={{
|
|
58
|
-
display:
|
|
59
|
-
flexDirection:
|
|
60
|
-
rowGap:
|
|
46
|
+
display: 'flex',
|
|
47
|
+
flexDirection: 'column',
|
|
48
|
+
rowGap: '1.5rem',
|
|
61
49
|
}}
|
|
62
50
|
>
|
|
63
51
|
<TextInput
|
|
64
52
|
id="text"
|
|
65
53
|
type="text"
|
|
66
|
-
labelText={t(
|
|
67
|
-
{...register(
|
|
54
|
+
labelText={t('sessionName', 'Session Name')}
|
|
55
|
+
{...register('sessionName', { required: true })}
|
|
68
56
|
invalid={errors.sessionName}
|
|
69
|
-
invalidText={t(
|
|
57
|
+
invalidText={t('requiredField', 'This field is required')}
|
|
70
58
|
/>
|
|
71
59
|
<TextInput
|
|
72
60
|
id="text"
|
|
73
61
|
type="text"
|
|
74
|
-
labelText={t(
|
|
75
|
-
{...register(
|
|
62
|
+
labelText={t('practitionerName', 'Practitioner Name')}
|
|
63
|
+
{...register('practitionerName', { required: true })}
|
|
76
64
|
invalid={errors.practitionerName}
|
|
77
|
-
invalidText={t(
|
|
65
|
+
invalidText={t('requiredField', 'This field is required')}
|
|
78
66
|
/>
|
|
79
67
|
<Controller
|
|
80
68
|
name="sessionDate"
|
|
81
69
|
control={control}
|
|
82
70
|
rules={{ required: true }}
|
|
83
71
|
render={({ field }) => (
|
|
84
|
-
<DatePicker
|
|
85
|
-
datePickerType="single"
|
|
86
|
-
size="md"
|
|
87
|
-
maxDate={new Date()}
|
|
88
|
-
{...field}
|
|
89
|
-
>
|
|
72
|
+
<DatePicker datePickerType="single" size="md" maxDate={new Date()} {...field}>
|
|
90
73
|
<DatePickerInput
|
|
91
74
|
id="session-date"
|
|
92
|
-
labelText={t(
|
|
75
|
+
labelText={t('sessionDate', 'Session Date')}
|
|
93
76
|
placeholder="mm/dd/yyyy"
|
|
94
77
|
size="md"
|
|
95
78
|
invalid={errors.sessionDate}
|
|
96
|
-
invalidText={t(
|
|
97
|
-
"requiredField",
|
|
98
|
-
"This field is required"
|
|
99
|
-
)}
|
|
79
|
+
invalidText={t('requiredField', 'This field is required')}
|
|
100
80
|
/>
|
|
101
81
|
</DatePicker>
|
|
102
82
|
)}
|
|
@@ -104,21 +84,21 @@ const SessionDetailsForm = () => {
|
|
|
104
84
|
<TextArea
|
|
105
85
|
id="text"
|
|
106
86
|
type="text"
|
|
107
|
-
labelText={t(
|
|
108
|
-
{...register(
|
|
87
|
+
labelText={t('sessionNotes', 'Session Notes')}
|
|
88
|
+
{...register('sessionNotes', { required: true })}
|
|
109
89
|
invalid={errors.sessionNotes}
|
|
110
|
-
invalidText={t(
|
|
90
|
+
invalidText={t('requiredField', 'This field is required')}
|
|
111
91
|
/>
|
|
112
92
|
</div>
|
|
113
93
|
</Layer>
|
|
114
94
|
</Tile>
|
|
115
95
|
</Layer>
|
|
116
|
-
<h4>{t(
|
|
96
|
+
<h4>{t('sessionParticipants', '2. Session participants')}</h4>
|
|
117
97
|
<div>
|
|
118
98
|
<p>
|
|
119
99
|
{t(
|
|
120
|
-
|
|
121
|
-
|
|
100
|
+
'markAbsentPatients',
|
|
101
|
+
'The patients in this group. Patients that are not present in the session should be marked as absent.',
|
|
122
102
|
)}
|
|
123
103
|
</p>
|
|
124
104
|
</div>
|
|
@@ -127,9 +107,9 @@ const SessionDetailsForm = () => {
|
|
|
127
107
|
<Layer>
|
|
128
108
|
<div
|
|
129
109
|
style={{
|
|
130
|
-
display:
|
|
131
|
-
flexDirection:
|
|
132
|
-
rowGap:
|
|
110
|
+
display: 'flex',
|
|
111
|
+
flexDirection: 'column',
|
|
112
|
+
rowGap: '1.5rem',
|
|
133
113
|
}}
|
|
134
114
|
>
|
|
135
115
|
<AttendanceTable patients={patients} />
|
|
@@ -139,12 +119,12 @@ const SessionDetailsForm = () => {
|
|
|
139
119
|
</Layer>
|
|
140
120
|
{questions?.length > 0 ? (
|
|
141
121
|
<>
|
|
142
|
-
<h4>{t(
|
|
122
|
+
<h4>{t('sessionSpecificDetails', '3. Specific details')}</h4>
|
|
143
123
|
<div>
|
|
144
124
|
<p>
|
|
145
125
|
{t(
|
|
146
|
-
|
|
147
|
-
|
|
126
|
+
'sessionSpecificDetailsDescription',
|
|
127
|
+
'They will be mapped to form responses for all patients as pre-filled data.',
|
|
148
128
|
)}
|
|
149
129
|
</p>
|
|
150
130
|
</div>
|
|
@@ -153,15 +133,12 @@ const SessionDetailsForm = () => {
|
|
|
153
133
|
<Layer>
|
|
154
134
|
<div
|
|
155
135
|
style={{
|
|
156
|
-
display:
|
|
157
|
-
flexDirection:
|
|
158
|
-
rowGap:
|
|
136
|
+
display: 'flex',
|
|
137
|
+
flexDirection: 'column',
|
|
138
|
+
rowGap: '1.5rem',
|
|
159
139
|
}}
|
|
160
140
|
>
|
|
161
|
-
<ConfigurableQuestionsSection
|
|
162
|
-
register={register}
|
|
163
|
-
specificQuestions={questions}
|
|
164
|
-
/>
|
|
141
|
+
<ConfigurableQuestionsSection register={register} specificQuestions={questions} />
|
|
165
142
|
</div>
|
|
166
143
|
</Layer>
|
|
167
144
|
</Tile>
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { Button } from
|
|
2
|
-
import React, { useContext, useEffect, useState } from
|
|
3
|
-
import styles from
|
|
4
|
-
import { useTranslation } from
|
|
5
|
-
import GroupFormWorkflowContext from
|
|
6
|
-
import { FormProvider, useForm, useFormContext } from
|
|
7
|
-
import CancelModal from
|
|
8
|
-
import SessionDetailsForm from
|
|
1
|
+
import { Button } from '@carbon/react';
|
|
2
|
+
import React, { useContext, useEffect, useState } from 'react';
|
|
3
|
+
import styles from './styles.scss';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import GroupFormWorkflowContext from '../context/GroupFormWorkflowContext';
|
|
6
|
+
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
|
|
7
|
+
import CancelModal from '../CancelModal';
|
|
8
|
+
import SessionDetailsForm from './SessionDetailsForm';
|
|
9
9
|
|
|
10
10
|
const NewGroupWorkflowButtons = () => {
|
|
11
11
|
const { t } = useTranslation();
|
|
12
12
|
const context = useContext(GroupFormWorkflowContext);
|
|
13
13
|
const { workflowState, patientUuids } = context;
|
|
14
14
|
const [cancelModalOpen, setCancelModalOpen] = useState(false);
|
|
15
|
-
if (workflowState !==
|
|
15
|
+
if (workflowState !== 'NEW_GROUP_SESSION') return null;
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
18
|
<>
|
|
19
19
|
<div className={styles.rightPanelActionButtons}>
|
|
20
20
|
<Button kind="secondary" type="submit" disabled={!patientUuids.length}>
|
|
21
|
-
{t(
|
|
21
|
+
{t('createNewSession', 'Create New Session')}
|
|
22
22
|
</Button>
|
|
23
23
|
<Button
|
|
24
24
|
kind="tertiary"
|
|
@@ -26,14 +26,10 @@ const NewGroupWorkflowButtons = () => {
|
|
|
26
26
|
setCancelModalOpen(true);
|
|
27
27
|
}}
|
|
28
28
|
>
|
|
29
|
-
{t(
|
|
29
|
+
{t('cancel', 'Cancel')}
|
|
30
30
|
</Button>
|
|
31
31
|
</div>
|
|
32
|
-
<CancelModal
|
|
33
|
-
open={cancelModalOpen}
|
|
34
|
-
setOpen={setCancelModalOpen}
|
|
35
|
-
context={context}
|
|
36
|
-
/>
|
|
32
|
+
<CancelModal open={cancelModalOpen} setOpen={setCancelModalOpen} context={context} />
|
|
37
33
|
</>
|
|
38
34
|
);
|
|
39
35
|
};
|
|
@@ -48,22 +44,20 @@ const GroupIdField = () => {
|
|
|
48
44
|
const { activeGroupUuid } = useContext(GroupFormWorkflowContext);
|
|
49
45
|
|
|
50
46
|
useEffect(() => {
|
|
51
|
-
if (activeGroupUuid) setValue(
|
|
47
|
+
if (activeGroupUuid) setValue('groupUuid', activeGroupUuid);
|
|
52
48
|
}, [activeGroupUuid, setValue]);
|
|
53
49
|
|
|
54
50
|
return (
|
|
55
51
|
<>
|
|
56
52
|
<input
|
|
57
53
|
hidden
|
|
58
|
-
{...register(
|
|
54
|
+
{...register('groupUuid', {
|
|
59
55
|
value: activeGroupUuid,
|
|
60
|
-
required: t(
|
|
56
|
+
required: t('chooseGroupError', 'Please choose a group.'),
|
|
61
57
|
})}
|
|
62
58
|
/>
|
|
63
59
|
{errors.groupUuid && !activeGroupUuid && (
|
|
64
|
-
<div className={styles.formError}>
|
|
65
|
-
{errors.groupUuid.message as string}
|
|
66
|
-
</div>
|
|
60
|
+
<div className={styles.formError}>{errors.groupUuid.message as string}</div>
|
|
67
61
|
)}
|
|
68
62
|
</>
|
|
69
63
|
);
|
|
@@ -71,9 +65,7 @@ const GroupIdField = () => {
|
|
|
71
65
|
|
|
72
66
|
const SessionMetaWorkspace = () => {
|
|
73
67
|
const { t } = useTranslation();
|
|
74
|
-
const { setSessionMeta, workflowState } = useContext(
|
|
75
|
-
GroupFormWorkflowContext
|
|
76
|
-
);
|
|
68
|
+
const { setSessionMeta, workflowState } = useContext(GroupFormWorkflowContext);
|
|
77
69
|
const methods = useForm();
|
|
78
70
|
|
|
79
71
|
const onSubmit = (data) => {
|
|
@@ -81,7 +73,7 @@ const SessionMetaWorkspace = () => {
|
|
|
81
73
|
setSessionMeta({ ...rest, sessionDate: sessionDate[0] });
|
|
82
74
|
};
|
|
83
75
|
|
|
84
|
-
if (workflowState !==
|
|
76
|
+
if (workflowState !== 'NEW_GROUP_SESSION') return null;
|
|
85
77
|
|
|
86
78
|
return (
|
|
87
79
|
<FormProvider {...methods}>
|
|
@@ -92,9 +84,9 @@ const SessionMetaWorkspace = () => {
|
|
|
92
84
|
<SessionDetailsForm />
|
|
93
85
|
</div>
|
|
94
86
|
<div className={styles.rightPanel}>
|
|
95
|
-
<h4>{t(
|
|
87
|
+
<h4>{t('newGroupSession', 'New Group Session')}</h4>
|
|
96
88
|
<GroupIdField />
|
|
97
|
-
<hr style={{ width:
|
|
89
|
+
<hr style={{ width: '100%' }} />
|
|
98
90
|
<NewGroupWorkflowButtons />
|
|
99
91
|
</div>
|
|
100
92
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useCallback, useContext, useMemo, useState } from
|
|
2
|
-
import { Edit } from
|
|
1
|
+
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
|
2
|
+
import { Edit } from '@carbon/react/icons';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
Checkbox,
|
|
@@ -11,15 +11,13 @@ import {
|
|
|
11
11
|
TableBody,
|
|
12
12
|
TableCell,
|
|
13
13
|
Button,
|
|
14
|
-
} from
|
|
15
|
-
import { useTranslation } from
|
|
16
|
-
import GroupFormWorkflowContext from
|
|
17
|
-
import AddGroupModal from
|
|
14
|
+
} from '@carbon/react';
|
|
15
|
+
import { useTranslation } from 'react-i18next';
|
|
16
|
+
import GroupFormWorkflowContext from '../../context/GroupFormWorkflowContext';
|
|
17
|
+
import AddGroupModal from '../../add-group-modal/AddGroupModal';
|
|
18
18
|
|
|
19
19
|
const PatientRow = ({ patient }) => {
|
|
20
|
-
const { patientUuids, addPatientUuid, removePatientUuid } = useContext(
|
|
21
|
-
GroupFormWorkflowContext
|
|
22
|
-
);
|
|
20
|
+
const { patientUuids, addPatientUuid, removePatientUuid } = useContext(GroupFormWorkflowContext);
|
|
23
21
|
const givenName = patient?.name?.[0]?.given?.[0];
|
|
24
22
|
const familyName = patient?.name?.[0]?.family;
|
|
25
23
|
const identifier = patient?.identifier?.[0]?.value;
|
|
@@ -50,11 +48,7 @@ const PatientRow = ({ patient }) => {
|
|
|
50
48
|
|
|
51
49
|
return (
|
|
52
50
|
<TableRow>
|
|
53
|
-
<TableCell>
|
|
54
|
-
{patient.display ||
|
|
55
|
-
patient.displayName ||
|
|
56
|
-
[givenName, familyName].join(" ")}
|
|
57
|
-
</TableCell>
|
|
51
|
+
<TableCell>{patient.display || patient.displayName || [givenName, familyName].join(' ')}</TableCell>
|
|
58
52
|
<TableCell>{identifier}</TableCell>
|
|
59
53
|
<TableCell>
|
|
60
54
|
<Checkbox
|
|
@@ -71,17 +65,11 @@ const PatientRow = ({ patient }) => {
|
|
|
71
65
|
|
|
72
66
|
const AttendanceTable = ({ patients }) => {
|
|
73
67
|
const { t } = useTranslation();
|
|
74
|
-
const { activeGroupUuid, activeGroupName, activeGroupMembers } = useContext(
|
|
75
|
-
GroupFormWorkflowContext
|
|
76
|
-
);
|
|
68
|
+
const { activeGroupUuid, activeGroupName, activeGroupMembers } = useContext(GroupFormWorkflowContext);
|
|
77
69
|
|
|
78
70
|
const [isOpen, setOpen] = useState(false);
|
|
79
71
|
|
|
80
|
-
const headers = [
|
|
81
|
-
t("name", "Name"),
|
|
82
|
-
t("identifier", "Patient ID"),
|
|
83
|
-
t("patientIsPresent", "Patient is present"),
|
|
84
|
-
];
|
|
72
|
+
const headers = [t('name', 'Name'), t('identifier', 'Patient ID'), t('patientIsPresent', 'Patient is present')];
|
|
85
73
|
|
|
86
74
|
const onPostCancel = useCallback(() => {
|
|
87
75
|
setOpen(false);
|
|
@@ -99,14 +87,14 @@ const AttendanceTable = ({ patients }) => {
|
|
|
99
87
|
}, [activeGroupMembers, patients]);
|
|
100
88
|
|
|
101
89
|
if (!activeGroupUuid) {
|
|
102
|
-
return <div>{t(
|
|
90
|
+
return <div>{t('selectGroupFirst', 'Please select a group first')}</div>;
|
|
103
91
|
}
|
|
104
92
|
|
|
105
93
|
return (
|
|
106
94
|
<div>
|
|
107
95
|
<span style={{ flexGrow: 1 }} />
|
|
108
96
|
<Button kind="ghost" onClick={() => setOpen(true)}>
|
|
109
|
-
{t(
|
|
97
|
+
{t('editGroup', 'Edit Group')}
|
|
110
98
|
<Edit size={20} />
|
|
111
99
|
</Button>
|
|
112
100
|
<AddGroupModal
|
|
@@ -130,9 +118,7 @@ const AttendanceTable = ({ patients }) => {
|
|
|
130
118
|
</TableHead>
|
|
131
119
|
<TableBody>
|
|
132
120
|
{activeGroupMembers.map((patientUuid, index) => {
|
|
133
|
-
const patient = patients.find(
|
|
134
|
-
(patient) => patient.id === patientUuid
|
|
135
|
-
);
|
|
121
|
+
const patient = patients.find((patient) => patient.id === patientUuid);
|
|
136
122
|
return <PatientRow patient={patient} key={index} />;
|
|
137
123
|
})}
|
|
138
124
|
</TableBody>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as AttendanceTable } from
|
|
1
|
+
export { default as AttendanceTable } from './AttendanceTable';
|
package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { TextInput, Select, SelectItem } from
|
|
3
|
-
import { type FieldValues, type UseFormRegister } from
|
|
4
|
-
import { type SpecificQuestion } from
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TextInput, Select, SelectItem } from '@carbon/react';
|
|
3
|
+
import { type FieldValues, type UseFormRegister } from 'react-hook-form';
|
|
4
|
+
import { type SpecificQuestion } from '../../types';
|
|
5
5
|
|
|
6
6
|
interface ConfigurableQuestionsSectionProps {
|
|
7
7
|
specificQuestions: Array<SpecificQuestion>;
|
|
8
8
|
register?: UseFormRegister<FieldValues>;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
const ConfigurableQuestionsSection: React.FC<
|
|
12
|
-
ConfigurableQuestionsSectionProps
|
|
13
|
-
> = ({ register, specificQuestions }) => {
|
|
11
|
+
const ConfigurableQuestionsSection: React.FC<ConfigurableQuestionsSectionProps> = ({ register, specificQuestions }) => {
|
|
14
12
|
return (
|
|
15
13
|
<>
|
|
16
14
|
{specificQuestions?.map((specificQuestion) => (
|
|
@@ -23,11 +21,7 @@ const ConfigurableQuestionsSection: React.FC<
|
|
|
23
21
|
>
|
|
24
22
|
<SelectItem value="" text="" />
|
|
25
23
|
{specificQuestion.answers.map((answer) => (
|
|
26
|
-
<SelectItem
|
|
27
|
-
key={answer.value}
|
|
28
|
-
value={answer.value}
|
|
29
|
-
text={answer.display}
|
|
30
|
-
/>
|
|
24
|
+
<SelectItem key={answer.value} value={answer.value} text={answer.display} />
|
|
31
25
|
))}
|
|
32
26
|
</Select>
|
|
33
27
|
) : (
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { render } from
|
|
3
|
-
import GroupDisplayHeader from
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import GroupDisplayHeader from './GroupDisplayHeader';
|
|
4
4
|
|
|
5
|
-
describe(
|
|
6
|
-
it(
|
|
5
|
+
describe('PatientBanner', () => {
|
|
6
|
+
it('renders placeholder information when no data is present', () => {
|
|
7
7
|
render(<GroupDisplayHeader />);
|
|
8
8
|
});
|
|
9
9
|
});
|
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
import React, { useContext } from
|
|
2
|
-
import { Button } from
|
|
3
|
-
import { Events, Close } from
|
|
4
|
-
import styles from
|
|
5
|
-
import { useTranslation } from
|
|
6
|
-
import GroupFormWorkflowContext from
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
import { Button } from '@carbon/react';
|
|
3
|
+
import { Events, Close } from '@carbon/react/icons';
|
|
4
|
+
import styles from './styles.scss';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import GroupFormWorkflowContext from '../../context/GroupFormWorkflowContext';
|
|
7
7
|
|
|
8
8
|
const GroupDisplayHeader = () => {
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
activeGroupUuid,
|
|
12
|
-
patientUuids,
|
|
13
|
-
activeSessionMeta,
|
|
14
|
-
unsetGroup,
|
|
15
|
-
destroySession,
|
|
16
|
-
} = useContext(GroupFormWorkflowContext);
|
|
9
|
+
const { activeGroupName, activeGroupUuid, patientUuids, activeSessionMeta, unsetGroup, destroySession } =
|
|
10
|
+
useContext(GroupFormWorkflowContext);
|
|
17
11
|
const { t } = useTranslation();
|
|
18
12
|
|
|
19
13
|
if (!activeGroupUuid) {
|
|
@@ -31,29 +25,27 @@ const GroupDisplayHeader = () => {
|
|
|
31
25
|
</div>
|
|
32
26
|
<div className={styles.groupInfoRow}>
|
|
33
27
|
<span>
|
|
34
|
-
{patientUuids.length} {t(
|
|
28
|
+
{patientUuids.length} {t('members', 'members')}
|
|
35
29
|
</span>
|
|
36
30
|
</div>
|
|
37
31
|
</div>
|
|
38
32
|
{activeSessionMeta?.sessionNotes && (
|
|
39
33
|
<div className={styles.groupMeataContent}>
|
|
40
34
|
<div className={`${styles.groupInfoRow} ${styles.sessionNotesLabel}`}>
|
|
41
|
-
{t(
|
|
42
|
-
</div>
|
|
43
|
-
<div className={styles.groupInfoRow}>
|
|
44
|
-
{activeSessionMeta.sessionNotes}
|
|
35
|
+
{t('sessionNotes', 'Session Notes')}
|
|
45
36
|
</div>
|
|
37
|
+
<div className={styles.groupInfoRow}>{activeSessionMeta.sessionNotes}</div>
|
|
46
38
|
</div>
|
|
47
39
|
)}
|
|
48
40
|
<span style={{ flexGrow: 1 }} />
|
|
49
41
|
<span>
|
|
50
42
|
<Button kind="ghost" onClick={() => unsetGroup()}>
|
|
51
|
-
{t(
|
|
43
|
+
{t('changeGroup', 'Choose a different group')} <Close size={20} />
|
|
52
44
|
</Button>
|
|
53
45
|
</span>
|
|
54
46
|
<span>
|
|
55
47
|
<Button kind="ghost" onClick={() => destroySession()}>
|
|
56
|
-
{t(
|
|
48
|
+
{t('cancel', 'Cancel')} <Close size={20} />
|
|
57
49
|
</Button>
|
|
58
50
|
</span>
|
|
59
51
|
</div>
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import React, { useEffect, useReducer, useRef } from
|
|
2
|
-
import { SkeletonIcon, SkeletonText } from
|
|
3
|
-
import { Events } from
|
|
4
|
-
import styles from
|
|
5
|
-
import { useTranslation } from
|
|
6
|
-
import useKeyPress from
|
|
1
|
+
import React, { useEffect, useReducer, useRef } from 'react';
|
|
2
|
+
import { SkeletonIcon, SkeletonText } from '@carbon/react';
|
|
3
|
+
import { Events } from '@carbon/react/icons';
|
|
4
|
+
import styles from './compact-group-result.scss';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import useKeyPress from '../../hooks/useKeyPress';
|
|
7
7
|
|
|
8
8
|
const reducer = (state, action) => {
|
|
9
9
|
switch (action.type) {
|
|
10
|
-
case
|
|
10
|
+
case 'arrowUp':
|
|
11
11
|
return { selectedIndex: Math.max(state.selectedIndex - 1, 0) };
|
|
12
|
-
case
|
|
12
|
+
case 'arrowDown':
|
|
13
13
|
return {
|
|
14
14
|
selectedIndex: Math.min(state.selectedIndex + 1, action.listLength - 1),
|
|
15
15
|
};
|
|
16
|
-
case
|
|
16
|
+
case 'select':
|
|
17
17
|
return { selectedIndex: action.payload };
|
|
18
18
|
default:
|
|
19
19
|
return state;
|
|
@@ -21,19 +21,11 @@ const reducer = (state, action) => {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const scrollingOptions = {
|
|
24
|
-
behavior:
|
|
25
|
-
block:
|
|
24
|
+
behavior: 'smooth',
|
|
25
|
+
block: 'nearest',
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const ResultItem = ({
|
|
29
|
-
index,
|
|
30
|
-
selectGroupAction,
|
|
31
|
-
group,
|
|
32
|
-
dispatch,
|
|
33
|
-
state,
|
|
34
|
-
totalGroups,
|
|
35
|
-
lastRef,
|
|
36
|
-
}) => {
|
|
28
|
+
const ResultItem = ({ index, selectGroupAction, group, dispatch, state, totalGroups, lastRef }) => {
|
|
37
29
|
const ref = useRef(null);
|
|
38
30
|
const { t } = useTranslation();
|
|
39
31
|
|
|
@@ -48,12 +40,10 @@ const ResultItem = ({
|
|
|
48
40
|
return (
|
|
49
41
|
<div
|
|
50
42
|
onClick={() => {
|
|
51
|
-
dispatch({ type:
|
|
43
|
+
dispatch({ type: 'select', payload: index });
|
|
52
44
|
selectGroupAction(group);
|
|
53
45
|
}}
|
|
54
|
-
className={`${styles.patientSearchResult} ${
|
|
55
|
-
index === state.selectedIndex && styles.patientSearchResultSelected
|
|
56
|
-
}`}
|
|
46
|
+
className={`${styles.patientSearchResult} ${index === state.selectedIndex && styles.patientSearchResultSelected}`}
|
|
57
47
|
role="button"
|
|
58
48
|
aria-pressed={index === state.selectedIndex}
|
|
59
49
|
tabIndex={0}
|
|
@@ -65,7 +55,7 @@ const ResultItem = ({
|
|
|
65
55
|
<div>
|
|
66
56
|
<h2 className={styles.patientName}>{group.name}</h2>
|
|
67
57
|
<p className={styles.demographics}>
|
|
68
|
-
{group.cohortMembers?.length ?? 0} {t(
|
|
58
|
+
{group.cohortMembers?.length ?? 0} {t('members', 'members')}
|
|
69
59
|
<span className={styles.middot}>·</span> {group.description}
|
|
70
60
|
</p>
|
|
71
61
|
</div>
|
|
@@ -74,21 +64,21 @@ const ResultItem = ({
|
|
|
74
64
|
};
|
|
75
65
|
|
|
76
66
|
const CompactGroupResults = ({ groups, selectGroupAction, lastRef }) => {
|
|
77
|
-
const arrowUpPressed = useKeyPress(
|
|
78
|
-
const arrowDownPressed = useKeyPress(
|
|
79
|
-
const enterPressed = useKeyPress(
|
|
67
|
+
const arrowUpPressed = useKeyPress('ArrowUp');
|
|
68
|
+
const arrowDownPressed = useKeyPress('ArrowDown');
|
|
69
|
+
const enterPressed = useKeyPress('Enter');
|
|
80
70
|
|
|
81
71
|
const [state, dispatch] = useReducer(reducer, { selectedIndex: 0 });
|
|
82
72
|
|
|
83
73
|
useEffect(() => {
|
|
84
74
|
if (arrowUpPressed) {
|
|
85
|
-
dispatch({ type:
|
|
75
|
+
dispatch({ type: 'arrowUp' });
|
|
86
76
|
}
|
|
87
77
|
}, [arrowUpPressed]);
|
|
88
78
|
|
|
89
79
|
useEffect(() => {
|
|
90
80
|
if (arrowDownPressed) {
|
|
91
|
-
dispatch({ type:
|
|
81
|
+
dispatch({ type: 'arrowDown', listLength: groups.length });
|
|
92
82
|
}
|
|
93
83
|
}, [arrowDownPressed, groups.length]);
|
|
94
84
|
|
|
@@ -117,8 +107,8 @@ export const SearchResultSkeleton = () => {
|
|
|
117
107
|
<div className={styles.patientAvatar} role="img">
|
|
118
108
|
<SkeletonIcon
|
|
119
109
|
style={{
|
|
120
|
-
height:
|
|
121
|
-
width:
|
|
110
|
+
height: '3rem',
|
|
111
|
+
width: '3rem',
|
|
122
112
|
}}
|
|
123
113
|
/>
|
|
124
114
|
</div>
|
|
@@ -127,9 +117,8 @@ export const SearchResultSkeleton = () => {
|
|
|
127
117
|
<SkeletonText />
|
|
128
118
|
</h2>
|
|
129
119
|
<span className={styles.demographics}>
|
|
130
|
-
<SkeletonIcon /> <span className={styles.middot}>·</span>{
|
|
131
|
-
<
|
|
132
|
-
<SkeletonIcon />
|
|
120
|
+
<SkeletonIcon /> <span className={styles.middot}>·</span> <SkeletonIcon />{' '}
|
|
121
|
+
<span className={styles.middot}>·</span> <SkeletonIcon />
|
|
133
122
|
</span>
|
|
134
123
|
</div>
|
|
135
124
|
</div>
|