@kenyaemr/esm-patient-registration-app 4.5.4 → 4.5.6

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.
Files changed (95) hide show
  1. package/dist/117.js +2 -0
  2. package/dist/117.js.map +1 -0
  3. package/dist/130.js +1 -1
  4. package/dist/130.js.map +1 -1
  5. package/dist/208.js +1 -1
  6. package/dist/218.js +1 -0
  7. package/dist/218.js.map +1 -0
  8. package/dist/275.js +1 -0
  9. package/dist/275.js.map +1 -0
  10. package/dist/319.js +1 -1
  11. package/dist/{821.js → 348.js} +1 -1
  12. package/dist/{821.js.map → 348.js.map} +1 -1
  13. package/dist/574.js +1 -1
  14. package/dist/68.js +1 -1
  15. package/dist/68.js.map +1 -1
  16. package/dist/693.js +1 -0
  17. package/dist/693.js.map +1 -0
  18. package/dist/757.js +1 -1
  19. package/dist/788.js +1 -1
  20. package/dist/807.js +1 -1
  21. package/dist/833.js +1 -1
  22. package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
  23. package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +147 -122
  24. package/dist/kenyaemr-esm-patient-registration-app.js.map +1 -1
  25. package/dist/main.js +1 -1
  26. package/dist/main.js.map +1 -1
  27. package/dist/routes.json +1 -1
  28. package/jest.config.js +3 -0
  29. package/package.json +5 -2
  30. package/src/index.ts +9 -2
  31. package/src/offline.resources.ts +8 -4
  32. package/src/offline.ts +1 -1
  33. package/src/patient-registration/field/__mocks__/field.resource.ts +1 -1
  34. package/src/patient-registration/field/address/address-field.component.tsx +25 -70
  35. package/src/patient-registration/field/address/address-hierarchy-levels.component.tsx +11 -9
  36. package/src/patient-registration/field/address/address-hierarchy.resource.tsx +57 -3
  37. package/src/patient-registration/field/address/address-search.component.tsx +1 -1
  38. package/src/patient-registration/field/address/tests/address-hierarchy.test.tsx +137 -63
  39. package/src/patient-registration/field/address/tests/address-search-component.test.tsx +128 -0
  40. package/src/patient-registration/field/address/tests/mocks.ts +93 -99
  41. package/src/patient-registration/field/dob/dob.component.tsx +34 -32
  42. package/src/patient-registration/field/field.resource.ts +1 -1
  43. package/src/patient-registration/field/id/id-field.component.tsx +1 -1
  44. package/src/patient-registration/field/id/identifier-selection-overlay.tsx +1 -1
  45. package/src/patient-registration/field/name/name-field.component.tsx +0 -1
  46. package/src/patient-registration/field/obs/obs-field.component.tsx +14 -13
  47. package/src/patient-registration/field/person-attributes/coded-attributes.component.tsx +1 -1
  48. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +1 -1
  49. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +103 -0
  50. package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +187 -0
  51. package/src/patient-registration/field/person-attributes/person-attributes.resource.tsx +1 -1
  52. package/src/patient-registration/field/person-attributes/text-person-attribute-field.component.tsx +3 -3
  53. package/src/patient-registration/field/person-attributes/text-person-attribute-field.test.tsx +88 -0
  54. package/src/patient-registration/form-manager.test.ts +1 -1
  55. package/src/patient-registration/form-manager.ts +1 -1
  56. package/src/patient-registration/input/basic-input/input/input.test.tsx +0 -135
  57. package/src/patient-registration/input/basic-input/select/select-input.test.tsx +8 -4
  58. package/src/patient-registration/input/combo-input/combo-input.component.tsx +8 -6
  59. package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +1 -1
  60. package/src/patient-registration/input/custom-input/identifier/utils.test.ts +81 -0
  61. package/src/patient-registration/input/custom-input/identifier/utils.ts +1 -1
  62. package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +1 -1
  63. package/src/patient-registration/patient-registration-context.ts +1 -1
  64. package/src/patient-registration/patient-registration-hooks.ts +1 -1
  65. package/src/patient-registration/patient-registration-utils.ts +1 -1
  66. package/src/patient-registration/patient-registration.component.tsx +1 -12
  67. package/src/patient-registration/patient-registration.resource.tsx +1 -72
  68. package/src/patient-registration/patient-registration.test.tsx +250 -247
  69. package/src/patient-registration/{patient-registration-types.tsx → patient-registration.types.tsx} +45 -0
  70. package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +83 -79
  71. package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +88 -0
  72. package/src/patient-registration/section/patient-relationships/relationships.resource.tsx +1 -1
  73. package/src/patient-registration/validation/patient-registration-validation.tsx +1 -1
  74. package/src/patient-verification/patient-verification-hook.tsx +12 -1
  75. package/src/patient-verification/patient-verification-utils.ts +1 -1
  76. package/src/patient-verification/patient-verification.component.tsx +1 -1
  77. package/src/patient-verification/verification-modal/confirm-prompt.component.tsx +11 -0
  78. package/src/root.component.tsx +1 -1
  79. package/src/routes.json +62 -51
  80. package/src/widgets/display-photo.test.tsx +37 -0
  81. package/src/widgets/edit-patient-details-button.test.tsx +36 -0
  82. package/translations/am.json +0 -7
  83. package/translations/en.json +2 -5
  84. package/translations/es.json +0 -7
  85. package/translations/fr.json +0 -7
  86. package/translations/he.json +0 -7
  87. package/translations/km.json +0 -7
  88. package/__mocks__/react-i18next.js +0 -49
  89. package/dist/196.js +0 -1
  90. package/dist/196.js.map +0 -1
  91. package/dist/59.js +0 -1
  92. package/dist/59.js.map +0 -1
  93. package/dist/9.js +0 -2
  94. package/dist/9.js.map +0 -1
  95. /package/dist/{9.js.LICENSE.txt → 117.js.LICENSE.txt} +0 -0
@@ -0,0 +1,128 @@
1
+ import React from 'react';
2
+ import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
3
+ import { Formik, Form, useFormikContext } from 'formik';
4
+ import { Resources, ResourcesContext } from '../../../../offline.resources';
5
+ import { PatientRegistrationContext } from '../../../patient-registration-context';
6
+ import { useConfig } from '@openmrs/esm-framework';
7
+ import { useAddressHierarchy, useOrderedAddressHierarchyLevels } from '../address-hierarchy.resource';
8
+ import { mockedAddressTemplate, mockedAddressOptions, mockedOrderedFields } from './mocks';
9
+ import AddressSearchComponent from '../address-search.component';
10
+ import userEvent from '@testing-library/user-event';
11
+
12
+ useAddressHierarchy;
13
+ jest.mock('@openmrs/esm-framework', () => ({
14
+ ...jest.requireActual('@openmrs/esm-framework'),
15
+ useConfig: jest.fn(),
16
+ }));
17
+
18
+ jest.mock('../address-hierarchy.resource', () => ({
19
+ ...(jest.requireActual('../address-hierarchy.resource') as jest.Mock),
20
+ useOrderedAddressHierarchyLevels: jest.fn(),
21
+ useAddressHierarchy: jest.fn(),
22
+ }));
23
+
24
+ jest.mock('../../../patient-registration.resource', () => ({
25
+ ...(jest.requireActual('../../../../patient-registration.resource') as jest.Mock),
26
+ useAddressHierarchy: jest.fn(),
27
+ }));
28
+
29
+ jest.mock('formik', () => ({
30
+ ...(jest.requireActual('formik') as jest.Mock),
31
+ useFormikContext: jest.fn(() => ({})),
32
+ }));
33
+
34
+ const allFields = mockedAddressTemplate.lines
35
+ .flat()
36
+ .filter((field) => field.isToken === 'IS_ADDR_TOKEN')
37
+ .map(({ codeName, displayText }) => ({
38
+ id: codeName,
39
+ name: codeName,
40
+ label: displayText,
41
+ }));
42
+ const orderMap = Object.fromEntries(mockedOrderedFields.map((field, indx) => [field, indx]));
43
+ allFields.sort((existingField1, existingField2) => orderMap[existingField1.name] - orderMap[existingField2.name]);
44
+
45
+ async function renderAddressHierarchy(addressTemplate = mockedAddressTemplate) {
46
+ await render(
47
+ <ResourcesContext.Provider value={{ addressTemplate } as Resources}>
48
+ <Formik initialValues={{}} onSubmit={null}>
49
+ <Form>
50
+ <PatientRegistrationContext.Provider value={{ setFieldValue: jest.fn() } as any}>
51
+ <AddressSearchComponent addressLayout={allFields} />
52
+ </PatientRegistrationContext.Provider>
53
+ </Form>
54
+ </Formik>
55
+ </ResourcesContext.Provider>,
56
+ );
57
+ }
58
+
59
+ const setFieldValue = jest.fn();
60
+
61
+ describe('Testing address search bar', () => {
62
+ beforeEach(() => {
63
+ cleanup();
64
+ (useConfig as jest.Mock).mockImplementation(() => ({
65
+ fieldConfigurations: {
66
+ address: {
67
+ useAddressHierarchy: {
68
+ enabled: true,
69
+ useQuickSearch: true,
70
+ searchAddressByLevel: false,
71
+ },
72
+ },
73
+ },
74
+ }));
75
+ (useOrderedAddressHierarchyLevels as jest.Mock).mockImplementation(() => ({
76
+ orderedFields: mockedOrderedFields,
77
+ isLoadingFieldOrder: false,
78
+ errorFetchingFieldOrder: null,
79
+ }));
80
+ (useFormikContext as jest.Mock).mockImplementation(() => ({
81
+ setFieldValue,
82
+ }));
83
+ });
84
+
85
+ it('should render the search bar', () => {
86
+ (useAddressHierarchy as jest.Mock).mockImplementation(() => ({
87
+ addresses: [],
88
+ error: null,
89
+ isLoading: false,
90
+ }));
91
+ renderAddressHierarchy();
92
+ const searchbox = screen.getByRole('searchbox');
93
+ expect(searchbox).toBeInTheDocument();
94
+ const ul = screen.queryByRole('list');
95
+ expect(ul).not.toBeInTheDocument();
96
+ });
97
+
98
+ it("should render only the results for the search term matched address' parents", async () => {
99
+ (useAddressHierarchy as jest.Mock).mockImplementation(() => ({
100
+ addresses: mockedAddressOptions,
101
+ error: null,
102
+ isLoading: false,
103
+ }));
104
+ renderAddressHierarchy();
105
+ const searchString = 'nea';
106
+ const separator = ' > ';
107
+ const options: Set<string> = new Set();
108
+ mockedAddressOptions.forEach((address) => {
109
+ const values = address.split(separator);
110
+ values.forEach((val, index) => {
111
+ if (val.toLowerCase().includes(searchString.toLowerCase())) {
112
+ options.add(values.slice(0, index + 1).join(separator));
113
+ }
114
+ });
115
+ });
116
+
117
+ const addressOptions = [...options];
118
+ addressOptions.forEach(async (address) => {
119
+ const optionElement = screen.getByText(address);
120
+ expect(optionElement).toBeInTheDocument();
121
+ fireEvent.click(optionElement);
122
+ const values = address.split(separator);
123
+ allFields.map(({ name }, index) => {
124
+ waitFor(() => expect(setFieldValue).toBeCalledWith(`address.${name}`, values?.[index]));
125
+ });
126
+ });
127
+ });
128
+ });
@@ -1,104 +1,98 @@
1
- export const mockResponse1 = {
2
- results: [
3
- {
4
- value:
5
- '<?xml version="1.0" encoding="UTF-8"?> \
6
- <org.openmrs.layout.address.AddressTemplate> \
7
- <nameMappings class="properties"> \
8
- <property name="postalCode" value="Postcode" /> \
9
- <property name="address1" value="Address line 1" /> \
10
- <property name="address2" value="Address line 2" /> \
11
- <property name="country" value="Country" /> \
12
- <property name="stateProvince" value="State" /> \
13
- <property name="cityVillage" value="City" /> \
14
- </nameMappings> \
15
- <sizeMappings class="properties"> \
16
- <property name="postalCode" value="10" /> \
17
- <property name="address2" value="40" /> \
18
- <property name="address1" value="40" /> \
19
- <property name="country" value="10" /> \
20
- <property name="stateProvince" value="10" /> \
21
- <property name="cityVillage" value="10" /> \
22
- </sizeMappings> \
23
- <lineByLineFormat> \
24
- <string> address1</string> \
25
- <string> address2</string> \
26
- <string> cityVillage stateProvince country postalCode</string> \
27
- </lineByLineFormat> \
28
- <requiredElements /> \
29
- </org.openmrs.layout.address.AddressTemplate>',
30
- },
31
- ],
32
- };
1
+ import { AddressTemplate } from '../../../patient-registration.types';
33
2
 
34
- export const mockResponse2 = {
35
- results: [
36
- {
37
- value:
38
- '<org.openmrs.layout.address.AddressTemplate> \
39
- <nameMappings> \
40
- <entry> \
41
- <string>country</string> \
42
- <string>Country</string> \
43
- </entry> \
44
- <entry> \
45
- <string>postalCode</string> \
46
- <string>Postcode</string> \
47
- </entry> \
48
- <entry> \
49
- <string>address1</string> \
50
- <string>Address line 1</string> \
51
- </entry> \
52
- <entry> \
53
- <string>address2</string> \
54
- <string>Address line 2</string> \
55
- </entry> \
56
- <entry> \
57
- <string>stateProvince</string> \
58
- <string>State</string> \
59
- </entry> \
60
- <entry> \
61
- <string>cityVillage</string> \
62
- <string>City</string> \
63
- </entry> \
64
- </nameMappings> \
65
- <sizeMappings> \
66
- <entry> \
67
- <string>country</string> \
68
- <string>40</string> \
69
- </entry> \
70
- <entry> \
71
- <string>countyDistrict</string> \
72
- <string>40</string> \
73
- </entry> \
74
- <entry> \
75
- <string>address1</string> \
76
- <string>40</string> \
77
- </entry> \
78
- <entry> \
79
- <string>stateProvince</string> \
80
- <string>40</string> \
81
- </entry> \
82
- <entry> \
83
- <string>cityVillage</string> \
84
- <string>40</string> \
85
- </entry> \
86
- </sizeMappings> \
87
- <elementDefaults> \
88
- <entry> \
89
- <string>country</string> \
90
- <string>Cambodia</string> \
91
- </entry> \
92
- </elementDefaults> \
93
- <lineByLineFormat> \
94
- <string>cityVillage, address1</string> \
95
- <string>countyDistrict, stateProvince</string> \
96
- <string>country</string> \
97
- </lineByLineFormat> \
98
- <maxTokens>0</maxTokens> \
99
- </org.openmrs.layout.address.AddressTemplate>',
100
- },
3
+ export const mockedAddressTemplate: AddressTemplate = {
4
+ displayName: null,
5
+ codeName: 'default',
6
+ country: null,
7
+ lines: [
8
+ [
9
+ {
10
+ isToken: 'IS_NOT_ADDR_TOKEN',
11
+ displayText: '',
12
+ },
13
+ {
14
+ isToken: 'IS_ADDR_TOKEN',
15
+ displayText: 'Village',
16
+ codeName: 'cityVillage',
17
+ displaySize: '40',
18
+ },
19
+ {
20
+ isToken: 'IS_NOT_ADDR_TOKEN',
21
+ displayText: ', ',
22
+ },
23
+ {
24
+ isToken: 'IS_ADDR_TOKEN',
25
+ displayText: 'Commune',
26
+ codeName: 'address1',
27
+ displaySize: '40',
28
+ },
29
+ ],
30
+ [
31
+ {
32
+ isToken: 'IS_NOT_ADDR_TOKEN',
33
+ displayText: '',
34
+ },
35
+ {
36
+ isToken: 'IS_ADDR_TOKEN',
37
+ displayText: 'District',
38
+ codeName: 'countyDistrict',
39
+ displaySize: '40',
40
+ },
41
+ {
42
+ isToken: 'IS_NOT_ADDR_TOKEN',
43
+ displayText: ', ',
44
+ },
45
+ {
46
+ isToken: 'IS_ADDR_TOKEN',
47
+ displayText: 'Province',
48
+ codeName: 'stateProvince',
49
+ displaySize: '40',
50
+ },
51
+ ],
52
+ [
53
+ {
54
+ isToken: 'IS_NOT_ADDR_TOKEN',
55
+ displayText: '',
56
+ },
57
+ {
58
+ isToken: 'IS_ADDR_TOKEN',
59
+ displayText: 'Country',
60
+ codeName: 'country',
61
+ displaySize: '40',
62
+ },
63
+ ],
101
64
  ],
65
+ lineByLineFormat: ['cityVillage, address1', 'countyDistrict, stateProvince', 'country'],
66
+ nameMappings: {
67
+ country: 'Country',
68
+ countyDistrict: 'District',
69
+ address1: 'Commune',
70
+ stateProvince: 'Province',
71
+ cityVillage: 'Village',
72
+ },
73
+ sizeMappings: {
74
+ country: '40',
75
+ countyDistrict: '40',
76
+ address1: '40',
77
+ stateProvince: '40',
78
+ cityVillage: '40',
79
+ },
80
+ elementDefaults: {
81
+ country: 'កម្ពុជា (Cambodia)',
82
+ },
83
+ elementRegex: null,
84
+ elementRegexFormats: null,
85
+ requiredElements: null,
102
86
  };
103
87
 
104
88
  export const mockedOrderedFields = ['country', 'stateProvince', 'cityVillage', 'postalCode', 'address1', 'address2'];
89
+ export const mockedAddressOptions = [
90
+ 'Cambodia > Banteay Meanchey > Mongkol Borei > Banteay Neang > Ou Thum',
91
+ 'Cambodia > Battambang > Banan > Ta Kream > Andoung Neang',
92
+ 'Cambodia > Banteay Meanchey > Mongkol Borei > Banteay Neang > Phnum',
93
+ 'Cambodia > Kampong Cham > Chamkar Leu > Ta Prok > Neang Laeung',
94
+ 'Cambodia > Battambang > Thma Koul > Ta Meun > Tumneab',
95
+ 'Cambodia > Banteay Meanchey > Mongkol Borei > Banteay Neang > Banteay Neang',
96
+ 'Cambodia > Banteay Meanchey > Phnum Srok > Spean Sraeng > Mukh Chhneang',
97
+ 'Cambodia > Kampong Cham > Cheung Prey > Phdau Chum > Cham Neang',
98
+ ];
@@ -1,12 +1,12 @@
1
1
  import React, { useContext } from 'react';
2
- import { ContentSwitcher, DatePicker, DatePickerInput, Switch, TextInput, Layer } from '@carbon/react';
2
+ import { ContentSwitcher, DatePicker, DatePickerInput, Layer, Switch, TextInput } from '@carbon/react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { useField } from 'formik';
5
5
  import { generateFormatting } from '../../date-util';
6
6
  import { PatientRegistrationContext } from '../../patient-registration-context';
7
- import styles from '../field.scss';
8
7
  import { useConfig } from '@openmrs/esm-framework';
9
8
  import { RegistrationConfig } from '../../../config-schema';
9
+ import styles from '../field.scss';
10
10
 
11
11
  const calcBirthdate = (yearDelta, monthDelta, dateOfBirth) => {
12
12
  const { enabled, month, dayOfMonth } = dateOfBirth.useEstimatedDateOfBirth;
@@ -104,38 +104,40 @@ export const DobField: React.FC = () => {
104
104
  ) : (
105
105
  <div className={styles.grid}>
106
106
  <div className={styles.dobField}>
107
- <TextInput
108
- id="yearsEstimated"
109
- type="number"
110
- name={yearsEstimated.name}
111
- light
112
- onChange={onEstimatedYearsChange}
113
- labelText={t('estimatedAgeInYearsLabelText', 'Estimated age in years')}
114
- invalid={!!(yearsEstimateMeta.touched && yearsEstimateMeta.error)}
115
- invalidText={yearsEstimateMeta.error && t(yearsEstimateMeta.error)}
116
- value={yearsEstimated.value}
117
- min={0}
118
- required
119
- {...yearsEstimated}
120
- onBlur={updateBirthdate}
121
- />
107
+ <Layer>
108
+ <TextInput
109
+ id="yearsEstimated"
110
+ type="number"
111
+ name={yearsEstimated.name}
112
+ onChange={onEstimatedYearsChange}
113
+ labelText={t('estimatedAgeInYearsLabelText', 'Estimated age in years')}
114
+ invalid={!!(yearsEstimateMeta.touched && yearsEstimateMeta.error)}
115
+ invalidText={yearsEstimateMeta.error && t(yearsEstimateMeta.error)}
116
+ value={yearsEstimated.value}
117
+ min={0}
118
+ required
119
+ {...yearsEstimated}
120
+ onBlur={updateBirthdate}
121
+ />
122
+ </Layer>
122
123
  </div>
123
124
  <div className={styles.dobField}>
124
- <TextInput
125
- id="monthsEstimated"
126
- type="number"
127
- name={monthsEstimated.name}
128
- light
129
- onChange={onEstimatedMonthsChange}
130
- labelText={t('estimatedAgeInMonthsLabelText', 'Estimated age in months')}
131
- invalid={!!(monthsEstimateMeta.touched && monthsEstimateMeta.error)}
132
- invalidText={monthsEstimateMeta.error && t(monthsEstimateMeta.error)}
133
- value={monthsEstimated.value}
134
- min={0}
135
- {...monthsEstimated}
136
- required={!yearsEstimateMeta.value}
137
- onBlur={updateBirthdate}
138
- />
125
+ <Layer>
126
+ <TextInput
127
+ id="monthsEstimated"
128
+ type="number"
129
+ name={monthsEstimated.name}
130
+ onChange={onEstimatedMonthsChange}
131
+ labelText={t('estimatedAgeInMonthsLabelText', 'Estimated age in months')}
132
+ invalid={!!(monthsEstimateMeta.touched && monthsEstimateMeta.error)}
133
+ invalidText={monthsEstimateMeta.error && t(monthsEstimateMeta.error)}
134
+ value={monthsEstimated.value}
135
+ min={0}
136
+ {...monthsEstimated}
137
+ required={!yearsEstimateMeta.value}
138
+ onBlur={updateBirthdate}
139
+ />
140
+ </Layer>
139
141
  </div>
140
142
  </div>
141
143
  )}
@@ -1,6 +1,6 @@
1
1
  import { FetchResponse, openmrsFetch, showToast } from '@openmrs/esm-framework';
2
2
  import useSWRImmutable from 'swr/immutable';
3
- import { ConceptAnswers, ConceptResponse } from '../patient-registration-types';
3
+ import { ConceptAnswers, ConceptResponse } from '../patient-registration.types';
4
4
 
5
5
  export function useConcept(conceptUuid: string): { data: ConceptResponse; isLoading: boolean } {
6
6
  const shouldFetch = typeof conceptUuid === 'string' && conceptUuid !== '';
@@ -11,7 +11,7 @@ import {
11
11
  IdentifierSource,
12
12
  PatientIdentifierType,
13
13
  PatientIdentifierValue,
14
- } from '../../patient-registration-types';
14
+ } from '../../patient-registration.types';
15
15
  import { ResourcesContext } from '../../../offline.resources';
16
16
  import styles from '../field.scss';
17
17
 
@@ -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 { FormValues, PatientIdentifierType, PatientIdentifierValue } from '../../patient-registration.types';
6
6
  import Overlay from '../../ui-components/overlay';
7
7
  import { ResourcesContext } from '../../../offline.resources';
8
8
  import { PatientRegistrationContext } from '../../patient-registration-context';
@@ -80,7 +80,6 @@ export const NameField = () => {
80
80
  id="middleName"
81
81
  name="middleName"
82
82
  labelText={t('middleNameLabelText', 'Middle Name')}
83
- light
84
83
  checkWarning={checkNumber}
85
84
  />
86
85
  );
@@ -3,7 +3,7 @@ import { Field } from 'formik';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { InlineNotification, Layer, Select, SelectItem } from '@carbon/react';
5
5
  import { useConfig } from '@openmrs/esm-framework';
6
- import { ConceptResponse } from '../../patient-registration-types';
6
+ import { ConceptResponse } from '../../patient-registration.types';
7
7
  import { FieldDefinition, RegistrationConfig } from '../../../config-schema';
8
8
  import { Input } from '../../input/basic-input/input/input.component';
9
9
  import { useConcept, useConceptAnswers } from '../field.resource';
@@ -148,18 +148,19 @@ function CodedObsField({ concept, answerConceptSetUuid, label }: CodedObsFieldPr
148
148
  {({ field, form: { touched, errors }, meta }) => {
149
149
  if (fieldDefinition?.customConceptAnswers?.length) {
150
150
  return (
151
- <Select
152
- id={fieldName}
153
- name={fieldName}
154
- labelText={label ?? concept?.display}
155
- light
156
- invalid={errors[fieldName] && touched[fieldName]}
157
- {...field}>
158
- <SelectItem key={`no-answer-select-item-${fieldName}`} value={''} text="" />
159
- {fieldDefinition?.customConceptAnswers.map((answer) => (
160
- <SelectItem key={answer.uuid} value={answer.uuid} text={answer.label} />
161
- ))}
162
- </Select>
151
+ <Layer>
152
+ <Select
153
+ id={fieldName}
154
+ name={fieldName}
155
+ labelText={label ?? concept?.display}
156
+ invalid={errors[fieldName] && touched[fieldName]}
157
+ {...field}>
158
+ <SelectItem key={`no-answer-select-item-${fieldName}`} value={''} text="" />
159
+ {fieldDefinition?.customConceptAnswers.map((answer) => (
160
+ <SelectItem key={answer.uuid} value={answer.uuid} text={answer.label} />
161
+ ))}
162
+ </Select>
163
+ </Layer>
163
164
  );
164
165
  }
165
166
  return (
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { Layer, Select, SelectItem } from '@carbon/react';
3
3
  import { useConfig } from '@openmrs/esm-framework';
4
4
  import { Input } from '../../input/basic-input/input/input.component';
5
- import { CodedPersonAttributeConfig } from '../../patient-registration-types';
5
+ import { CodedPersonAttributeConfig } from '../../patient-registration.types';
6
6
  import { useConceptAnswers } from '../field.resource';
7
7
  import { usePersonAttributeType } from './person-attributes.resource';
8
8
  import styles from './../field.scss';
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Layer, Select, SelectItem } from '@carbon/react';
3
3
  import { Input } from '../../input/basic-input/input/input.component';
4
- import { PersonAttributeTypeResponse } from '../../patient-registration-types';
4
+ import { PersonAttributeTypeResponse } from '../../patient-registration.types';
5
5
  import { useConceptAnswers } from '../field.resource';
6
6
  import styles from './../field.scss';
7
7
  import { useTranslation } from 'react-i18next';
@@ -0,0 +1,103 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { useConceptAnswers } from '../field.resource';
4
+ import { CodedPersonAttributeField } from './coded-person-attribute-field.component';
5
+ import { Form, Formik } from 'formik';
6
+
7
+ jest.mock('formik', () => ({
8
+ ...jest.requireActual('formik'),
9
+ }));
10
+
11
+ jest.mock('../field.resource'); // Mock the useConceptAnswers hook
12
+
13
+ const mockedUseConceptAnswers = useConceptAnswers as jest.Mock;
14
+
15
+ describe('CodedPersonAttributeField', () => {
16
+ const conceptAnswers = [
17
+ { uuid: '1', display: 'Option 1' },
18
+ { uuid: '2', display: 'Option 2' },
19
+ ];
20
+ const personAttributeType = {
21
+ format: 'org.openmrs.Concept',
22
+ display: 'Referred by',
23
+ uuid: '4dd56a75-14ab-4148-8700-1f4f704dc5b0',
24
+ };
25
+ const answerConceptSetUuid = '6682d17f-0777-45e4-a39b-93f77eb3531c';
26
+
27
+ beforeEach(() => {
28
+ jest.clearAllMocks();
29
+ mockedUseConceptAnswers.mockReturnValue({
30
+ data: conceptAnswers,
31
+ isLoading: false,
32
+ });
33
+ });
34
+
35
+ it('renders the Select component when conceptAnswers are available', () => {
36
+ render(
37
+ <Formik initialValues={{}} onSubmit={() => {}}>
38
+ <Form>
39
+ <CodedPersonAttributeField
40
+ id="attributeId"
41
+ personAttributeType={personAttributeType}
42
+ answerConceptSetUuid={answerConceptSetUuid}
43
+ label={personAttributeType.display}
44
+ />
45
+ </Form>
46
+ </Formik>,
47
+ );
48
+
49
+ expect(screen.getByLabelText(/Referred by/i)).toBeInTheDocument();
50
+ expect(screen.getByText(/Option 1/i)).toBeInTheDocument();
51
+ expect(screen.getByText(/Option 2/i)).toBeInTheDocument();
52
+ });
53
+
54
+ it('renders the Input component when conceptAnswers are not available', () => {
55
+ mockedUseConceptAnswers.mockReturnValueOnce({
56
+ data: null,
57
+ isLoading: false,
58
+ });
59
+
60
+ render(
61
+ <Formik initialValues={{}} onSubmit={() => {}}>
62
+ <Form>
63
+ <CodedPersonAttributeField
64
+ id="attributeId"
65
+ personAttributeType={personAttributeType}
66
+ answerConceptSetUuid={answerConceptSetUuid}
67
+ label={personAttributeType.display}
68
+ />
69
+ </Form>
70
+ </Formik>,
71
+ );
72
+
73
+ expect(screen.getByLabelText(/Referred by/i)).toBeInTheDocument();
74
+ expect(screen.queryByText(/Option 1/i)).not.toBeInTheDocument();
75
+ expect(screen.queryByText(/Option 2/i)).not.toBeInTheDocument();
76
+ expect(screen.getByRole('textbox')).toBeInTheDocument();
77
+ });
78
+
79
+ it('renders the Input component when conceptAnswers are still loading', () => {
80
+ mockedUseConceptAnswers.mockReturnValueOnce({
81
+ data: null,
82
+ isLoading: true,
83
+ });
84
+
85
+ render(
86
+ <Formik initialValues={{}} onSubmit={() => {}}>
87
+ <Form>
88
+ <CodedPersonAttributeField
89
+ id="attributeId"
90
+ personAttributeType={personAttributeType}
91
+ answerConceptSetUuid={answerConceptSetUuid}
92
+ label={personAttributeType.display}
93
+ />
94
+ </Form>
95
+ </Formik>,
96
+ );
97
+
98
+ expect(screen.getByLabelText(/Referred by/i)).toBeInTheDocument();
99
+ expect(screen.queryByText(/Option 1/i)).not.toBeInTheDocument();
100
+ expect(screen.queryByText(/Option 2/i)).not.toBeInTheDocument();
101
+ expect(screen.getByRole('textbox')).toBeInTheDocument();
102
+ });
103
+ });