@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,20 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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/useSpecificQuestions';
|
|
13
|
+
|
|
14
|
+
interface ParamTypes {
|
|
15
|
+
formUuid?: string;
|
|
16
|
+
}
|
|
16
17
|
|
|
17
18
|
const SessionDetailsForm = () => {
|
|
19
|
+
const { specificQuestions } = useConfig();
|
|
20
|
+
const { formUuid } = useParams() as ParamTypes;
|
|
21
|
+
const { questions } = useSpecificQuestions(formUuid, specificQuestions);
|
|
22
|
+
|
|
18
23
|
const { t } = useTranslation();
|
|
19
24
|
const {
|
|
20
25
|
register,
|
|
@@ -22,66 +27,56 @@ const SessionDetailsForm = () => {
|
|
|
22
27
|
control,
|
|
23
28
|
} = useFormContext();
|
|
24
29
|
|
|
25
|
-
const {
|
|
26
|
-
const { patients, isLoading } = useGetPatients(
|
|
30
|
+
const { activeGroupMembers } = useContext(GroupFormWorkflowContext);
|
|
31
|
+
const { patients, isLoading } = useGetPatients(activeGroupMembers);
|
|
27
32
|
|
|
28
33
|
return (
|
|
29
34
|
<div>
|
|
30
35
|
{!isLoading && (
|
|
31
36
|
<div className={styles.formSection}>
|
|
32
|
-
<h4>{t(
|
|
37
|
+
<h4>{t('sessionDetails', '1. Session details')}</h4>
|
|
33
38
|
<div>
|
|
34
|
-
<p>
|
|
35
|
-
{t(
|
|
36
|
-
"allFieldsRequired",
|
|
37
|
-
"All fields are required unless marked optional"
|
|
38
|
-
)}
|
|
39
|
-
</p>
|
|
39
|
+
<p>{t('allFieldsRequired', 'All fields are required unless marked optional')}</p>
|
|
40
40
|
</div>
|
|
41
41
|
<Layer>
|
|
42
42
|
<Tile className={styles.formSectionTile}>
|
|
43
43
|
<Layer>
|
|
44
44
|
<div
|
|
45
45
|
style={{
|
|
46
|
-
display:
|
|
47
|
-
flexDirection:
|
|
48
|
-
rowGap:
|
|
46
|
+
display: 'flex',
|
|
47
|
+
flexDirection: 'column',
|
|
48
|
+
rowGap: '1.5rem',
|
|
49
49
|
}}
|
|
50
50
|
>
|
|
51
51
|
<TextInput
|
|
52
52
|
id="text"
|
|
53
53
|
type="text"
|
|
54
|
-
labelText={t(
|
|
55
|
-
{...register(
|
|
54
|
+
labelText={t('sessionName', 'Session Name')}
|
|
55
|
+
{...register('sessionName', { required: true })}
|
|
56
56
|
invalid={errors.sessionName}
|
|
57
|
-
invalidText={
|
|
57
|
+
invalidText={t('requiredField', 'This field is required')}
|
|
58
58
|
/>
|
|
59
59
|
<TextInput
|
|
60
60
|
id="text"
|
|
61
61
|
type="text"
|
|
62
|
-
labelText={t(
|
|
63
|
-
{...register(
|
|
62
|
+
labelText={t('practitionerName', 'Practitioner Name')}
|
|
63
|
+
{...register('practitionerName', { required: true })}
|
|
64
64
|
invalid={errors.practitionerName}
|
|
65
|
-
invalidText={
|
|
65
|
+
invalidText={t('requiredField', 'This field is required')}
|
|
66
66
|
/>
|
|
67
67
|
<Controller
|
|
68
68
|
name="sessionDate"
|
|
69
69
|
control={control}
|
|
70
70
|
rules={{ required: true }}
|
|
71
71
|
render={({ field }) => (
|
|
72
|
-
<DatePicker
|
|
73
|
-
datePickerType="single"
|
|
74
|
-
size="md"
|
|
75
|
-
maxDate={new Date()}
|
|
76
|
-
{...field}
|
|
77
|
-
>
|
|
72
|
+
<DatePicker datePickerType="single" size="md" maxDate={new Date()} {...field}>
|
|
78
73
|
<DatePickerInput
|
|
79
74
|
id="session-date"
|
|
80
|
-
labelText={t(
|
|
75
|
+
labelText={t('sessionDate', 'Session Date')}
|
|
81
76
|
placeholder="mm/dd/yyyy"
|
|
82
77
|
size="md"
|
|
83
78
|
invalid={errors.sessionDate}
|
|
84
|
-
invalidText={
|
|
79
|
+
invalidText={t('requiredField', 'This field is required')}
|
|
85
80
|
/>
|
|
86
81
|
</DatePicker>
|
|
87
82
|
)}
|
|
@@ -89,21 +84,21 @@ const SessionDetailsForm = () => {
|
|
|
89
84
|
<TextArea
|
|
90
85
|
id="text"
|
|
91
86
|
type="text"
|
|
92
|
-
labelText={t(
|
|
93
|
-
{...register(
|
|
87
|
+
labelText={t('sessionNotes', 'Session Notes')}
|
|
88
|
+
{...register('sessionNotes', { required: true })}
|
|
94
89
|
invalid={errors.sessionNotes}
|
|
95
|
-
invalidText={
|
|
90
|
+
invalidText={t('requiredField', 'This field is required')}
|
|
96
91
|
/>
|
|
97
92
|
</div>
|
|
98
93
|
</Layer>
|
|
99
94
|
</Tile>
|
|
100
95
|
</Layer>
|
|
101
|
-
<h4>{t(
|
|
96
|
+
<h4>{t('sessionParticipants', '2. Session participants')}</h4>
|
|
102
97
|
<div>
|
|
103
98
|
<p>
|
|
104
99
|
{t(
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
'markAbsentPatients',
|
|
101
|
+
'The patients in this group. Patients that are not present in the session should be marked as absent.',
|
|
107
102
|
)}
|
|
108
103
|
</p>
|
|
109
104
|
</div>
|
|
@@ -112,9 +107,9 @@ const SessionDetailsForm = () => {
|
|
|
112
107
|
<Layer>
|
|
113
108
|
<div
|
|
114
109
|
style={{
|
|
115
|
-
display:
|
|
116
|
-
flexDirection:
|
|
117
|
-
rowGap:
|
|
110
|
+
display: 'flex',
|
|
111
|
+
flexDirection: 'column',
|
|
112
|
+
rowGap: '1.5rem',
|
|
118
113
|
}}
|
|
119
114
|
>
|
|
120
115
|
<AttendanceTable patients={patients} />
|
|
@@ -122,6 +117,34 @@ const SessionDetailsForm = () => {
|
|
|
122
117
|
</Layer>
|
|
123
118
|
</Tile>
|
|
124
119
|
</Layer>
|
|
120
|
+
{questions?.length > 0 ? (
|
|
121
|
+
<>
|
|
122
|
+
<h4>{t('sessionSpecificDetails', '3. Specific details')}</h4>
|
|
123
|
+
<div>
|
|
124
|
+
<p>
|
|
125
|
+
{t(
|
|
126
|
+
'sessionSpecificDetailsDescription',
|
|
127
|
+
'They will be mapped to form responses for all patients as pre-filled data.',
|
|
128
|
+
)}
|
|
129
|
+
</p>
|
|
130
|
+
</div>
|
|
131
|
+
<Layer>
|
|
132
|
+
<Tile className={styles.formSectionTile}>
|
|
133
|
+
<Layer>
|
|
134
|
+
<div
|
|
135
|
+
style={{
|
|
136
|
+
display: 'flex',
|
|
137
|
+
flexDirection: 'column',
|
|
138
|
+
rowGap: '1.5rem',
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
141
|
+
<ConfigurableQuestionsSection register={register} specificQuestions={questions} />
|
|
142
|
+
</div>
|
|
143
|
+
</Layer>
|
|
144
|
+
</Tile>
|
|
145
|
+
</Layer>
|
|
146
|
+
</>
|
|
147
|
+
) : null}
|
|
125
148
|
</div>
|
|
126
149
|
)}
|
|
127
150
|
</div>
|
|
@@ -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,19 +65,13 @@ 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
|
-
const
|
|
74
|
+
const onPostCancel = useCallback(() => {
|
|
87
75
|
setOpen(false);
|
|
88
76
|
}, []);
|
|
89
77
|
|
|
@@ -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
|
|
@@ -116,7 +104,7 @@ const AttendanceTable = ({ patients }) => {
|
|
|
116
104
|
isCreate: false,
|
|
117
105
|
groupName: activeGroupName,
|
|
118
106
|
isOpen: isOpen,
|
|
119
|
-
|
|
107
|
+
onPostCancel: onPostCancel,
|
|
120
108
|
onPostSubmit: onPostSubmit,
|
|
121
109
|
}}
|
|
122
110
|
/>
|
|
@@ -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';
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
|
|
6
|
+
interface ConfigurableQuestionsSectionProps {
|
|
7
|
+
specificQuestions: Array<SpecificQuestion>;
|
|
8
|
+
register?: UseFormRegister<FieldValues>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const ConfigurableQuestionsSection: React.FC<ConfigurableQuestionsSectionProps> = ({ register, specificQuestions }) => {
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
{specificQuestions?.map((specificQuestion) => (
|
|
15
|
+
<div key={specificQuestion.question.id}>
|
|
16
|
+
{specificQuestion?.answers?.length > 0 ? (
|
|
17
|
+
<Select
|
|
18
|
+
{...register(specificQuestion.question.id, { required: false })}
|
|
19
|
+
id={specificQuestion.question.id}
|
|
20
|
+
labelText={specificQuestion.question.display}
|
|
21
|
+
readOnly={!!specificQuestion.question.disabled}
|
|
22
|
+
defaultValue={specificQuestion.question.defaultAnswer}
|
|
23
|
+
>
|
|
24
|
+
<SelectItem value="" text="" />
|
|
25
|
+
{specificQuestion.answers.map((answer) => (
|
|
26
|
+
<SelectItem key={answer.value} value={answer.value} text={answer.display} />
|
|
27
|
+
))}
|
|
28
|
+
</Select>
|
|
29
|
+
) : (
|
|
30
|
+
<TextInput
|
|
31
|
+
id={specificQuestion.question.id}
|
|
32
|
+
{...register(specificQuestion.question.id, { required: false })}
|
|
33
|
+
type="text"
|
|
34
|
+
labelText={specificQuestion.question.display}
|
|
35
|
+
readOnly={!!specificQuestion.question.disabled}
|
|
36
|
+
defaultValue={specificQuestion.question.defaultAnswer}
|
|
37
|
+
/>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
))}
|
|
41
|
+
</>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default ConfigurableQuestionsSection;
|
|
@@ -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,26 +1,26 @@
|
|
|
1
|
-
@use '@carbon/
|
|
2
|
-
@use '@carbon/
|
|
3
|
-
@
|
|
1
|
+
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/type';
|
|
4
4
|
|
|
5
5
|
.container {
|
|
6
|
-
height:
|
|
6
|
+
height: layout.$spacing-11;
|
|
7
7
|
display: flex;
|
|
8
8
|
align-items: center;
|
|
9
|
-
background-color:
|
|
10
|
-
border-top: 0.0125rem solid
|
|
11
|
-
border-bottom: 0.0125rem solid
|
|
12
|
-
padding: 0
|
|
9
|
+
background-color: colors.$white-0;
|
|
10
|
+
border-top: 0.0125rem solid colors.$gray-20;
|
|
11
|
+
border-bottom: 0.0125rem solid colors.$gray-20;
|
|
12
|
+
padding: 0 layout.$spacing-05;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.photoPlaceholder {
|
|
16
|
-
height:
|
|
17
|
-
width:
|
|
16
|
+
height: layout.$spacing-09;
|
|
17
|
+
width: layout.$spacing-09;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.groupAvatar {
|
|
21
|
-
width:
|
|
22
|
-
height:
|
|
23
|
-
margin:
|
|
21
|
+
width: layout.$spacing-09;
|
|
22
|
+
height: layout.$spacing-09;
|
|
23
|
+
margin: layout.$spacing-03 layout.$spacing-05 layout.$spacing-03 0;
|
|
24
24
|
border-radius: 1px;
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -30,29 +30,29 @@
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
.groupInfoContent {
|
|
33
|
-
margin-left:
|
|
34
|
-
margin-right:
|
|
33
|
+
margin-left: layout.$spacing-05;
|
|
34
|
+
margin-right: layout.$spacing-10;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
.groupInfoRow {
|
|
38
38
|
display: flex;
|
|
39
39
|
align-items: center;
|
|
40
40
|
& > button {
|
|
41
|
-
min-height:
|
|
41
|
+
min-height: layout.$spacing-07;
|
|
42
42
|
}
|
|
43
43
|
@include type.type-style('body-compact-02');
|
|
44
|
-
color:
|
|
44
|
+
color: colors.$gray-70;
|
|
45
45
|
column-gap: 0.8rem;
|
|
46
46
|
|
|
47
47
|
}
|
|
48
48
|
.sessionNotesLabel {
|
|
49
49
|
@include type.type-style('label-01');
|
|
50
|
-
margin-bottom:
|
|
50
|
+
margin-bottom: layout.$spacing-01
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
.groupEditBtn {
|
|
54
|
-
color:
|
|
55
|
-
margin:
|
|
54
|
+
color: colors.$gray-100;
|
|
55
|
+
margin: layout.$spacing-03;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
.groupMetaContent {
|