@kenyaemr/esm-patient-registration-app 4.5.4 → 4.5.5
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/117.js +2 -0
- package/dist/117.js.map +1 -0
- package/dist/130.js +1 -1
- package/dist/130.js.map +1 -1
- package/dist/208.js +1 -1
- package/dist/218.js +1 -0
- package/dist/218.js.map +1 -0
- package/dist/275.js +1 -0
- package/dist/275.js.map +1 -0
- package/dist/319.js +1 -1
- package/dist/{821.js → 348.js} +1 -1
- package/dist/{821.js.map → 348.js.map} +1 -1
- package/dist/574.js +1 -1
- package/dist/68.js +1 -1
- package/dist/68.js.map +1 -1
- package/dist/693.js +1 -0
- package/dist/693.js.map +1 -0
- package/dist/757.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 +147 -122
- 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/jest.config.js +3 -0
- package/package.json +5 -2
- package/src/index.ts +9 -2
- package/src/offline.resources.ts +8 -4
- package/src/offline.ts +1 -1
- package/src/patient-registration/field/__mocks__/field.resource.ts +1 -1
- package/src/patient-registration/field/address/address-field.component.tsx +25 -70
- package/src/patient-registration/field/address/address-hierarchy-levels.component.tsx +11 -9
- package/src/patient-registration/field/address/address-hierarchy.resource.tsx +57 -3
- package/src/patient-registration/field/address/address-search.component.tsx +1 -1
- package/src/patient-registration/field/address/tests/address-hierarchy.test.tsx +137 -63
- package/src/patient-registration/field/address/tests/address-search-component.test.tsx +128 -0
- package/src/patient-registration/field/address/tests/mocks.ts +93 -99
- package/src/patient-registration/field/dob/dob.component.tsx +34 -32
- package/src/patient-registration/field/field.resource.ts +1 -1
- package/src/patient-registration/field/id/id-field.component.tsx +1 -1
- package/src/patient-registration/field/id/identifier-selection-overlay.tsx +1 -1
- package/src/patient-registration/field/name/name-field.component.tsx +0 -1
- package/src/patient-registration/field/obs/obs-field.component.tsx +14 -13
- 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 +1 -1
- package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +103 -0
- package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +187 -0
- package/src/patient-registration/field/person-attributes/person-attributes.resource.tsx +1 -1
- package/src/patient-registration/field/person-attributes/text-person-attribute-field.component.tsx +3 -3
- package/src/patient-registration/field/person-attributes/text-person-attribute-field.test.tsx +88 -0
- package/src/patient-registration/form-manager.test.ts +1 -1
- package/src/patient-registration/form-manager.ts +1 -1
- package/src/patient-registration/input/basic-input/input/input.test.tsx +0 -135
- package/src/patient-registration/input/basic-input/select/select-input.test.tsx +8 -4
- package/src/patient-registration/input/combo-input/combo-input.component.tsx +8 -6
- package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +1 -1
- package/src/patient-registration/input/custom-input/identifier/utils.test.ts +81 -0
- 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/patient-registration-context.ts +1 -1
- package/src/patient-registration/patient-registration-hooks.ts +1 -1
- package/src/patient-registration/patient-registration-utils.ts +1 -1
- package/src/patient-registration/patient-registration.component.tsx +1 -12
- package/src/patient-registration/patient-registration.resource.tsx +1 -72
- package/src/patient-registration/patient-registration.test.tsx +250 -247
- package/src/patient-registration/{patient-registration-types.tsx → patient-registration.types.tsx} +45 -0
- package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +83 -79
- package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +88 -0
- package/src/patient-registration/section/patient-relationships/relationships.resource.tsx +1 -1
- package/src/patient-registration/validation/patient-registration-validation.tsx +1 -1
- package/src/patient-verification/patient-verification-hook.tsx +12 -1
- package/src/patient-verification/patient-verification-utils.ts +1 -1
- package/src/patient-verification/patient-verification.component.tsx +1 -1
- package/src/patient-verification/verification-modal/confirm-prompt.component.tsx +11 -0
- package/src/root.component.tsx +1 -1
- package/src/routes.json +62 -51
- package/src/widgets/display-photo.test.tsx +37 -0
- package/src/widgets/edit-patient-details-button.test.tsx +36 -0
- package/translations/am.json +0 -7
- package/translations/en.json +2 -5
- package/translations/es.json +0 -7
- package/translations/fr.json +0 -7
- package/translations/he.json +0 -7
- package/translations/km.json +0 -7
- package/__mocks__/react-i18next.js +0 -49
- package/dist/196.js +0 -1
- package/dist/196.js.map +0 -1
- package/dist/59.js +0 -1
- package/dist/59.js.map +0 -1
- package/dist/9.js +0 -2
- package/dist/9.js.map +0 -1
- /package/dist/{9.js.LICENSE.txt → 117.js.LICENSE.txt} +0 -0
package/src/offline.resources.ts
CHANGED
|
@@ -2,12 +2,16 @@ import React from 'react';
|
|
|
2
2
|
import find from 'lodash-es/find';
|
|
3
3
|
import camelCase from 'lodash-es/camelCase';
|
|
4
4
|
import escapeRegExp from 'lodash-es/escapeRegExp';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { messageOmrsServiceWorker, openmrsFetch, Session } from '@openmrs/esm-framework';
|
|
6
|
+
import type {
|
|
7
|
+
PatientIdentifierType,
|
|
8
|
+
FetchedPatientIdentifierType,
|
|
9
|
+
AddressTemplate,
|
|
10
|
+
} from './patient-registration/patient-registration.types';
|
|
7
11
|
import { cacheForOfflineHeaders } from './constants';
|
|
8
12
|
|
|
9
13
|
export interface Resources {
|
|
10
|
-
addressTemplate:
|
|
14
|
+
addressTemplate: AddressTemplate;
|
|
11
15
|
currentSession: Session;
|
|
12
16
|
relationshipTypes: any;
|
|
13
17
|
identifierTypes: Array<PatientIdentifierType>;
|
|
@@ -21,7 +25,7 @@ export async function fetchCurrentSession(): Promise<Session> {
|
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
export async function fetchAddressTemplate() {
|
|
24
|
-
const { data } = await cacheAndFetch('/ws/rest/v1/
|
|
28
|
+
const { data } = await cacheAndFetch<AddressTemplate>('/ws/rest/v1/addresstemplate');
|
|
25
29
|
return data;
|
|
26
30
|
}
|
|
27
31
|
|
package/src/offline.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
fetchPatientIdentifierTypesWithSources,
|
|
16
16
|
} from './offline.resources';
|
|
17
17
|
import { FormManager } from './patient-registration/form-manager';
|
|
18
|
-
import { PatientRegistration } from './patient-registration/patient-registration
|
|
18
|
+
import { PatientRegistration } from './patient-registration/patient-registration.types';
|
|
19
19
|
|
|
20
20
|
export function setupOffline() {
|
|
21
21
|
setupOfflineSync(patientRegistration, [], syncPatientRegistration, {
|
|
@@ -14,87 +14,44 @@ function parseString(xmlDockAsString: string) {
|
|
|
14
14
|
const parser = new DOMParser();
|
|
15
15
|
return parser.parseFromString(xmlDockAsString, 'text/xml');
|
|
16
16
|
}
|
|
17
|
-
function getTagAsDocument(tagName: string, template: XMLDocument) {
|
|
18
|
-
const tmp = template.getElementsByTagName(tagName)[0];
|
|
19
|
-
return tmp ? parseString(tmp.outerHTML) : parseString('');
|
|
20
|
-
}
|
|
21
17
|
|
|
22
18
|
export const AddressComponent: React.FC = () => {
|
|
23
19
|
const [selected, setSelected] = useState('');
|
|
24
|
-
const [addressLayout, setAddressLayout] = useState<
|
|
25
|
-
Array<{
|
|
26
|
-
id: string;
|
|
27
|
-
name: string;
|
|
28
|
-
value: string;
|
|
29
|
-
label: string;
|
|
30
|
-
}>
|
|
31
|
-
>([]);
|
|
32
|
-
const { t } = useTranslation();
|
|
33
20
|
const { addressTemplate } = useContext(ResourcesContext);
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
21
|
+
const addressLayout = useMemo(() => {
|
|
22
|
+
if (!addressTemplate?.lines) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const allFields = addressTemplate?.lines?.flat();
|
|
26
|
+
const fields = allFields?.filter(({ isToken }) => isToken === 'IS_ADDR_TOKEN');
|
|
27
|
+
|
|
28
|
+
return fields.map(({ displayText, codeName }) => ({
|
|
29
|
+
id: codeName,
|
|
30
|
+
name: codeName,
|
|
31
|
+
label: displayText,
|
|
32
|
+
}));
|
|
33
|
+
}, [addressTemplate]);
|
|
34
|
+
|
|
35
|
+
const { t } = useTranslation();
|
|
38
36
|
const config = useConfig();
|
|
39
37
|
const {
|
|
40
38
|
fieldConfigurations: {
|
|
41
39
|
address: {
|
|
42
|
-
useAddressHierarchy: { enabled, useQuickSearch, searchAddressByLevel },
|
|
40
|
+
useAddressHierarchy: { enabled: addressHierarchyEnabled, useQuickSearch, searchAddressByLevel },
|
|
43
41
|
},
|
|
44
42
|
},
|
|
45
43
|
} = config;
|
|
46
44
|
|
|
47
|
-
const { setFieldValue
|
|
45
|
+
const { setFieldValue } = useContext(PatientRegistrationContext);
|
|
48
46
|
const { orderedFields, isLoadingFieldOrder, errorFetchingFieldOrder } = useOrderedAddressHierarchyLevels();
|
|
49
47
|
|
|
50
48
|
useEffect(() => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return [name.innerHTML, value.innerHTML];
|
|
58
|
-
}),
|
|
59
|
-
);
|
|
60
|
-
const nameMappings = getTagAsDocument('nameMappings', templateXmlDoc);
|
|
61
|
-
const properties =
|
|
62
|
-
Array.from(nameMappings.getElementsByTagName('property')).length > 0
|
|
63
|
-
? nameMappings.getElementsByTagName('property')
|
|
64
|
-
: nameMappings.getElementsByTagName('entry');
|
|
65
|
-
|
|
66
|
-
const propertiesObj = Array.prototype.map.call(properties, (property: Element) => {
|
|
67
|
-
const name = property.getAttribute('name') ?? property.getElementsByTagName('string')[0].innerHTML;
|
|
68
|
-
const label = property.getAttribute('value') ?? property.getElementsByTagName('string')[1].innerHTML;
|
|
69
|
-
/*
|
|
70
|
-
DO NOT REMOVE THIS COMMENT UNLESS YOU UNDERSTAND WHY IT IS HERE
|
|
71
|
-
|
|
72
|
-
t('postalCode', 'Postal code')
|
|
73
|
-
t('address1', 'Address line 1')
|
|
74
|
-
t('address2', 'Address line 2')
|
|
75
|
-
t('countyDistrict', 'District')
|
|
76
|
-
t('stateProvince', 'State')
|
|
77
|
-
t('cityVillage', 'city')
|
|
78
|
-
t('country', 'Country')
|
|
79
|
-
t('countyDistrict', 'District')
|
|
80
|
-
*/
|
|
81
|
-
const value = defaultValues[name];
|
|
82
|
-
setInitialFormValues((initialFormValues) => ({
|
|
83
|
-
...initialFormValues,
|
|
84
|
-
address: {
|
|
85
|
-
...(initialFormValues.address ?? {}),
|
|
86
|
-
[name]: value,
|
|
87
|
-
},
|
|
88
|
-
}));
|
|
89
|
-
return {
|
|
90
|
-
id: name,
|
|
91
|
-
name,
|
|
92
|
-
value,
|
|
93
|
-
label,
|
|
94
|
-
};
|
|
95
|
-
});
|
|
96
|
-
setAddressLayout(propertiesObj);
|
|
97
|
-
}, [t, addressTemplateXml, setFieldValue, values, setInitialFormValues]);
|
|
49
|
+
if (addressTemplate?.elementDefaults) {
|
|
50
|
+
Object.entries(addressTemplate.elementDefaults).forEach(([name, defaultValue]) => {
|
|
51
|
+
setFieldValue(`address.${name}`, defaultValue);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}, [addressTemplate, setFieldValue]);
|
|
98
55
|
|
|
99
56
|
const orderedAddressFields = useMemo(() => {
|
|
100
57
|
if (isLoadingFieldOrder || errorFetchingFieldOrder) {
|
|
@@ -116,7 +73,7 @@ export const AddressComponent: React.FC = () => {
|
|
|
116
73
|
);
|
|
117
74
|
}
|
|
118
75
|
|
|
119
|
-
if (!
|
|
76
|
+
if (!addressHierarchyEnabled) {
|
|
120
77
|
return (
|
|
121
78
|
<AddressComponentContainer>
|
|
122
79
|
{addressLayout.map((attributes, index) => (
|
|
@@ -125,7 +82,6 @@ export const AddressComponent: React.FC = () => {
|
|
|
125
82
|
name={`address.${attributes.name}`}
|
|
126
83
|
labelText={t(attributes.label)}
|
|
127
84
|
id={attributes.name}
|
|
128
|
-
setSelectedValue={setSelectedValue}
|
|
129
85
|
selected={selected}
|
|
130
86
|
/>
|
|
131
87
|
))}
|
|
@@ -166,7 +122,6 @@ export const AddressComponent: React.FC = () => {
|
|
|
166
122
|
name={`address.${attributes.name}`}
|
|
167
123
|
labelText={t(attributes.label)}
|
|
168
124
|
id={attributes.name}
|
|
169
|
-
setSelectedValue={setSelectedValue}
|
|
170
125
|
selected={selected}
|
|
171
126
|
/>
|
|
172
127
|
))
|
|
@@ -188,4 +143,4 @@ const AddressComponentContainer = ({ children }) => {
|
|
|
188
143
|
</div>
|
|
189
144
|
</div>
|
|
190
145
|
);
|
|
191
|
-
};
|
|
146
|
+
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import React, { useCallback
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { useAddressEntries, useAddressEntryFetchConfig } from './address-hierarchy.resource';
|
|
4
4
|
import { useField } from 'formik';
|
|
5
5
|
import ComboInput from '../../input/combo-input/combo-input.component';
|
|
6
|
-
import { InlineNotification } from '@carbon/react';
|
|
7
6
|
|
|
8
7
|
interface AddressHierarchyLevelsProps {
|
|
9
8
|
orderedAddressFields: Array<any>;
|
|
@@ -34,22 +33,25 @@ interface AddressComboBoxProps {
|
|
|
34
33
|
|
|
35
34
|
const AddressComboBox: React.FC<AddressComboBoxProps> = ({ attribute }) => {
|
|
36
35
|
const { t } = useTranslation();
|
|
37
|
-
const [field, meta,
|
|
36
|
+
const [field, meta, { setValue }] = useField(`address.${attribute.name}`);
|
|
38
37
|
const { fetchEntriesForField, searchString, updateChildElements } = useAddressEntryFetchConfig(attribute.name);
|
|
39
38
|
const { entries } = useAddressEntries(fetchEntriesForField, searchString);
|
|
40
39
|
|
|
41
|
-
const handleInputChange = useCallback(
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
const handleInputChange = useCallback(
|
|
41
|
+
(newValue) => {
|
|
42
|
+
setValue(newValue);
|
|
43
|
+
},
|
|
44
|
+
[setValue],
|
|
45
|
+
);
|
|
44
46
|
|
|
45
47
|
const handleSelection = useCallback(
|
|
46
48
|
(selectedItem) => {
|
|
47
49
|
if (meta.value !== selectedItem) {
|
|
48
|
-
|
|
50
|
+
setValue(selectedItem);
|
|
49
51
|
updateChildElements();
|
|
50
52
|
}
|
|
51
53
|
},
|
|
52
|
-
[updateChildElements,
|
|
54
|
+
[updateChildElements, meta.value, setValue],
|
|
53
55
|
);
|
|
54
56
|
|
|
55
57
|
return (
|
|
@@ -60,7 +62,7 @@ const AddressComboBox: React.FC<AddressComboBoxProps> = ({ attribute }) => {
|
|
|
60
62
|
fieldProps={{
|
|
61
63
|
...field,
|
|
62
64
|
id: attribute.name,
|
|
63
|
-
labelText: `${attribute.label} (${t('optional', 'optional')})`,
|
|
65
|
+
labelText: `${t(attribute.label)} (${t('optional', 'optional')})`,
|
|
64
66
|
}}
|
|
65
67
|
handleInputChange={handleInputChange}
|
|
66
68
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FetchResponse, openmrsFetch } from '@openmrs/esm-framework';
|
|
1
|
+
import { type FetchResponse, openmrsFetch } from '@openmrs/esm-framework';
|
|
2
2
|
import { useField } from 'formik';
|
|
3
3
|
import { useCallback, useContext, useEffect, useMemo } from 'react';
|
|
4
4
|
import useSWRImmutable from 'swr/immutable';
|
|
@@ -10,7 +10,7 @@ interface AddressFields {
|
|
|
10
10
|
|
|
11
11
|
export function useOrderedAddressHierarchyLevels() {
|
|
12
12
|
const url = '/module/addresshierarchy/ajax/getOrderedAddressHierarchyLevels.form';
|
|
13
|
-
const { data, isLoading, error } = useSWRImmutable<FetchResponse<Array<AddressFields
|
|
13
|
+
const { data, isLoading, error } = useSWRImmutable<FetchResponse<Array<AddressFields>>, Error>(url, openmrsFetch);
|
|
14
14
|
|
|
15
15
|
const results = useMemo(
|
|
16
16
|
() => ({
|
|
@@ -56,7 +56,7 @@ export function useAddressEntries(fetchResults, searchString) {
|
|
|
56
56
|
* This also returns the function to reset the lower ordered fields if the value of a field is changed.
|
|
57
57
|
*/
|
|
58
58
|
export function useAddressEntryFetchConfig(addressField: string) {
|
|
59
|
-
const { orderedFields, isLoadingFieldOrder
|
|
59
|
+
const { orderedFields, isLoadingFieldOrder } = useOrderedAddressHierarchyLevels();
|
|
60
60
|
const { setFieldValue } = useContext(PatientRegistrationContext);
|
|
61
61
|
const [, { value: addressValues }] = useField('address');
|
|
62
62
|
|
|
@@ -101,3 +101,57 @@ export function useAddressEntryFetchConfig(addressField: string) {
|
|
|
101
101
|
|
|
102
102
|
return results;
|
|
103
103
|
}
|
|
104
|
+
|
|
105
|
+
export function useAddressHierarchy(searchString: string, separator: string) {
|
|
106
|
+
const { data, error, isLoading } = useSWRImmutable<
|
|
107
|
+
FetchResponse<
|
|
108
|
+
Array<{
|
|
109
|
+
address: string;
|
|
110
|
+
}>
|
|
111
|
+
>,
|
|
112
|
+
Error
|
|
113
|
+
>(
|
|
114
|
+
searchString
|
|
115
|
+
? `/module/addresshierarchy/ajax/getPossibleFullAddresses.form?separator=${separator}&searchString=${searchString}`
|
|
116
|
+
: null,
|
|
117
|
+
openmrsFetch,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const results = useMemo(
|
|
121
|
+
() => ({
|
|
122
|
+
addresses: data?.data?.map((address) => address.address) ?? [],
|
|
123
|
+
error,
|
|
124
|
+
isLoading,
|
|
125
|
+
}),
|
|
126
|
+
[data?.data, error, isLoading],
|
|
127
|
+
);
|
|
128
|
+
return results;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function useAddressHierarchyWithParentSearch(addressField: string, parentid: string, query: string) {
|
|
132
|
+
const { data, error, isLoading } = useSWRImmutable<
|
|
133
|
+
FetchResponse<
|
|
134
|
+
Array<{
|
|
135
|
+
uuid: string;
|
|
136
|
+
name: string;
|
|
137
|
+
}>
|
|
138
|
+
>,
|
|
139
|
+
Error
|
|
140
|
+
>(
|
|
141
|
+
query
|
|
142
|
+
? `/module/addresshierarchy/ajax/getPossibleAddressHierarchyEntriesWithParents.form?addressField=${addressField}&limit=20&searchString=${query}&parentUuid=${parentid}`
|
|
143
|
+
: null,
|
|
144
|
+
openmrsFetch,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const results = useMemo(
|
|
148
|
+
() => ({
|
|
149
|
+
error: error,
|
|
150
|
+
isLoading,
|
|
151
|
+
addresses: data?.data ?? [],
|
|
152
|
+
}),
|
|
153
|
+
[data?.data, error, isLoading],
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
return results;
|
|
157
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect, useMemo } from 'react';
|
|
2
|
-
import { useAddressHierarchy } from '
|
|
2
|
+
import { useAddressHierarchy } from './address-hierarchy.resource';
|
|
3
3
|
import { Search } from '@carbon/react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { useFormikContext } from 'formik';
|
|
@@ -6,8 +6,18 @@ import { Resources, ResourcesContext } from '../../../../offline.resources';
|
|
|
6
6
|
import { PatientRegistrationContext } from '../../../patient-registration-context';
|
|
7
7
|
import { useConfig } from '@openmrs/esm-framework';
|
|
8
8
|
import { useOrderedAddressHierarchyLevels } from '../address-hierarchy.resource';
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import { mockedAddressTemplate, mockedOrderedFields } from './mocks';
|
|
10
|
+
|
|
11
|
+
// Mocking the AddressSearchComponent
|
|
12
|
+
jest.mock('../address-search.component', () => jest.fn(() => <div data-testid="address-search-bar" />));
|
|
13
|
+
// Mocking the AddressHierarchyLevels
|
|
14
|
+
jest.mock('../address-hierarchy-levels.component', () => jest.fn(() => <div data-testid="address-hierarchy-levels" />));
|
|
15
|
+
// Mocking the SkeletonText
|
|
16
|
+
jest.mock('@carbon/react', () => ({
|
|
17
|
+
...jest.requireActual('@carbon/react'),
|
|
18
|
+
SkeletonText: jest.fn(() => <div data-testid="skeleton-text" />),
|
|
19
|
+
InlineNotification: jest.fn(() => <div data-testid="inline-notification" />),
|
|
20
|
+
}));
|
|
11
21
|
|
|
12
22
|
jest.mock('@openmrs/esm-framework', () => ({
|
|
13
23
|
...jest.requireActual('@openmrs/esm-framework'),
|
|
@@ -19,63 +29,91 @@ jest.mock('../address-hierarchy.resource', () => ({
|
|
|
19
29
|
useOrderedAddressHierarchyLevels: jest.fn(),
|
|
20
30
|
}));
|
|
21
31
|
|
|
22
|
-
async function
|
|
32
|
+
async function renderAddressHierarchy(addressTemplate = mockedAddressTemplate) {
|
|
23
33
|
await render(
|
|
24
|
-
<ResourcesContext.Provider value={{ addressTemplate
|
|
34
|
+
<ResourcesContext.Provider value={{ addressTemplate } as Resources}>
|
|
25
35
|
<Formik initialValues={{}} onSubmit={null}>
|
|
26
36
|
<Form>
|
|
27
|
-
<PatientRegistrationContext.Provider
|
|
28
|
-
value={{ setFieldValue: jest.fn(), setInitialFormValues: jest.fn(), values: { address: {} } }}>
|
|
37
|
+
<PatientRegistrationContext.Provider value={{ setFieldValue: jest.fn() } as any}>
|
|
29
38
|
<AddressComponent />
|
|
30
39
|
</PatientRegistrationContext.Provider>
|
|
31
40
|
</Form>
|
|
32
41
|
</Formik>
|
|
33
42
|
</ResourcesContext.Provider>,
|
|
34
43
|
);
|
|
35
|
-
|
|
36
|
-
const countryInput = screen.getByLabelText('Country (optional)');
|
|
37
|
-
expect(countryInput).toBeInTheDocument();
|
|
38
|
-
expect(countryInput).toHaveAttribute('name', 'address.country');
|
|
39
|
-
const stateInput = screen.getByLabelText('State (optional)');
|
|
40
|
-
expect(stateInput).toBeInTheDocument();
|
|
41
|
-
expect(stateInput).toHaveAttribute('name', 'address.stateProvince');
|
|
42
|
-
const cityInput = screen.getByLabelText('City (optional)');
|
|
43
|
-
expect(cityInput).toBeInTheDocument();
|
|
44
|
-
expect(cityInput).toHaveAttribute('name', 'address.cityVillage');
|
|
45
|
-
const address1Input = screen.getByLabelText('Address line 1 (optional)');
|
|
46
|
-
expect(address1Input).toBeInTheDocument();
|
|
47
|
-
expect(address1Input).toHaveAttribute('name', 'address.address1');
|
|
48
|
-
const address2Input = screen.getByLabelText('Address line 2 (optional)');
|
|
49
|
-
expect(address2Input).toBeInTheDocument();
|
|
50
|
-
expect(address2Input).toHaveAttribute('name', 'address.address2');
|
|
51
|
-
const postalCodeInput = screen.getByLabelText('Postcode (optional)');
|
|
52
|
-
expect(postalCodeInput).toBeInTheDocument();
|
|
53
|
-
expect(postalCodeInput).toHaveAttribute('name', 'address.postalCode');
|
|
54
44
|
}
|
|
55
45
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const inputs = screen.getAllByRole('textbox');
|
|
59
|
-
inputs.forEach((input, indx) => {
|
|
60
|
-
const inputName = input.getAttribute('name');
|
|
61
|
-
// Names are in the format of address.${name}
|
|
62
|
-
const fieldName = inputName.split('.')?.[1];
|
|
63
|
-
expect(fieldName).toBe(mockedOrderedFields[indx]);
|
|
64
|
-
});
|
|
65
|
-
}
|
|
46
|
+
describe('Testing address hierarchy', () => {
|
|
47
|
+
beforeEach(cleanup);
|
|
66
48
|
|
|
67
|
-
|
|
68
|
-
|
|
49
|
+
it('should render skeleton when address template is loading', () => {
|
|
50
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
51
|
+
fieldConfigurations: {
|
|
52
|
+
address: {
|
|
53
|
+
useAddressHierarchy: {
|
|
54
|
+
enabled: false,
|
|
55
|
+
useQuickSearch: false,
|
|
56
|
+
searchAddressByLevel: false,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
}));
|
|
69
61
|
(useOrderedAddressHierarchyLevels as jest.Mock).mockImplementation(() => ({
|
|
70
|
-
orderedFields:
|
|
62
|
+
orderedFields: [],
|
|
71
63
|
isLoadingFieldOrder: false,
|
|
72
64
|
errorFetchingFieldOrder: null,
|
|
73
65
|
}));
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
renderAddressHierarchy(null);
|
|
68
|
+
const skeletonText = screen.getByTestId('skeleton-text');
|
|
69
|
+
expect(skeletonText).toBeInTheDocument();
|
|
74
70
|
});
|
|
75
71
|
|
|
76
|
-
|
|
72
|
+
it('should render skeleton when address hierarchy is enabled and addresshierarchy order is loading', () => {
|
|
73
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
74
|
+
fieldConfigurations: {
|
|
75
|
+
address: {
|
|
76
|
+
useAddressHierarchy: {
|
|
77
|
+
enabled: true,
|
|
78
|
+
useQuickSearch: false,
|
|
79
|
+
searchAddressByLevel: false,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
}));
|
|
84
|
+
(useOrderedAddressHierarchyLevels as jest.Mock).mockImplementation(() => ({
|
|
85
|
+
orderedFields: [],
|
|
86
|
+
isLoadingFieldOrder: true,
|
|
87
|
+
errorFetchingFieldOrder: null,
|
|
88
|
+
}));
|
|
89
|
+
renderAddressHierarchy();
|
|
90
|
+
const skeletonText = screen.getByTestId('skeleton-text');
|
|
91
|
+
expect(skeletonText).toBeInTheDocument();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should render skeleton when address hierarchy is enabled and addresshierarchy order is loading', () => {
|
|
95
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
96
|
+
fieldConfigurations: {
|
|
97
|
+
address: {
|
|
98
|
+
useAddressHierarchy: {
|
|
99
|
+
enabled: true,
|
|
100
|
+
useQuickSearch: false,
|
|
101
|
+
searchAddressByLevel: false,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
}));
|
|
106
|
+
(useOrderedAddressHierarchyLevels as jest.Mock).mockImplementation(() => ({
|
|
107
|
+
orderedFields: [],
|
|
108
|
+
isLoadingFieldOrder: false,
|
|
109
|
+
errorFetchingFieldOrder: true,
|
|
110
|
+
}));
|
|
111
|
+
renderAddressHierarchy();
|
|
112
|
+
const inlineNotification = screen.getByTestId('inline-notification');
|
|
113
|
+
expect(inlineNotification).toBeInTheDocument();
|
|
114
|
+
});
|
|
77
115
|
|
|
78
|
-
it('
|
|
116
|
+
it('should render the address component with address hierarchy disabled', () => {
|
|
79
117
|
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
80
118
|
fieldConfigurations: {
|
|
81
119
|
address: {
|
|
@@ -87,37 +125,72 @@ describe('address hierarchy', () => {
|
|
|
87
125
|
},
|
|
88
126
|
},
|
|
89
127
|
}));
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
128
|
+
(useOrderedAddressHierarchyLevels as jest.Mock).mockImplementation(() => ({
|
|
129
|
+
orderedFields: [],
|
|
130
|
+
isLoadingFieldOrder: false,
|
|
131
|
+
errorFetchingFieldOrder: null,
|
|
132
|
+
}));
|
|
133
|
+
renderAddressHierarchy();
|
|
134
|
+
const allFields = mockedAddressTemplate.lines.flat().filter(({ isToken }) => isToken === 'IS_ADDR_TOKEN');
|
|
135
|
+
allFields.forEach((field) => {
|
|
136
|
+
const textFieldInput = screen.getByLabelText(`${field.displayText} (optional)`);
|
|
137
|
+
expect(textFieldInput).toBeInTheDocument();
|
|
138
|
+
});
|
|
94
139
|
});
|
|
95
140
|
|
|
96
|
-
it('
|
|
141
|
+
it('should render the fields in order if the address hierarcy is enabled', () => {
|
|
97
142
|
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
98
143
|
fieldConfigurations: {
|
|
99
144
|
address: {
|
|
100
145
|
useAddressHierarchy: {
|
|
101
146
|
enabled: true,
|
|
102
|
-
useQuickSearch:
|
|
147
|
+
useQuickSearch: false,
|
|
103
148
|
searchAddressByLevel: false,
|
|
104
149
|
},
|
|
105
150
|
},
|
|
106
151
|
},
|
|
107
152
|
}));
|
|
153
|
+
(useOrderedAddressHierarchyLevels as jest.Mock).mockImplementation(() => ({
|
|
154
|
+
orderedFields: [],
|
|
155
|
+
isLoadingFieldOrder: false,
|
|
156
|
+
errorFetchingFieldOrder: null,
|
|
157
|
+
}));
|
|
158
|
+
renderAddressHierarchy();
|
|
159
|
+
const allFields = mockedAddressTemplate.lines.flat().filter(({ isToken }) => isToken === 'IS_ADDR_TOKEN');
|
|
160
|
+
const orderMap = Object.fromEntries(mockedOrderedFields.map((field, indx) => [field, indx]));
|
|
161
|
+
allFields.sort(
|
|
162
|
+
(existingField1, existingField2) =>
|
|
163
|
+
orderMap[existingField1.codeName ?? 0] - orderMap[existingField2.codeName ?? 0],
|
|
164
|
+
);
|
|
165
|
+
allFields.forEach((field) => {
|
|
166
|
+
const textFieldInput = screen.getByLabelText(`${field.displayText} (optional)`);
|
|
167
|
+
expect(textFieldInput).toBeInTheDocument();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
108
170
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
171
|
+
it('should render quick search bar on above the fields when address hierarchy is enabled and quicksearch is set to true', () => {
|
|
172
|
+
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
173
|
+
fieldConfigurations: {
|
|
174
|
+
address: {
|
|
175
|
+
useAddressHierarchy: {
|
|
176
|
+
enabled: true,
|
|
177
|
+
useQuickSearch: true,
|
|
178
|
+
searchAddressByLevel: false,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
}));
|
|
183
|
+
(useOrderedAddressHierarchyLevels as jest.Mock).mockImplementation(() => ({
|
|
184
|
+
orderedFields: [],
|
|
185
|
+
isLoadingFieldOrder: false,
|
|
186
|
+
errorFetchingFieldOrder: null,
|
|
187
|
+
}));
|
|
188
|
+
renderAddressHierarchy();
|
|
189
|
+
const addressSearchBar = screen.getByTestId('address-search-bar');
|
|
190
|
+
expect(addressSearchBar).toBeInTheDocument();
|
|
118
191
|
});
|
|
119
192
|
|
|
120
|
-
it('
|
|
193
|
+
it('should render combo boxes fields when address hierarchy is enabled and searchAddressByLevel is set to true', () => {
|
|
121
194
|
(useConfig as jest.Mock).mockImplementation(() => ({
|
|
122
195
|
fieldConfigurations: {
|
|
123
196
|
address: {
|
|
@@ -129,12 +202,13 @@ describe('address hierarchy', () => {
|
|
|
129
202
|
},
|
|
130
203
|
},
|
|
131
204
|
}));
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
205
|
+
(useOrderedAddressHierarchyLevels as jest.Mock).mockImplementation(() => ({
|
|
206
|
+
orderedFields: [],
|
|
207
|
+
isLoadingFieldOrder: false,
|
|
208
|
+
errorFetchingFieldOrder: null,
|
|
209
|
+
}));
|
|
210
|
+
renderAddressHierarchy();
|
|
211
|
+
const addressHierarchyLevels = screen.getByTestId('address-hierarchy-levels');
|
|
212
|
+
expect(addressHierarchyLevels).toBeInTheDocument();
|
|
139
213
|
});
|
|
140
214
|
});
|