@kenyaemr/esm-patient-registration-app 4.5.0 → 4.5.2
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/130.js +2 -0
- package/dist/{858.js.LICENSE.txt → 130.js.LICENSE.txt} +2 -0
- package/dist/130.js.map +1 -0
- package/dist/196.js +1 -0
- package/dist/196.js.map +1 -0
- package/dist/208.js +2 -0
- package/dist/208.js.map +1 -0
- package/dist/317.js +1 -1
- package/dist/317.js.map +1 -1
- package/dist/319.js +1 -0
- package/dist/537.js +1 -0
- package/dist/537.js.map +1 -0
- package/dist/591.js +1 -1
- package/dist/591.js.map +1 -1
- package/dist/62.js +1 -1
- package/dist/62.js.map +1 -1
- package/dist/635.js +1 -1
- package/dist/635.js.map +1 -1
- package/dist/68.js +1 -1
- package/dist/68.js.map +1 -1
- package/dist/735.js +1 -1
- package/dist/742.js +1 -0
- package/dist/742.js.map +1 -0
- package/dist/757.js +1 -1
- package/dist/784.js.map +1 -1
- package/dist/788.js +1 -0
- package/dist/807.js +1 -1
- package/dist/821.js +1 -1
- package/dist/821.js.map +1 -1
- package/dist/833.js +1 -1
- package/dist/857.js +1 -0
- package/dist/857.js.map +1 -0
- package/dist/9.js +1 -1
- package/dist/9.js.map +1 -1
- package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
- package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +133 -137
- 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 -0
- package/package.json +2 -2
- package/src/add-patient-link.test.tsx +18 -0
- package/src/config-schema.ts +19 -5
- package/src/index.ts +33 -105
- package/src/nav-link.test.tsx +13 -0
- package/src/patient-registration/field/address/address-field.component.tsx +1 -1
- package/src/patient-registration/field/address/address-hierarchy.resource.tsx +2 -1
- package/src/patient-registration/field/field.test.tsx +291 -0
- package/src/patient-registration/field/name/name-field.component.tsx +45 -28
- package/src/patient-registration/form-manager.ts +1 -0
- package/src/patient-registration/input/combo-input/combo-input.component.tsx +28 -19
- package/src/patient-registration/input/input.scss +5 -0
- package/src/patient-registration/section/death-info/death-info-section.test.tsx +9 -6
- package/src/root.component.tsx +11 -11
- package/src/routes.json +46 -0
- package/translations/am.json +91 -0
- package/translations/es.json +91 -0
- package/translations/fr.json +8 -6
- package/translations/he.json +8 -6
- package/translations/km.json +8 -6
- package/dist/144.js +0 -2
- package/dist/144.js.map +0 -1
- package/dist/207.js +0 -1
- package/dist/207.js.map +0 -1
- package/dist/330.js +0 -1
- package/dist/330.js.map +0 -1
- package/dist/59.js +0 -1
- package/dist/59.js.map +0 -1
- package/dist/805.js +0 -1
- package/dist/805.js.map +0 -1
- package/dist/858.js +0 -2
- package/dist/858.js.map +0 -1
- package/dist/876.js +0 -1
- package/dist/876.js.map +0 -1
- package/dist/887.js +0 -1
- package/dist/887.js.map +0 -1
- package/dist/kenyaemr-esm-patient-registration-app.old +0 -1
- /package/dist/{144.js.LICENSE.txt → 208.js.LICENSE.txt} +0 -0
package/src/config-schema.ts
CHANGED
|
@@ -41,6 +41,7 @@ export interface RegistrationConfig {
|
|
|
41
41
|
defaultUnknownGivenName: string;
|
|
42
42
|
defaultUnknownFamilyName: string;
|
|
43
43
|
displayCapturePhoto: boolean;
|
|
44
|
+
displayReverseFieldOrder: boolean;
|
|
44
45
|
};
|
|
45
46
|
gender: Array<Gender>;
|
|
46
47
|
address: {
|
|
@@ -78,12 +79,12 @@ export const builtInSections: Array<SectionDefinition> = [
|
|
|
78
79
|
name: 'Basic Info',
|
|
79
80
|
fields: ['name', 'gender', 'dob', 'id'],
|
|
80
81
|
},
|
|
81
|
-
{ id: 'contact', name: 'Contact Details', fields: ['address'] },
|
|
82
|
+
{ id: 'contact', name: 'Contact Details', fields: ['address', 'phone'] },
|
|
82
83
|
{ id: 'death', name: 'Death Info', fields: [] },
|
|
83
84
|
{ id: 'relationships', name: 'Relationships', fields: [] },
|
|
84
85
|
];
|
|
85
86
|
|
|
86
|
-
export const builtInFields = ['name', 'gender', 'dob', 'address', 'id'] as const;
|
|
87
|
+
export const builtInFields = ['name', 'gender', 'dob', 'address', 'id', 'phone & email'] as const;
|
|
87
88
|
|
|
88
89
|
export const esmPatientRegistrationSchema = {
|
|
89
90
|
sections: {
|
|
@@ -184,8 +185,15 @@ export const esmPatientRegistrationSchema = {
|
|
|
184
185
|
},
|
|
185
186
|
},
|
|
186
187
|
_default: [
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
{
|
|
189
|
+
id: 'phone',
|
|
190
|
+
type: 'person attribute',
|
|
191
|
+
uuid: '14d4f066-15f5-102d-96e4-000c29c2a5d7',
|
|
192
|
+
showHeading: false,
|
|
193
|
+
validation: {
|
|
194
|
+
matches: '',
|
|
195
|
+
},
|
|
196
|
+
},
|
|
189
197
|
],
|
|
190
198
|
_description:
|
|
191
199
|
'Definitions for custom fields that can be used in sectionDefinitions. Can also be used to override built-in fields.',
|
|
@@ -213,6 +221,11 @@ export const esmPatientRegistrationSchema = {
|
|
|
213
221
|
_default: true,
|
|
214
222
|
_description: 'Whether to display capture patient photo slot on name field',
|
|
215
223
|
},
|
|
224
|
+
displayReverseFieldOrder: {
|
|
225
|
+
_type: Type.Boolean,
|
|
226
|
+
_default: false,
|
|
227
|
+
_description: "Whether to display the name fields in the order 'Family name' -> 'Middle name' -> 'First name'",
|
|
228
|
+
},
|
|
216
229
|
},
|
|
217
230
|
gender: {
|
|
218
231
|
_type: Type.Array,
|
|
@@ -379,7 +392,8 @@ export const esmPatientRegistrationSchema = {
|
|
|
379
392
|
);
|
|
380
393
|
const badField = badSection.fields.find((f) => !allowedFields.includes(f));
|
|
381
394
|
return (
|
|
382
|
-
`The section definition '${
|
|
395
|
+
`The section definition '${
|
|
396
|
+
badSection.id
|
|
383
397
|
}' contains an invalid field '${badField}'. 'fields' can only contain the built-in fields '${builtInFields.join(
|
|
384
398
|
"', '",
|
|
385
399
|
)}'` +
|
package/src/index.ts
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import { registerBreadcrumbs, defineConfigSchema, getAsyncLifecycle } from '@openmrs/esm-framework';
|
|
2
|
-
import { FormManager } from './patient-registration/form-manager';
|
|
3
2
|
import { esmPatientRegistrationSchema } from './config-schema';
|
|
4
3
|
import { moduleName, patientRegistration } from './constants';
|
|
5
4
|
import { setupOffline } from './offline';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
// __VERSION__ is replaced by Webpack with the version from package.json
|
|
9
|
-
const version = __VERSION__;
|
|
6
|
+
export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
|
|
10
7
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
'webservices.rest': '^2.24.0',
|
|
8
|
+
const options = {
|
|
9
|
+
featureName: 'Patient Registration',
|
|
10
|
+
moduleName,
|
|
15
11
|
};
|
|
16
12
|
|
|
17
|
-
function
|
|
18
|
-
const options = {
|
|
19
|
-
featureName: 'Patient Registration',
|
|
20
|
-
moduleName,
|
|
21
|
-
};
|
|
22
|
-
|
|
13
|
+
export function startupApp() {
|
|
23
14
|
defineConfigSchema(moduleName, esmPatientRegistrationSchema);
|
|
24
15
|
|
|
25
16
|
registerBreadcrumbs([
|
|
@@ -36,96 +27,33 @@ function setupOpenMRS() {
|
|
|
36
27
|
]);
|
|
37
28
|
|
|
38
29
|
setupOffline();
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
pages: [
|
|
42
|
-
{
|
|
43
|
-
load: getAsyncLifecycle(() => import('./root.component'), options),
|
|
44
|
-
route: 'patient-registration',
|
|
45
|
-
online: {
|
|
46
|
-
savePatientForm: FormManager.savePatientFormOnline,
|
|
47
|
-
isOffline: false,
|
|
48
|
-
},
|
|
49
|
-
offline: {
|
|
50
|
-
savePatientForm: FormManager.savePatientFormOffline,
|
|
51
|
-
isOffline: true,
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
load: getAsyncLifecycle(() => import('./root.component'), {
|
|
56
|
-
featureName: 'edit-patient-details-form',
|
|
57
|
-
moduleName,
|
|
58
|
-
}),
|
|
59
|
-
route: /patient\/([a-zA-Z0-9\-]+)\/edit/,
|
|
60
|
-
online: {
|
|
61
|
-
savePatientForm: FormManager.savePatientFormOnline,
|
|
62
|
-
},
|
|
63
|
-
offline: {
|
|
64
|
-
savePatientForm: FormManager.savePatientFormOffline,
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
extensions: [
|
|
69
|
-
{
|
|
70
|
-
id: 'add-patient-action',
|
|
71
|
-
slot: 'top-nav-actions-slot',
|
|
72
|
-
load: getAsyncLifecycle(() => import('./add-patient-link'), options),
|
|
73
|
-
online: true,
|
|
74
|
-
offline: true,
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
id: 'cancel-patient-edit-modal',
|
|
78
|
-
load: getAsyncLifecycle(() => import('./widgets/cancel-patient-edit.component'), options),
|
|
79
|
-
online: true,
|
|
80
|
-
offline: true,
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
id: 'patient-photo-widget',
|
|
84
|
-
slot: 'patient-photo-slot',
|
|
85
|
-
load: getAsyncLifecycle(() => import('./widgets/display-photo.component'), options),
|
|
86
|
-
online: true,
|
|
87
|
-
offline: true,
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
id: 'edit-patient-details-button',
|
|
91
|
-
slot: 'patient-actions-slot',
|
|
92
|
-
load: getAsyncLifecycle(() => import('./widgets/edit-patient-details-button.component'), options),
|
|
93
|
-
online: true,
|
|
94
|
-
offline: true,
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
id: 'edit-patient-details-button',
|
|
98
|
-
slot: 'patient-search-actions-slot',
|
|
99
|
-
load: getAsyncLifecycle(() => import('./widgets/edit-patient-details-button.component'), options),
|
|
100
|
-
online: true,
|
|
101
|
-
offline: true,
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
id: 'delete-identifier-confirmation-modal',
|
|
105
|
-
load: getAsyncLifecycle(() => import('./widgets/delete-identifier-confirmation-modal'), options),
|
|
106
|
-
online: true,
|
|
107
|
-
offline: true,
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
id: 'empty-client-registry-modal',
|
|
111
|
-
load: getAsyncLifecycle(
|
|
112
|
-
() => import('./patient-verification/verification-modal/empty-prompt.component'),
|
|
113
|
-
options,
|
|
114
|
-
),
|
|
115
|
-
online: true,
|
|
116
|
-
offline: true,
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
id: 'confirm-client-registry-modal',
|
|
120
|
-
load: getAsyncLifecycle(
|
|
121
|
-
() => import('./patient-verification/verification-modal/confirm-prompt.component'),
|
|
122
|
-
options,
|
|
123
|
-
),
|
|
124
|
-
online: true,
|
|
125
|
-
offline: true,
|
|
126
|
-
},
|
|
127
|
-
],
|
|
128
|
-
};
|
|
129
30
|
}
|
|
130
31
|
|
|
131
|
-
export
|
|
32
|
+
export const root = getAsyncLifecycle(() => import('./root.component'), options);
|
|
33
|
+
|
|
34
|
+
export const editPatient = getAsyncLifecycle(() => import('./root.component'), {
|
|
35
|
+
featureName: 'edit-patient-details-form',
|
|
36
|
+
moduleName,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const addPatientLink = getAsyncLifecycle(() => import('./add-patient-link'), options);
|
|
40
|
+
|
|
41
|
+
export const cancelPatientEditModal = getAsyncLifecycle(
|
|
42
|
+
() => import('./widgets/cancel-patient-edit.component'),
|
|
43
|
+
options,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export const patientPhoto = getAsyncLifecycle(() => import('./widgets/display-photo.component'), options);
|
|
47
|
+
|
|
48
|
+
export const editPatientDetailsButton = getAsyncLifecycle(
|
|
49
|
+
() => import('./widgets/edit-patient-details-button.component'),
|
|
50
|
+
{
|
|
51
|
+
featureName: 'edit-patient-details',
|
|
52
|
+
moduleName,
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
export const deleteIdentifierConfirmationModal = getAsyncLifecycle(
|
|
57
|
+
() => import('./widgets/delete-identifier-confirmation-modal'),
|
|
58
|
+
options,
|
|
59
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import Root from './nav-link';
|
|
4
|
+
|
|
5
|
+
describe('Nav link component', () => {
|
|
6
|
+
it('renders a link to the patient registration page', () => {
|
|
7
|
+
const { getByText } = render(<Root />);
|
|
8
|
+
const linkElement = getByText('Patient Registration');
|
|
9
|
+
|
|
10
|
+
expect(linkElement).toBeInTheDocument();
|
|
11
|
+
expect(linkElement).toHaveAttribute('href', '/openmrs/spa/patient-registration');
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -25,9 +25,10 @@ export function useOrderedAddressHierarchyLevels() {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function useAddressEntries(fetchResults, searchString) {
|
|
28
|
+
const encodedSearchString = encodeURIComponent(searchString);
|
|
28
29
|
const { data, isLoading, error } = useSWRImmutable<FetchResponse<Array<{ name: string }>>>(
|
|
29
30
|
fetchResults
|
|
30
|
-
? `module/addresshierarchy/ajax/getChildAddressHierarchyEntries.form?searchString=${
|
|
31
|
+
? `module/addresshierarchy/ajax/getChildAddressHierarchyEntries.form?searchString=${encodedSearchString}`
|
|
31
32
|
: null,
|
|
32
33
|
openmrsFetch,
|
|
33
34
|
);
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Field } from './field.component';
|
|
4
|
+
import { useConfig } from '@openmrs/esm-framework';
|
|
5
|
+
import { PatientRegistrationContext } from '../patient-registration-context';
|
|
6
|
+
import { Resources, ResourcesContext } from '../../offline.resources';
|
|
7
|
+
import { Form, Formik } from 'formik';
|
|
8
|
+
|
|
9
|
+
jest.mock('@openmrs/esm-framework', () => ({
|
|
10
|
+
...jest.requireActual('@openmrs/esm-framework'),
|
|
11
|
+
useConfig: jest.fn(),
|
|
12
|
+
}));
|
|
13
|
+
const predefinedAddressTemplate = {
|
|
14
|
+
results: [
|
|
15
|
+
{
|
|
16
|
+
value:
|
|
17
|
+
'<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>',
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const mockedIdentifierTypes = [
|
|
23
|
+
{
|
|
24
|
+
fieldName: 'openMrsId',
|
|
25
|
+
format: null,
|
|
26
|
+
identifierSources: [
|
|
27
|
+
{
|
|
28
|
+
uuid: '8549f706-7e85-4c1d-9424-217d50a2988b',
|
|
29
|
+
name: 'Generator for OpenMRS ID',
|
|
30
|
+
description: 'Generator for OpenMRS ID',
|
|
31
|
+
baseCharacterSet: '0123456789ACDEFGHJKLMNPRTUVWXY',
|
|
32
|
+
prefix: '',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
isPrimary: true,
|
|
36
|
+
name: 'OpenMRS ID',
|
|
37
|
+
required: true,
|
|
38
|
+
uniquenessBehavior: 'UNIQUE',
|
|
39
|
+
uuid: '05a29f94-c0ed-11e2-94be-8c13b969e334',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
fieldName: 'idCard',
|
|
43
|
+
format: null,
|
|
44
|
+
identifierSources: [],
|
|
45
|
+
isPrimary: false,
|
|
46
|
+
name: 'ID Card',
|
|
47
|
+
required: false,
|
|
48
|
+
uniquenessBehavior: 'UNIQUE',
|
|
49
|
+
uuid: 'b4143563-16cd-4439-b288-f83d61670fc8',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
fieldName: 'legacyId',
|
|
53
|
+
format: null,
|
|
54
|
+
identifierSources: [],
|
|
55
|
+
isPrimary: false,
|
|
56
|
+
name: 'Legacy ID',
|
|
57
|
+
required: false,
|
|
58
|
+
uniquenessBehavior: null,
|
|
59
|
+
uuid: '22348099-3873-459e-a32e-d93b17eda533',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
fieldName: 'oldIdentificationNumber',
|
|
63
|
+
format: '',
|
|
64
|
+
identifierSources: [],
|
|
65
|
+
isPrimary: false,
|
|
66
|
+
name: 'Old Identification Number',
|
|
67
|
+
required: false,
|
|
68
|
+
uniquenessBehavior: null,
|
|
69
|
+
uuid: '8d79403a-c2cc-11de-8d13-0010c6dffd0f',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
fieldName: 'openMrsIdentificationNumber',
|
|
73
|
+
format: '',
|
|
74
|
+
identifierSources: [],
|
|
75
|
+
isPrimary: false,
|
|
76
|
+
name: 'OpenMRS Identification Number',
|
|
77
|
+
required: false,
|
|
78
|
+
uniquenessBehavior: null,
|
|
79
|
+
uuid: '8d793bee-c2cc-11de-8d13-0010c6dffd0f',
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
const mockResourcesContextValue = {
|
|
83
|
+
addressTemplate: predefinedAddressTemplate,
|
|
84
|
+
currentSession: {
|
|
85
|
+
authenticated: true,
|
|
86
|
+
sessionId: 'JSESSION',
|
|
87
|
+
currentProvider: { uuid: 'provider-uuid', identifier: 'PRO-123' },
|
|
88
|
+
},
|
|
89
|
+
relationshipTypes: [],
|
|
90
|
+
identifierTypes: [...mockedIdentifierTypes],
|
|
91
|
+
} as Resources;
|
|
92
|
+
|
|
93
|
+
describe('Field', () => {
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
jest.clearAllMocks();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should render NameField component when name prop is "name"', () => {
|
|
99
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
100
|
+
fieldConfigurations: {
|
|
101
|
+
name: {
|
|
102
|
+
displayMiddleName: true,
|
|
103
|
+
unidentifiedPatient: true,
|
|
104
|
+
defaultUnknownGivenName: 'UNKNOWN',
|
|
105
|
+
defaultUnknownFamilyName: 'UNKNOWN',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
}));
|
|
109
|
+
render(
|
|
110
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
111
|
+
<Formik initialValues={{}} onSubmit={null}>
|
|
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
|
+
);
|
|
125
|
+
expect(screen.getByText('Full Name')).toBeInTheDocument();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should render GenderField component when name prop is "gender"', () => {
|
|
129
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
130
|
+
fieldConfigurations: {
|
|
131
|
+
gender: [
|
|
132
|
+
{
|
|
133
|
+
value: 'Male',
|
|
134
|
+
label: 'Male',
|
|
135
|
+
id: 'male',
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
}));
|
|
140
|
+
render(
|
|
141
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
142
|
+
<Formik initialValues={{}} onSubmit={null}>
|
|
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
|
+
);
|
|
156
|
+
expect(screen.getByLabelText('Male')).toBeInTheDocument();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should render DobField component when name prop is "dob"', () => {
|
|
160
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
161
|
+
fieldConfigurations: {
|
|
162
|
+
dob: {
|
|
163
|
+
minAgeLimit: 0,
|
|
164
|
+
maxAgeLimit: 120,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
}));
|
|
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
|
+
);
|
|
184
|
+
expect(screen.getByText('Birth')).toBeInTheDocument();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should render AddressComponent component when name prop is "address"', () => {
|
|
188
|
+
jest.mock('./address/address-hierarchy.resource', () => ({
|
|
189
|
+
...(jest.requireActual('../address-hierarchy.resource') as jest.Mock),
|
|
190
|
+
useOrderedAddressHierarchyLevels: jest.fn(),
|
|
191
|
+
}));
|
|
192
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
193
|
+
fieldConfigurations: {
|
|
194
|
+
address: {
|
|
195
|
+
useAddressHierarchy: {
|
|
196
|
+
enabled: false,
|
|
197
|
+
useQuickSearch: false,
|
|
198
|
+
searchAddressByLevel: false,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
}));
|
|
203
|
+
render(
|
|
204
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
205
|
+
<Formik initialValues={{}} onSubmit={null}>
|
|
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
|
+
);
|
|
219
|
+
expect(screen.getByText('Address')).toBeInTheDocument();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should render Identifiers component when name prop is "id"', () => {
|
|
223
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
224
|
+
defaultPatientIdentifierTypes: ['OpenMRS ID'],
|
|
225
|
+
}));
|
|
226
|
+
// initial value for the identifiers field
|
|
227
|
+
const openmrsID = {
|
|
228
|
+
name: 'OpenMRS ID',
|
|
229
|
+
fieldName: 'openMrsId',
|
|
230
|
+
required: true,
|
|
231
|
+
uuid: '05a29f94-c0ed-11e2-94be-8c13b969e334',
|
|
232
|
+
format: null,
|
|
233
|
+
isPrimary: true,
|
|
234
|
+
identifierSources: [
|
|
235
|
+
{
|
|
236
|
+
uuid: '691eed12-c0f1-11e2-94be-8c13b969e334',
|
|
237
|
+
name: 'Generator 1 for OpenMRS ID',
|
|
238
|
+
autoGenerationOption: {
|
|
239
|
+
manualEntryEnabled: false,
|
|
240
|
+
automaticGenerationEnabled: true,
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
uuid: '01af8526-cea4-4175-aa90-340acb411771',
|
|
245
|
+
name: 'Generator 2 for OpenMRS ID',
|
|
246
|
+
autoGenerationOption: {
|
|
247
|
+
manualEntryEnabled: true,
|
|
248
|
+
automaticGenerationEnabled: true,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
autoGenerationSource: null,
|
|
253
|
+
};
|
|
254
|
+
render(
|
|
255
|
+
<ResourcesContext.Provider value={mockResourcesContextValue}>
|
|
256
|
+
<Formik initialValues={{}} onSubmit={null}>
|
|
257
|
+
<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
|
+
}}>
|
|
267
|
+
<Field name="id" />
|
|
268
|
+
</PatientRegistrationContext.Provider>
|
|
269
|
+
</Form>
|
|
270
|
+
</Formik>
|
|
271
|
+
</ResourcesContext.Provider>,
|
|
272
|
+
);
|
|
273
|
+
expect(screen.getByText('Identifiers')).toBeInTheDocument();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should return null and report an error for an invalid field name', () => {
|
|
277
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
278
|
+
fieldDefinitions: [{ id: 'weight' }],
|
|
279
|
+
}));
|
|
280
|
+
let error = null;
|
|
281
|
+
try {
|
|
282
|
+
render(<Field name="invalidField" />);
|
|
283
|
+
} catch (err) {
|
|
284
|
+
error = err;
|
|
285
|
+
}
|
|
286
|
+
expect(error).toBe(
|
|
287
|
+
"Invalid field name 'invalidField'. Valid options are 'weight', 'name', 'gender', 'dob', 'address', 'id', 'phone & email'.",
|
|
288
|
+
);
|
|
289
|
+
expect(screen.queryByTestId('invalid-field')).not.toBeInTheDocument();
|
|
290
|
+
});
|
|
291
|
+
});
|
|
@@ -21,7 +21,7 @@ function checkNumber(value: string) {
|
|
|
21
21
|
export const NameField = () => {
|
|
22
22
|
const {
|
|
23
23
|
fieldConfigurations: {
|
|
24
|
-
name: { displayCapturePhoto },
|
|
24
|
+
name: { displayCapturePhoto, displayReverseFieldOrder },
|
|
25
25
|
},
|
|
26
26
|
} = useConfig() as RegistrationConfig;
|
|
27
27
|
const { t } = useTranslation();
|
|
@@ -55,6 +55,36 @@ export const NameField = () => {
|
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
+
const firstNameField = (
|
|
59
|
+
<Input
|
|
60
|
+
id="givenName"
|
|
61
|
+
name="givenName"
|
|
62
|
+
labelText={t('givenNameLabelText', 'First Name')}
|
|
63
|
+
checkWarning={checkNumber}
|
|
64
|
+
required
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const middleNameField = fieldConfigs.displayMiddleName && (
|
|
69
|
+
<Input
|
|
70
|
+
id="middleName"
|
|
71
|
+
name="middleName"
|
|
72
|
+
labelText={t('middleNameLabelText', 'Middle Name')}
|
|
73
|
+
light
|
|
74
|
+
checkWarning={checkNumber}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const familyNameField = (
|
|
79
|
+
<Input
|
|
80
|
+
id="familyName"
|
|
81
|
+
name="familyName"
|
|
82
|
+
labelText={t('familyNameLabelText', 'Family Name')}
|
|
83
|
+
checkWarning={checkNumber}
|
|
84
|
+
required
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
|
|
58
88
|
return (
|
|
59
89
|
<div>
|
|
60
90
|
<h4 className={styles.productiveHeading02Light}>{t('fullNameLabelText', 'Full Name')}</h4>
|
|
@@ -75,33 +105,20 @@ export const NameField = () => {
|
|
|
75
105
|
<Switch name="known" text={t('yes', 'Yes')} />
|
|
76
106
|
<Switch name="unknown" text={t('no', 'No')} />
|
|
77
107
|
</ContentSwitcher>
|
|
78
|
-
{nameKnown &&
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
light
|
|
93
|
-
checkWarning={checkNumber}
|
|
94
|
-
/>
|
|
95
|
-
)}
|
|
96
|
-
<Input
|
|
97
|
-
id="familyName"
|
|
98
|
-
name="familyName"
|
|
99
|
-
labelText={t('familyNameLabelText', 'Family Name')}
|
|
100
|
-
checkWarning={checkNumber}
|
|
101
|
-
required
|
|
102
|
-
/>
|
|
103
|
-
</>
|
|
104
|
-
)}
|
|
108
|
+
{nameKnown &&
|
|
109
|
+
(!displayReverseFieldOrder ? (
|
|
110
|
+
<>
|
|
111
|
+
{firstNameField}
|
|
112
|
+
{middleNameField}
|
|
113
|
+
{familyNameField}
|
|
114
|
+
</>
|
|
115
|
+
) : (
|
|
116
|
+
<>
|
|
117
|
+
{familyNameField}
|
|
118
|
+
{middleNameField}
|
|
119
|
+
{firstNameField}
|
|
120
|
+
</>
|
|
121
|
+
))}
|
|
105
122
|
</div>
|
|
106
123
|
</div>
|
|
107
124
|
</div>
|
|
@@ -39,6 +39,7 @@ export type SavePatientForm = (
|
|
|
39
39
|
savePatientTransactionManager: SavePatientTransactionManager,
|
|
40
40
|
abortController?: AbortController,
|
|
41
41
|
) => Promise<string | void>;
|
|
42
|
+
|
|
42
43
|
export class FormManager {
|
|
43
44
|
static savePatientFormOffline: SavePatientForm = async (
|
|
44
45
|
isNewPatient,
|