@kenyaemr/esm-patient-registration-app 4.5.1 → 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 -3
- 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-levels.component.tsx +1 -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 +31 -28
- 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: {
|
|
@@ -183,7 +184,17 @@ export const esmPatientRegistrationSchema = {
|
|
|
183
184
|
_description: 'For coded questions only. Provide ability to add custom concept answers.',
|
|
184
185
|
},
|
|
185
186
|
},
|
|
186
|
-
_default: [
|
|
187
|
+
_default: [
|
|
188
|
+
{
|
|
189
|
+
id: 'phone',
|
|
190
|
+
type: 'person attribute',
|
|
191
|
+
uuid: '14d4f066-15f5-102d-96e4-000c29c2a5d7',
|
|
192
|
+
showHeading: false,
|
|
193
|
+
validation: {
|
|
194
|
+
matches: '',
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
],
|
|
187
198
|
_description:
|
|
188
199
|
'Definitions for custom fields that can be used in sectionDefinitions. Can also be used to override built-in fields.',
|
|
189
200
|
},
|
|
@@ -210,6 +221,11 @@ export const esmPatientRegistrationSchema = {
|
|
|
210
221
|
_default: true,
|
|
211
222
|
_description: 'Whether to display capture patient photo slot on name field',
|
|
212
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
|
+
},
|
|
213
229
|
},
|
|
214
230
|
gender: {
|
|
215
231
|
_type: Type.Array,
|
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
|
+
});
|
|
@@ -37,7 +37,7 @@ const AddressComboBox: React.FC<AddressComboBoxProps> = ({ attribute }) => {
|
|
|
37
37
|
const [field, meta, helpers] = useField(`address.${attribute.name}`);
|
|
38
38
|
const { fetchEntriesForField, searchString, updateChildElements } = useAddressEntryFetchConfig(attribute.name);
|
|
39
39
|
const { entries } = useAddressEntries(fetchEntriesForField, searchString);
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
const handleInputChange = useCallback((newValue) => {
|
|
42
42
|
helpers.setValue(newValue);
|
|
43
43
|
}, []);
|
|
@@ -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,
|