@kenyaemr/esm-patient-registration-app 5.2.1 → 5.2.3
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/102.js +1 -0
- package/dist/102.js.map +1 -0
- package/dist/130.js +1 -1
- package/dist/130.js.map +1 -1
- package/dist/271.js +1 -0
- package/dist/319.js +1 -1
- package/dist/431.js +2 -0
- package/dist/431.js.map +1 -0
- package/dist/460.js +1 -1
- package/dist/537.js +1 -1
- package/dist/537.js.map +1 -1
- package/dist/574.js +1 -1
- package/dist/644.js +1 -0
- package/dist/757.js +1 -1
- package/dist/784.js +1 -1
- package/dist/788.js +1 -1
- package/dist/807.js +1 -1
- package/dist/833.js +1 -1
- package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
- package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +91 -47
- package/dist/kenyaemr-esm-patient-registration-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/dist.tar.gz +0 -0
- package/package.json +3 -2
- package/src/add-patient-link.test.tsx +9 -7
- package/src/config-schema.ts +31 -38
- package/src/constants.ts +1 -1
- package/src/offline.resources.ts +1 -1
- package/src/offline.ts +2 -2
- package/src/patient-registration/before-save-prompt.tsx +2 -1
- package/src/patient-registration/field/__mocks__/field.resource.ts +1 -1
- package/src/patient-registration/field/address/address-field.component.tsx +5 -4
- package/src/patient-registration/field/address/address-hierarchy.resource.tsx +2 -2
- package/src/patient-registration/field/address/address-search.component.tsx +1 -14
- package/src/patient-registration/field/address/custom-address-field.component.tsx +1 -1
- package/src/patient-registration/field/address/tests/address-hierarchy.test.tsx +3 -3
- package/src/patient-registration/field/address/tests/address-search-component.test.tsx +14 -7
- package/src/patient-registration/field/custom-field.component.tsx +1 -1
- package/src/patient-registration/field/dob/dob.component.tsx +2 -2
- package/src/patient-registration/field/dob/dob.test.tsx +0 -3
- package/src/patient-registration/field/field.component.tsx +4 -1
- package/src/patient-registration/field/field.resource.ts +2 -2
- package/src/patient-registration/field/field.test.tsx +98 -95
- package/src/patient-registration/field/gender/gender-field.component.tsx +4 -4
- package/src/patient-registration/field/gender/gender-field.test.tsx +7 -14
- package/src/patient-registration/field/id/id-field.component.tsx +6 -6
- package/src/patient-registration/field/id/id-field.test.tsx +9 -7
- package/src/patient-registration/field/id/identifier-selection-overlay.component.tsx +1 -1
- package/src/patient-registration/field/name/name-field.component.tsx +1 -1
- package/src/patient-registration/field/obs/obs-field.component.tsx +35 -33
- package/src/patient-registration/field/obs/obs-field.test.tsx +106 -28
- package/src/patient-registration/field/person-attributes/coded-attributes.component.tsx +1 -1
- package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +67 -24
- package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +54 -30
- package/src/patient-registration/field/person-attributes/person-attribute-field.component.tsx +4 -3
- package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +1 -1
- package/src/patient-registration/field/person-attributes/{person-attributes.resource.tsx → person-attributes.resource.ts} +2 -2
- package/src/patient-registration/field/person-attributes/text-person-attribute-field.component.tsx +1 -1
- package/src/patient-registration/field/phone/phone-field.component.tsx +16 -0
- package/src/patient-registration/form-manager.test.ts +1 -1
- package/src/patient-registration/form-manager.ts +14 -22
- package/src/patient-registration/input/basic-input/select/select-input.test.tsx +3 -3
- package/src/patient-registration/input/custom-input/autosuggest/autosuggest.component.tsx +5 -5
- package/src/patient-registration/input/custom-input/autosuggest/autosuggest.test.tsx +70 -58
- package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +1 -1
- package/src/patient-registration/input/custom-input/identifier/identifier-input.test.tsx +2 -5
- package/src/patient-registration/input/custom-input/identifier/utils.ts +1 -1
- package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +1 -1
- package/src/patient-registration/input/dummy-data/dummy-data-input.test.tsx +6 -6
- package/src/patient-registration/patient-registration-context.ts +3 -4
- package/src/patient-registration/patient-registration-hooks.ts +12 -12
- package/src/patient-registration/patient-registration-utils.ts +7 -7
- package/src/patient-registration/patient-registration.component.tsx +7 -7
- package/src/patient-registration/{patient-registration.resource.tsx → patient-registration.resource.ts} +1 -1
- package/src/patient-registration/patient-registration.test.tsx +270 -251
- package/src/patient-registration/{patient-registration.types.tsx → patient-registration.types.ts} +11 -3
- package/src/patient-registration/section/death-info/death-info-section.test.tsx +33 -45
- package/src/patient-registration/section/demographics/demographics-section.test.tsx +1 -2
- package/src/patient-registration/section/generic-section.component.tsx +1 -1
- package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +3 -3
- package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +17 -5
- package/src/patient-registration/section/patient-relationships/relationships.resource.tsx +3 -3
- package/src/patient-registration/section/section-wrapper.component.tsx +1 -1
- package/src/patient-registration/section/section.component.tsx +1 -1
- package/src/patient-registration/validation/patient-registration-validation.test.tsx +140 -126
- package/src/patient-registration/validation/patient-registration-validation.tsx +54 -46
- package/src/widgets/cancel-patient-edit.test.tsx +7 -4
- package/src/widgets/delete-identifier-confirmation-modal.test.tsx +7 -4
- package/src/widgets/display-photo.test.tsx +1 -1
- package/src/widgets/edit-patient-details-button.test.tsx +12 -7
- package/translations/am.json +4 -2
- package/translations/ar.json +4 -2
- package/translations/en.json +4 -2
- package/translations/es.json +4 -2
- package/translations/fr.json +4 -2
- package/translations/he.json +4 -2
- package/translations/km.json +4 -2
- package/translations/zh.json +89 -0
- package/translations/zh_CN.json +89 -0
- package/tsconfig.json +1 -1
- package/__mocks__/autogenerationoptions.mock.ts +0 -34
- package/dist/388.js +0 -2
- package/dist/388.js.map +0 -1
- package/dist/598.js +0 -1
- package/dist/598.js.map +0 -1
- package/src/patient-registration/field/__mocks__/identifier-types.mock.ts +0 -76
- package/src/patient-registration/field/__mocks__/identifiers.mock.ts +0 -27
- package/src/patient-registration/field/address/tests/mocks.ts +0 -98
- /package/dist/{388.js.LICENSE.txt → 431.js.LICENSE.txt} +0 -0
|
@@ -1,28 +1,31 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { Form, Formik } from 'formik';
|
|
2
3
|
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { Field } from './field.component';
|
|
4
4
|
import { useConfig } from '@openmrs/esm-framework';
|
|
5
|
+
import { Field } from './field.component';
|
|
6
|
+
import type { AddressTemplate, FormValues } from '../patient-registration.types';
|
|
7
|
+
import { type Resources, ResourcesContext } from '../../offline.resources';
|
|
5
8
|
import { PatientRegistrationContext } from '../patient-registration-context';
|
|
6
|
-
import { Resources, ResourcesContext } from '../../offline.resources';
|
|
7
|
-
import { Form, Formik } from 'formik';
|
|
8
9
|
|
|
9
10
|
jest.mock('@openmrs/esm-framework', () => ({
|
|
10
11
|
...jest.requireActual('@openmrs/esm-framework'),
|
|
11
12
|
useConfig: jest.fn(),
|
|
12
13
|
}));
|
|
14
|
+
|
|
13
15
|
const predefinedAddressTemplate = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
uuid: 'test-address-template-uuid',
|
|
17
|
+
property: 'layout.address.format',
|
|
18
|
+
description: 'Test Address Template',
|
|
19
|
+
display:
|
|
20
|
+
'Layout - Address Format = <org.openmrs.layout.address.AddressTemplate>\n <nameMappings class="properties">\n <property name="postalCode" value="Location.postalCode"/>\n <property name="address2" value="Location.address2"/>\n <property name="address1" value="Location.address1"/>\n <property name="country" value="Location.country"/>\n <property name="stateProvince" value="Location.stateProvince"/>\n <property name="cityVillage" value="Location.cityVillage"/>\n </nameMappings>\n <sizeMappings class="properties">\n <property name="postalCode" value="10"/>\n <property name="address2" value="40"/>\n <property name="address1" value="40"/>\n <property name="country" value="10"/>\n <property name="stateProvince" value="10"/>\n <property name="cityVillage" value="10"/>\n </sizeMappings>\n <lineByLineFormat>\n <string>address1</string>\n <string>address2</string>\n <string>cityVillage stateProvince country postalCode</string>\n </lineByLineFormat>\n </org.openmrs.layout.address.AddressTemplate>',
|
|
21
|
+
value:
|
|
22
|
+
'<org.openmrs.layout.address.AddressTemplate>\r\n <nameMappings class="properties">\r\n <property name="postalCode" value="Location.postalCode"/>\r\n <property name="address2" value="Location.address2"/>\r\n <property name="address1" value="Location.address1"/>\r\n <property name="country" value="Location.country"/>\r\n <property name="stateProvince" value="Location.stateProvince"/>\r\n <property name="cityVillage" value="Location.cityVillage"/>\r\n </nameMappings>\r\n <sizeMappings class="properties">\r\n <property name="postalCode" value="4"/>\r\n <property name="address1" value="40"/>\r\n <property name="address2" value="40"/>\r\n <property name="country" value="10"/>\r\n <property name="stateProvince" value="10"/>\r\n <property name="cityVillage" value="10"/>\r\n <asset name="cityVillage" value="10"/>\r\n </sizeMappings>\r\n <lineByLineFormat>\r\n <string>address1 address2</string>\r\n <string>cityVillage stateProvince postalCode</string>\r\n <string>country</string>\r\n </lineByLineFormat>\r\n <elementDefaults class="properties">\r\n <property name="country" value=""/>\r\n </elementDefaults>\r\n <elementRegex class="properties">\r\n <property name="address1" value="[a-zA-Z]+$"/>\r\n </elementRegex>\r\n <elementRegexFormats class="properties">\r\n <property name="address1" value="Countries can only be letters"/>\r\n </elementRegexFormats>\r\n </org.openmrs.layout.address.AddressTemplate>',
|
|
20
23
|
};
|
|
21
24
|
|
|
22
25
|
const mockedIdentifierTypes = [
|
|
23
26
|
{
|
|
24
27
|
fieldName: 'openMrsId',
|
|
25
|
-
format:
|
|
28
|
+
format: '',
|
|
26
29
|
identifierSources: [
|
|
27
30
|
{
|
|
28
31
|
uuid: '8549f706-7e85-4c1d-9424-217d50a2988b',
|
|
@@ -35,22 +38,22 @@ const mockedIdentifierTypes = [
|
|
|
35
38
|
isPrimary: true,
|
|
36
39
|
name: 'OpenMRS ID',
|
|
37
40
|
required: true,
|
|
38
|
-
uniquenessBehavior: 'UNIQUE',
|
|
41
|
+
uniquenessBehavior: 'UNIQUE' as const,
|
|
39
42
|
uuid: '05a29f94-c0ed-11e2-94be-8c13b969e334',
|
|
40
43
|
},
|
|
41
44
|
{
|
|
42
45
|
fieldName: 'idCard',
|
|
43
|
-
format:
|
|
46
|
+
format: '',
|
|
44
47
|
identifierSources: [],
|
|
45
48
|
isPrimary: false,
|
|
46
49
|
name: 'ID Card',
|
|
47
50
|
required: false,
|
|
48
|
-
uniquenessBehavior: 'UNIQUE',
|
|
51
|
+
uniquenessBehavior: 'UNIQUE' as const,
|
|
49
52
|
uuid: 'b4143563-16cd-4439-b288-f83d61670fc8',
|
|
50
53
|
},
|
|
51
54
|
{
|
|
52
55
|
fieldName: 'legacyId',
|
|
53
|
-
format:
|
|
56
|
+
format: '',
|
|
54
57
|
identifierSources: [],
|
|
55
58
|
isPrimary: false,
|
|
56
59
|
name: 'Legacy ID',
|
|
@@ -79,8 +82,9 @@ const mockedIdentifierTypes = [
|
|
|
79
82
|
uuid: '8d793bee-c2cc-11de-8d13-0010c6dffd0f',
|
|
80
83
|
},
|
|
81
84
|
];
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
|
|
86
|
+
const mockResourcesContextValue: Resources = {
|
|
87
|
+
addressTemplate: predefinedAddressTemplate as unknown as AddressTemplate,
|
|
84
88
|
currentSession: {
|
|
85
89
|
authenticated: true,
|
|
86
90
|
sessionId: 'JSESSION',
|
|
@@ -88,10 +92,39 @@ const mockResourcesContextValue = {
|
|
|
88
92
|
},
|
|
89
93
|
relationshipTypes: [],
|
|
90
94
|
identifierTypes: [...mockedIdentifierTypes],
|
|
91
|
-
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const initialContextValues = {
|
|
98
|
+
currentPhoto: 'data:image/png;base64,1234567890',
|
|
99
|
+
identifierTypes: [],
|
|
100
|
+
inEditMode: false,
|
|
101
|
+
initialFormValues: {} as FormValues,
|
|
102
|
+
isOffline: false,
|
|
103
|
+
setCapturePhotoProps: jest.fn(),
|
|
104
|
+
setFieldValue: jest.fn(),
|
|
105
|
+
setInitialFormValues: jest.fn(),
|
|
106
|
+
validationSchema: null,
|
|
107
|
+
values: {} as FormValues,
|
|
108
|
+
};
|
|
92
109
|
|
|
93
110
|
describe('Field', () => {
|
|
111
|
+
let ContextWrapper;
|
|
112
|
+
|
|
94
113
|
beforeEach(() => {
|
|
114
|
+
ContextWrapper = ({ children }) => (
|
|
115
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
116
|
+
<Formik initialValues={{}} onSubmit={jest.fn()}>
|
|
117
|
+
<Form>
|
|
118
|
+
<PatientRegistrationContext.Provider value={initialContextValues}>
|
|
119
|
+
{children}
|
|
120
|
+
</PatientRegistrationContext.Provider>
|
|
121
|
+
</Form>
|
|
122
|
+
</Formik>
|
|
123
|
+
</ResourcesContext.Provider>
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
afterEach(() => {
|
|
95
128
|
jest.clearAllMocks();
|
|
96
129
|
});
|
|
97
130
|
|
|
@@ -106,22 +139,9 @@ describe('Field', () => {
|
|
|
106
139
|
},
|
|
107
140
|
},
|
|
108
141
|
}));
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
<Form>
|
|
113
|
-
<PatientRegistrationContext.Provider
|
|
114
|
-
value={{
|
|
115
|
-
setFieldValue: jest.fn(),
|
|
116
|
-
setInitialFormValues: jest.fn(),
|
|
117
|
-
values: {},
|
|
118
|
-
}}>
|
|
119
|
-
<Field name="name" />
|
|
120
|
-
</PatientRegistrationContext.Provider>
|
|
121
|
-
</Form>
|
|
122
|
-
</Formik>
|
|
123
|
-
</ResourcesContext.Provider>,
|
|
124
|
-
);
|
|
142
|
+
|
|
143
|
+
render(<Field name="name" />, { wrapper: ContextWrapper });
|
|
144
|
+
|
|
125
145
|
expect(screen.getByText('Full Name')).toBeInTheDocument();
|
|
126
146
|
});
|
|
127
147
|
|
|
@@ -137,22 +157,9 @@ describe('Field', () => {
|
|
|
137
157
|
],
|
|
138
158
|
},
|
|
139
159
|
}));
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
<Form>
|
|
144
|
-
<PatientRegistrationContext.Provider
|
|
145
|
-
value={{
|
|
146
|
-
setFieldValue: jest.fn(),
|
|
147
|
-
setInitialFormValues: jest.fn(),
|
|
148
|
-
values: {},
|
|
149
|
-
}}>
|
|
150
|
-
<Field name="gender" />
|
|
151
|
-
</PatientRegistrationContext.Provider>
|
|
152
|
-
</Form>
|
|
153
|
-
</Formik>
|
|
154
|
-
</ResourcesContext.Provider>,
|
|
155
|
-
);
|
|
160
|
+
|
|
161
|
+
render(<Field name="gender" />, { wrapper: ContextWrapper });
|
|
162
|
+
|
|
156
163
|
expect(screen.getByLabelText('Male')).toBeInTheDocument();
|
|
157
164
|
});
|
|
158
165
|
|
|
@@ -165,22 +172,7 @@ describe('Field', () => {
|
|
|
165
172
|
},
|
|
166
173
|
},
|
|
167
174
|
}));
|
|
168
|
-
render(
|
|
169
|
-
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
170
|
-
<Formik initialValues={{}} onSubmit={null}>
|
|
171
|
-
<Form>
|
|
172
|
-
<PatientRegistrationContext.Provider
|
|
173
|
-
value={{
|
|
174
|
-
setFieldValue: jest.fn(),
|
|
175
|
-
setInitialFormValues: jest.fn(),
|
|
176
|
-
values: {},
|
|
177
|
-
}}>
|
|
178
|
-
<Field name="dob" />
|
|
179
|
-
</PatientRegistrationContext.Provider>
|
|
180
|
-
</Form>
|
|
181
|
-
</Formik>
|
|
182
|
-
</ResourcesContext.Provider>,
|
|
183
|
-
);
|
|
175
|
+
render(<Field name="dob" />, { wrapper: ContextWrapper });
|
|
184
176
|
expect(screen.getByText('Birth')).toBeInTheDocument();
|
|
185
177
|
});
|
|
186
178
|
|
|
@@ -200,22 +192,9 @@ describe('Field', () => {
|
|
|
200
192
|
},
|
|
201
193
|
},
|
|
202
194
|
}));
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
<Form>
|
|
207
|
-
<PatientRegistrationContext.Provider
|
|
208
|
-
value={{
|
|
209
|
-
setFieldValue: jest.fn(),
|
|
210
|
-
setInitialFormValues: jest.fn(),
|
|
211
|
-
values: {},
|
|
212
|
-
}}>
|
|
213
|
-
<Field name="address" />
|
|
214
|
-
</PatientRegistrationContext.Provider>
|
|
215
|
-
</Form>
|
|
216
|
-
</Formik>
|
|
217
|
-
</ResourcesContext.Provider>,
|
|
218
|
-
);
|
|
195
|
+
|
|
196
|
+
render(<Field name="address" />, { wrapper: ContextWrapper });
|
|
197
|
+
|
|
219
198
|
expect(screen.getByText('Address')).toBeInTheDocument();
|
|
220
199
|
});
|
|
221
200
|
|
|
@@ -223,7 +202,7 @@ describe('Field', () => {
|
|
|
223
202
|
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
224
203
|
defaultPatientIdentifierTypes: ['OpenMRS ID'],
|
|
225
204
|
}));
|
|
226
|
-
|
|
205
|
+
|
|
227
206
|
const openmrsID = {
|
|
228
207
|
name: 'OpenMRS ID',
|
|
229
208
|
fieldName: 'openMrsId',
|
|
@@ -249,21 +228,41 @@ describe('Field', () => {
|
|
|
249
228
|
},
|
|
250
229
|
},
|
|
251
230
|
],
|
|
231
|
+
identifierUuid: 'openmrs-identifier-uuid',
|
|
232
|
+
identifierTypeUuid: 'openmrs-id-identifier-type-uuid',
|
|
233
|
+
initialValue: '12345',
|
|
234
|
+
identifierValue: '12345',
|
|
235
|
+
identifierName: 'OpenMRS ID',
|
|
236
|
+
preferred: true,
|
|
237
|
+
selectedSource: {
|
|
238
|
+
uuid: 'openmrs-id-selected-source-uuid',
|
|
239
|
+
name: 'Generator 1 for OpenMRS ID',
|
|
240
|
+
autoGenerationOption: {
|
|
241
|
+
manualEntryEnabled: false,
|
|
242
|
+
automaticGenerationEnabled: true,
|
|
243
|
+
},
|
|
244
|
+
},
|
|
252
245
|
autoGenerationSource: null,
|
|
253
246
|
};
|
|
247
|
+
|
|
248
|
+
const updatedContextValues = {
|
|
249
|
+
currentPhoto: 'data:image/png;base64,1234567890',
|
|
250
|
+
identifierTypes: [],
|
|
251
|
+
inEditMode: false,
|
|
252
|
+
initialFormValues: { identifiers: { openmrsID } } as unknown as FormValues,
|
|
253
|
+
isOffline: false,
|
|
254
|
+
setCapturePhotoProps: jest.fn(),
|
|
255
|
+
setFieldValue: jest.fn(),
|
|
256
|
+
setInitialFormValues: jest.fn(),
|
|
257
|
+
validationSchema: null,
|
|
258
|
+
values: { identifiers: { openmrsID } } as unknown as FormValues,
|
|
259
|
+
};
|
|
260
|
+
|
|
254
261
|
render(
|
|
255
262
|
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
256
|
-
<Formik initialValues={{}} onSubmit={
|
|
263
|
+
<Formik initialValues={{}} onSubmit={jest.fn()}>
|
|
257
264
|
<Form>
|
|
258
|
-
<PatientRegistrationContext.Provider
|
|
259
|
-
value={{
|
|
260
|
-
setFieldValue: jest.fn(),
|
|
261
|
-
initialFormValues: { identifiers: { openmrsID } },
|
|
262
|
-
setInitialFormValues: jest.fn(),
|
|
263
|
-
values: {
|
|
264
|
-
identifiers: { openmrsID },
|
|
265
|
-
},
|
|
266
|
-
}}>
|
|
265
|
+
<PatientRegistrationContext.Provider value={updatedContextValues}>
|
|
267
266
|
<Field name="id" />
|
|
268
267
|
</PatientRegistrationContext.Provider>
|
|
269
268
|
</Form>
|
|
@@ -274,18 +273,22 @@ describe('Field', () => {
|
|
|
274
273
|
});
|
|
275
274
|
|
|
276
275
|
it('should return null and report an error for an invalid field name', () => {
|
|
276
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
277
|
+
|
|
277
278
|
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
278
279
|
fieldDefinitions: [{ id: 'weight' }],
|
|
279
280
|
}));
|
|
280
281
|
let error = null;
|
|
282
|
+
|
|
281
283
|
try {
|
|
282
284
|
render(<Field name="invalidField" />);
|
|
283
285
|
} catch (err) {
|
|
284
286
|
error = err;
|
|
285
287
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
);
|
|
288
|
+
|
|
289
|
+
expect(error).toMatch(/Invalid field name 'invalidField'. Valid options are /);
|
|
289
290
|
expect(screen.queryByTestId('invalid-field')).not.toBeInTheDocument();
|
|
291
|
+
|
|
292
|
+
consoleError.mockRestore();
|
|
290
293
|
});
|
|
291
294
|
});
|
|
@@ -4,7 +4,7 @@ import styles from '../field.scss';
|
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { PatientRegistrationContext } from '../../patient-registration-context';
|
|
6
6
|
import { useField } from 'formik';
|
|
7
|
-
import { RegistrationConfig } from '../../../config-schema';
|
|
7
|
+
import { type RegistrationConfig } from '../../../config-schema';
|
|
8
8
|
import { useConfig } from '@openmrs/esm-framework';
|
|
9
9
|
|
|
10
10
|
export const GenderField: React.FC = () => {
|
|
@@ -33,10 +33,10 @@ export const GenderField: React.FC = () => {
|
|
|
33
33
|
<RadioButtonGroup name="gender" orientation="vertical" onChange={setGender} valueSelected={field.value}>
|
|
34
34
|
{fieldConfigs.map((option) => (
|
|
35
35
|
<RadioButton
|
|
36
|
-
key={option.label}
|
|
37
|
-
id={option.
|
|
36
|
+
key={option.label ?? option.value}
|
|
37
|
+
id={`gender-option-${option.value}`}
|
|
38
38
|
value={option.value}
|
|
39
|
-
labelText={t(
|
|
39
|
+
labelText={t(option.label ?? option.value, option.label ?? option.value)}
|
|
40
40
|
/>
|
|
41
41
|
))}
|
|
42
42
|
</RadioButtonGroup>
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import
|
|
3
|
-
import '@testing-library/jest-dom/extend-expect';
|
|
4
|
-
import '@testing-library/jest-dom';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
5
3
|
import { Formik, Form } from 'formik';
|
|
6
|
-
|
|
4
|
+
import { render } from '@testing-library/react';
|
|
7
5
|
import { GenderField } from './gender-field.component';
|
|
8
6
|
|
|
9
7
|
jest.mock('@openmrs/esm-framework', () => ({
|
|
@@ -12,9 +10,8 @@ jest.mock('@openmrs/esm-framework', () => ({
|
|
|
12
10
|
fieldConfigurations: {
|
|
13
11
|
gender: [
|
|
14
12
|
{
|
|
15
|
-
value: '
|
|
13
|
+
value: 'male',
|
|
16
14
|
label: 'Male',
|
|
17
|
-
id: 'male',
|
|
18
15
|
},
|
|
19
16
|
],
|
|
20
17
|
name: {
|
|
@@ -50,17 +47,13 @@ describe('GenderField', () => {
|
|
|
50
47
|
);
|
|
51
48
|
};
|
|
52
49
|
|
|
53
|
-
it('renders', () => {
|
|
54
|
-
expect(renderComponent()).not.toBeNull();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
50
|
it('has a label', () => {
|
|
58
51
|
expect(renderComponent().getAllByText('Sex')).toBeTruthy();
|
|
59
52
|
});
|
|
60
53
|
|
|
61
|
-
it('checks an option', () => {
|
|
54
|
+
it('checks an option', async () => {
|
|
55
|
+
const user = userEvent.setup();
|
|
62
56
|
const component = renderComponent();
|
|
63
|
-
|
|
64
|
-
expect(component.getByLabelText('Male')).toBeChecked();
|
|
57
|
+
expect(component.getByLabelText('Male').getAttribute('value')).toBe('male');
|
|
65
58
|
});
|
|
66
59
|
});
|
|
@@ -7,10 +7,10 @@ import IdentifierSelectionOverlay from './identifier-selection-overlay.component
|
|
|
7
7
|
import { IdentifierInput } from '../../input/custom-input/identifier/identifier-input.component';
|
|
8
8
|
import { PatientRegistrationContext } from '../../patient-registration-context';
|
|
9
9
|
import {
|
|
10
|
-
FormValues,
|
|
11
|
-
IdentifierSource,
|
|
12
|
-
PatientIdentifierType,
|
|
13
|
-
PatientIdentifierValue,
|
|
10
|
+
type FormValues,
|
|
11
|
+
type IdentifierSource,
|
|
12
|
+
type PatientIdentifierType,
|
|
13
|
+
type PatientIdentifierValue,
|
|
14
14
|
} from '../../patient-registration.types';
|
|
15
15
|
import { ResourcesContext } from '../../../offline.resources';
|
|
16
16
|
import styles from '../field.scss';
|
|
@@ -31,8 +31,8 @@ export function setIdentifierSource(
|
|
|
31
31
|
identifierValue: autoGeneration
|
|
32
32
|
? 'auto-generated'
|
|
33
33
|
: identifierValue !== 'auto-generated'
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
? identifierValue
|
|
35
|
+
: initialValue,
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
3
4
|
import { Identifiers } from './id-field.component';
|
|
4
|
-
import { Resources, ResourcesContext } from '../../../offline.resources';
|
|
5
|
+
import { type Resources, ResourcesContext } from '../../../offline.resources';
|
|
5
6
|
import { Form, Formik } from 'formik';
|
|
6
7
|
import { PatientRegistrationContext } from '../../patient-registration-context';
|
|
7
|
-
import { openmrsID } from '
|
|
8
|
-
import { mockedIdentifierTypes } from '../__mocks__/identifier-types.mock';
|
|
8
|
+
import { openmrsID, mockedIdentifierTypes } from '__mocks__';
|
|
9
9
|
|
|
10
10
|
jest.mock('@openmrs/esm-framework', () => ({
|
|
11
11
|
...jest.requireActual('@openmrs/esm-framework'),
|
|
@@ -16,7 +16,7 @@ jest.mock('@openmrs/esm-framework', () => ({
|
|
|
16
16
|
|
|
17
17
|
describe('Identifiers', () => {
|
|
18
18
|
const mockResourcesContextValue = {
|
|
19
|
-
addressTemplate:
|
|
19
|
+
addressTemplate: {},
|
|
20
20
|
currentSession: {
|
|
21
21
|
authenticated: true,
|
|
22
22
|
sessionId: 'JSESSION',
|
|
@@ -76,7 +76,9 @@ describe('Identifiers', () => {
|
|
|
76
76
|
expect(configureButton).toBeEnabled();
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
it('should open identifier selection overlay when "Configure" button is clicked', () => {
|
|
79
|
+
it('should open identifier selection overlay when "Configure" button is clicked', async () => {
|
|
80
|
+
const user = userEvent.setup();
|
|
81
|
+
|
|
80
82
|
render(
|
|
81
83
|
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
82
84
|
<Formik initialValues={{}} onSubmit={null}>
|
|
@@ -98,7 +100,7 @@ describe('Identifiers', () => {
|
|
|
98
100
|
);
|
|
99
101
|
|
|
100
102
|
const configureButton = screen.getByRole('button', { name: 'Configure' });
|
|
101
|
-
|
|
103
|
+
await user.click(configureButton);
|
|
102
104
|
|
|
103
105
|
expect(screen.getByRole('button', { name: 'Close overlay' })).toBeInTheDocument();
|
|
104
106
|
});
|
|
@@ -2,7 +2,7 @@ import React, { useMemo, useCallback, useEffect, useState, useContext } from 're
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { Button, ButtonSet, Checkbox, Search, RadioButtonGroup, RadioButton } from '@carbon/react';
|
|
4
4
|
import { isDesktop, useConfig, useLayoutType } from '@openmrs/esm-framework';
|
|
5
|
-
import { FormValues, PatientIdentifierType, PatientIdentifierValue } from '../../patient-registration.types';
|
|
5
|
+
import { type FormValues, type PatientIdentifierType, PatientIdentifierValue } from '../../patient-registration.types';
|
|
6
6
|
import Overlay from '../../ui-components/overlay/overlay.component';
|
|
7
7
|
import { ResourcesContext } from '../../../offline.resources';
|
|
8
8
|
import { PatientRegistrationContext } from '../../patient-registration-context';
|
|
@@ -6,7 +6,7 @@ import { ExtensionSlot, useConfig } from '@openmrs/esm-framework';
|
|
|
6
6
|
import { Input } from '../../input/basic-input/input/input.component';
|
|
7
7
|
import { PatientRegistrationContext } from '../../patient-registration-context';
|
|
8
8
|
import styles from '../field.scss';
|
|
9
|
-
import { RegistrationConfig } from '../../../config-schema';
|
|
9
|
+
import { type RegistrationConfig } from '../../../config-schema';
|
|
10
10
|
|
|
11
11
|
export const unidentifiedPatientAttributeTypeUuid = '8b56eac7-5c76-4b9c-8c6f-1deab8d3fc47';
|
|
12
12
|
const containsNoNumbers = /^([^0-9]*)$/;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { Field } from 'formik';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { InlineNotification, Layer, Select, SelectItem } from '@carbon/react';
|
|
6
6
|
import { useConfig } from '@openmrs/esm-framework';
|
|
7
|
-
import { ConceptResponse } from '../../patient-registration.types';
|
|
8
|
-
import { FieldDefinition, RegistrationConfig } from '../../../config-schema';
|
|
7
|
+
import { type ConceptResponse } from '../../patient-registration.types';
|
|
8
|
+
import { type FieldDefinition, type RegistrationConfig } from '../../../config-schema';
|
|
9
9
|
import { Input } from '../../input/basic-input/input/input.component';
|
|
10
10
|
import { useConcept, useConceptAnswers } from '../field.resource';
|
|
11
11
|
import styles from './../field.scss';
|
|
@@ -15,8 +15,10 @@ export interface ObsFieldProps {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function ObsField({ fieldDefinition }: ObsFieldProps) {
|
|
18
|
+
const { t } = useTranslation();
|
|
18
19
|
const { data: concept, isLoading } = useConcept(fieldDefinition.uuid);
|
|
19
|
-
|
|
20
|
+
|
|
21
|
+
const config = useConfig<RegistrationConfig>();
|
|
20
22
|
|
|
21
23
|
if (!config.registrationObs.encounterTypeUuid) {
|
|
22
24
|
console.error(
|
|
@@ -30,6 +32,7 @@ export function ObsField({ fieldDefinition }: ObsFieldProps) {
|
|
|
30
32
|
if (isLoading) {
|
|
31
33
|
return null;
|
|
32
34
|
}
|
|
35
|
+
|
|
33
36
|
switch (concept.datatype.display) {
|
|
34
37
|
case 'Text':
|
|
35
38
|
return (
|
|
@@ -55,12 +58,17 @@ export function ObsField({ fieldDefinition }: ObsFieldProps) {
|
|
|
55
58
|
answerConceptSetUuid={fieldDefinition.answerConceptSetUuid}
|
|
56
59
|
label={fieldDefinition.label}
|
|
57
60
|
required={fieldDefinition.validation.required}
|
|
61
|
+
customConceptAnswers={fieldDefinition.customConceptAnswers}
|
|
58
62
|
/>
|
|
59
63
|
);
|
|
60
64
|
default:
|
|
61
65
|
return (
|
|
62
66
|
<InlineNotification kind="error" title="Error">
|
|
63
|
-
|
|
67
|
+
{t(
|
|
68
|
+
'obsFieldUnknownDatatype',
|
|
69
|
+
`Concept for obs field '{{fieldDefinitionId}}' has unknown datatype '{{datatypeName}}'`,
|
|
70
|
+
{ fieldDefinitionId: fieldDefinition.id, datatypeName: concept.datatype.display },
|
|
71
|
+
)}
|
|
64
72
|
</InlineNotification>
|
|
65
73
|
);
|
|
66
74
|
}
|
|
@@ -115,8 +123,6 @@ interface NumericObsFieldProps {
|
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
function NumericObsField({ concept, label, required }: NumericObsFieldProps) {
|
|
118
|
-
const { t } = useTranslation();
|
|
119
|
-
|
|
120
126
|
const fieldName = `obs.${concept.uuid}`;
|
|
121
127
|
|
|
122
128
|
return (
|
|
@@ -144,40 +150,32 @@ interface CodedObsFieldProps {
|
|
|
144
150
|
answerConceptSetUuid?: string;
|
|
145
151
|
label?: string;
|
|
146
152
|
required?: boolean;
|
|
153
|
+
customConceptAnswers: Array<{ uuid: string; label?: string }>;
|
|
147
154
|
}
|
|
148
155
|
|
|
149
|
-
function CodedObsField({ concept, answerConceptSetUuid, label, required }: CodedObsFieldProps) {
|
|
150
|
-
const
|
|
156
|
+
function CodedObsField({ concept, answerConceptSetUuid, label, required, customConceptAnswers }: CodedObsFieldProps) {
|
|
157
|
+
const { t } = useTranslation();
|
|
158
|
+
const fieldName = `obs.${concept.uuid}`;
|
|
159
|
+
|
|
151
160
|
const { data: conceptAnswers, isLoading: isLoadingConceptAnswers } = useConceptAnswers(
|
|
152
|
-
answerConceptSetUuid ?? concept.uuid,
|
|
161
|
+
customConceptAnswers.length ? '' : answerConceptSetUuid ?? concept.uuid,
|
|
153
162
|
);
|
|
154
163
|
|
|
155
|
-
const
|
|
156
|
-
|
|
164
|
+
const answers = useMemo(
|
|
165
|
+
() =>
|
|
166
|
+
customConceptAnswers.length
|
|
167
|
+
? customConceptAnswers
|
|
168
|
+
: isLoadingConceptAnswers
|
|
169
|
+
? []
|
|
170
|
+
: conceptAnswers.map((answer) => ({ ...answer, label: answer.display })),
|
|
171
|
+
[customConceptAnswers, conceptAnswers, isLoadingConceptAnswers],
|
|
172
|
+
);
|
|
157
173
|
|
|
158
174
|
return (
|
|
159
175
|
<div className={classNames(styles.customField, styles.halfWidthInDesktopView)}>
|
|
160
176
|
{!isLoadingConceptAnswers ? (
|
|
161
177
|
<Field name={fieldName}>
|
|
162
178
|
{({ field, form: { touched, errors }, meta }) => {
|
|
163
|
-
if (fieldDefinition?.customConceptAnswers?.length) {
|
|
164
|
-
return (
|
|
165
|
-
<Layer>
|
|
166
|
-
<Select
|
|
167
|
-
id={fieldName}
|
|
168
|
-
name={fieldName}
|
|
169
|
-
required={required}
|
|
170
|
-
labelText={label ?? concept?.display}
|
|
171
|
-
invalid={errors[fieldName] && touched[fieldName]}
|
|
172
|
-
{...field}>
|
|
173
|
-
<SelectItem key={`no-answer-select-item-${fieldName}`} value={''} text="" />
|
|
174
|
-
{fieldDefinition?.customConceptAnswers.map((answer) => (
|
|
175
|
-
<SelectItem key={answer.uuid} value={answer.uuid} text={answer.label} />
|
|
176
|
-
))}
|
|
177
|
-
</Select>
|
|
178
|
-
</Layer>
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
179
|
return (
|
|
182
180
|
<Layer>
|
|
183
181
|
<Select
|
|
@@ -187,9 +185,13 @@ function CodedObsField({ concept, answerConceptSetUuid, label, required }: Coded
|
|
|
187
185
|
required={required}
|
|
188
186
|
invalid={errors[fieldName] && touched[fieldName]}
|
|
189
187
|
{...field}>
|
|
190
|
-
<SelectItem
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
<SelectItem
|
|
189
|
+
key={`no-answer-select-item-${fieldName}`}
|
|
190
|
+
value={''}
|
|
191
|
+
text={t('selectAnOption', 'Select an option')}
|
|
192
|
+
/>
|
|
193
|
+
{answers.map((answer) => (
|
|
194
|
+
<SelectItem key={answer.uuid} value={answer.uuid} text={answer.label} />
|
|
193
195
|
))}
|
|
194
196
|
</Select>
|
|
195
197
|
</Layer>
|