@kenyaemr/esm-patient-registration-app 4.5.3 → 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.
Files changed (101) 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/879.js +1 -0
  23. package/dist/879.js.map +1 -0
  24. package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
  25. package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +171 -122
  26. package/dist/kenyaemr-esm-patient-registration-app.js.map +1 -1
  27. package/dist/main.js +1 -1
  28. package/dist/main.js.map +1 -1
  29. package/dist/routes.json +1 -1
  30. package/jest.config.js +3 -0
  31. package/package.json +5 -2
  32. package/src/config-schema.ts +11 -5
  33. package/src/index.ts +9 -2
  34. package/src/offline.resources.ts +8 -4
  35. package/src/offline.ts +1 -1
  36. package/src/patient-registration/field/__mocks__/field.resource.ts +1 -1
  37. package/src/patient-registration/field/address/address-field.component.tsx +25 -70
  38. package/src/patient-registration/field/address/address-hierarchy-levels.component.tsx +11 -9
  39. package/src/patient-registration/field/address/address-hierarchy.resource.tsx +57 -3
  40. package/src/patient-registration/field/address/address-search.component.tsx +1 -1
  41. package/src/patient-registration/field/address/tests/address-hierarchy.test.tsx +137 -63
  42. package/src/patient-registration/field/address/tests/address-search-component.test.tsx +128 -0
  43. package/src/patient-registration/field/address/tests/mocks.ts +93 -99
  44. package/src/patient-registration/field/dob/dob.component.tsx +48 -44
  45. package/src/patient-registration/field/dob/dob.test.tsx +6 -1
  46. package/src/patient-registration/field/field.resource.ts +1 -1
  47. package/src/patient-registration/field/id/id-field.component.tsx +1 -1
  48. package/src/patient-registration/field/id/identifier-selection-overlay.tsx +1 -1
  49. package/src/patient-registration/field/name/name-field.component.tsx +38 -22
  50. package/src/patient-registration/field/obs/obs-field.component.tsx +14 -13
  51. package/src/patient-registration/field/person-attributes/coded-attributes.component.tsx +1 -1
  52. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +1 -1
  53. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +103 -0
  54. package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +187 -0
  55. package/src/patient-registration/field/person-attributes/person-attributes.resource.tsx +1 -1
  56. package/src/patient-registration/field/person-attributes/text-person-attribute-field.component.tsx +3 -3
  57. package/src/patient-registration/field/person-attributes/text-person-attribute-field.test.tsx +88 -0
  58. package/src/patient-registration/form-manager.test.ts +1 -2
  59. package/src/patient-registration/form-manager.ts +1 -9
  60. package/src/patient-registration/input/basic-input/input/input.test.tsx +0 -135
  61. package/src/patient-registration/input/basic-input/select/select-input.test.tsx +8 -4
  62. package/src/patient-registration/input/combo-input/combo-input.component.tsx +8 -6
  63. package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +1 -1
  64. package/src/patient-registration/input/custom-input/identifier/utils.test.ts +81 -0
  65. package/src/patient-registration/input/custom-input/identifier/utils.ts +1 -1
  66. package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +1 -2
  67. package/src/patient-registration/patient-registration-context.ts +1 -1
  68. package/src/patient-registration/patient-registration-hooks.ts +14 -2
  69. package/src/patient-registration/patient-registration-utils.ts +1 -4
  70. package/src/patient-registration/patient-registration.component.tsx +1 -12
  71. package/src/patient-registration/patient-registration.resource.tsx +1 -72
  72. package/src/patient-registration/patient-registration.test.tsx +250 -247
  73. package/src/patient-registration/{patient-registration-types.tsx → patient-registration.types.tsx} +45 -1
  74. package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +83 -79
  75. package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +88 -0
  76. package/src/patient-registration/section/patient-relationships/relationships.resource.tsx +1 -1
  77. package/src/patient-registration/validation/patient-registration-validation.tsx +1 -1
  78. package/src/patient-verification/patient-verification-hook.tsx +12 -1
  79. package/src/patient-verification/patient-verification-utils.ts +1 -1
  80. package/src/patient-verification/patient-verification.component.tsx +1 -1
  81. package/src/patient-verification/verification-modal/confirm-prompt.component.tsx +11 -0
  82. package/src/root.component.tsx +1 -1
  83. package/src/routes.json +62 -51
  84. package/src/widgets/cancel-patient-edit.test.tsx +24 -0
  85. package/src/widgets/delete-identifier-confirmation-modal.test.tsx +31 -0
  86. package/src/widgets/display-photo.test.tsx +37 -0
  87. package/src/widgets/edit-patient-details-button.test.tsx +36 -0
  88. package/translations/am.json +0 -7
  89. package/translations/en.json +2 -5
  90. package/translations/es.json +0 -7
  91. package/translations/fr.json +0 -7
  92. package/translations/he.json +0 -7
  93. package/translations/km.json +0 -7
  94. package/__mocks__/react-i18next.js +0 -49
  95. package/dist/196.js +0 -1
  96. package/dist/196.js.map +0 -1
  97. package/dist/59.js +0 -1
  98. package/dist/59.js.map +0 -1
  99. package/dist/9.js +0 -2
  100. package/dist/9.js.map +0 -1
  101. /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;
@@ -25,9 +25,9 @@ export const DobField: React.FC = () => {
25
25
  const { t } = useTranslation();
26
26
  const {
27
27
  fieldConfigurations: { dateOfBirth },
28
- } = useConfig() as RegistrationConfig;
29
- const [dobUnknown] = useField('birthdateEstimated');
30
- const dobKnown = !dobUnknown.value;
28
+ } = useConfig<RegistrationConfig>();
29
+ const allowEstimatedBirthDate = dateOfBirth?.allowEstimatedDateOfBirth;
30
+ const [{ value: dobUnknown }] = useField('birthdateEstimated');
31
31
  const [birthdate, birthdateMeta] = useField('birthdate');
32
32
  const [yearsEstimated, yearsEstimateMeta] = useField('yearsEstimated');
33
33
  const [monthsEstimated, monthsEstimateMeta] = useField('monthsEstimated');
@@ -75,17 +75,19 @@ export const DobField: React.FC = () => {
75
75
  return (
76
76
  <div className={styles.halfWidthInDesktopView}>
77
77
  <h4 className={styles.productiveHeading02Light}>{t('birthFieldLabelText', 'Birth')}</h4>
78
- <div className={styles.dobField}>
79
- <div className={styles.dobContentSwitcherLabel}>
80
- <span className={styles.label01}>{t('dobToggleLabelText', 'Date of Birth Known?')}</span>
78
+ {(allowEstimatedBirthDate || dobUnknown) && (
79
+ <div className={styles.dobField}>
80
+ <div className={styles.dobContentSwitcherLabel}>
81
+ <span className={styles.label01}>{t('dobToggleLabelText', 'Date of Birth Known?')}</span>
82
+ </div>
83
+ <ContentSwitcher onChange={onToggle} selectedIndex={dobUnknown ? 1 : 0}>
84
+ <Switch name="known" text={t('yes', 'Yes')} />
85
+ <Switch name="unknown" text={t('no', 'No')} />
86
+ </ContentSwitcher>
81
87
  </div>
82
- <ContentSwitcher onChange={onToggle}>
83
- <Switch name="known" text={t('yes', 'Yes')} />
84
- <Switch name="unknown" text={t('no', 'No')} />
85
- </ContentSwitcher>
86
- </div>
88
+ )}
87
89
  <Layer>
88
- {dobKnown ? (
90
+ {!dobUnknown ? (
89
91
  <div className={styles.dobField}>
90
92
  <DatePicker dateFormat={dateFormat} datePickerType="single" onChange={onDateChange} maxDate={format(today)}>
91
93
  <DatePickerInput
@@ -102,38 +104,40 @@ export const DobField: React.FC = () => {
102
104
  ) : (
103
105
  <div className={styles.grid}>
104
106
  <div className={styles.dobField}>
105
- <TextInput
106
- id="yearsEstimated"
107
- type="number"
108
- name={yearsEstimated.name}
109
- light
110
- onChange={onEstimatedYearsChange}
111
- labelText={t('estimatedAgeInYearsLabelText', 'Estimated age in years')}
112
- invalid={!!(yearsEstimateMeta.touched && yearsEstimateMeta.error)}
113
- invalidText={yearsEstimateMeta.error && t(yearsEstimateMeta.error)}
114
- value={yearsEstimated.value}
115
- min={0}
116
- required
117
- {...yearsEstimated}
118
- onBlur={updateBirthdate}
119
- />
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>
120
123
  </div>
121
124
  <div className={styles.dobField}>
122
- <TextInput
123
- id="monthsEstimated"
124
- type="number"
125
- name={monthsEstimated.name}
126
- light
127
- onChange={onEstimatedMonthsChange}
128
- labelText={t('estimatedAgeInMonthsLabelText', 'Estimated age in months')}
129
- invalid={!!(monthsEstimateMeta.touched && monthsEstimateMeta.error)}
130
- invalidText={monthsEstimateMeta.error && t(monthsEstimateMeta.error)}
131
- value={monthsEstimated.value}
132
- min={0}
133
- {...monthsEstimated}
134
- required={!yearsEstimateMeta.value}
135
- onBlur={updateBirthdate}
136
- />
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>
137
141
  </div>
138
142
  </div>
139
143
  )}
@@ -14,7 +14,12 @@ jest.mock('@openmrs/esm-framework', () => {
14
14
  return {
15
15
  ...originalModule,
16
16
  useConfig: jest.fn().mockImplementation(() => ({
17
- fieldConfigurations: { dateOfBirth: { useEstimatedDateOfBirth: { enabled: true, dayOfMonth: 0, month: 0 } } },
17
+ fieldConfigurations: {
18
+ dateOfBirth: {
19
+ allowEstimatedDateOfBirth: true,
20
+ useEstimatedDateOfBirth: { enabled: true, dayOfMonth: 0, month: 0 },
21
+ },
22
+ },
18
23
  })),
19
24
  };
20
25
  });
@@ -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';
@@ -8,6 +8,7 @@ import { PatientRegistrationContext } from '../../patient-registration-context';
8
8
  import styles from '../field.scss';
9
9
  import { RegistrationConfig } from '../../../config-schema';
10
10
 
11
+ export const unidentifiedPatientAttributeTypeUuid = '8b56eac7-5c76-4b9c-8c6f-1deab8d3fc47';
11
12
  const containsNoNumbers = /^([^0-9]*)$/;
12
13
 
13
14
  function checkNumber(value: string) {
@@ -19,17 +20,26 @@ function checkNumber(value: string) {
19
20
  }
20
21
 
21
22
  export const NameField = () => {
23
+ const { t } = useTranslation();
24
+ const { setCapturePhotoProps, currentPhoto, setFieldValue } = useContext(PatientRegistrationContext);
22
25
  const {
23
26
  fieldConfigurations: {
24
- name: { displayCapturePhoto, displayReverseFieldOrder },
27
+ name: {
28
+ displayCapturePhoto,
29
+ allowUnidentifiedPatients,
30
+ defaultUnknownGivenName,
31
+ defaultUnknownFamilyName,
32
+ displayMiddleName,
33
+ displayReverseFieldOrder,
34
+ },
25
35
  },
26
- } = useConfig() as RegistrationConfig;
27
- const { t } = useTranslation();
28
- const { setCapturePhotoProps, currentPhoto, setFieldValue } = useContext(PatientRegistrationContext);
29
- const { fieldConfigurations } = useConfig();
30
- const fieldConfigs = fieldConfigurations?.name;
31
- const [{ value: unidentified }] = useField('unidentifiedPatient');
32
- const nameKnown = !unidentified;
36
+ } = useConfig<RegistrationConfig>();
37
+
38
+ const [{ value: isPatientUnknownValue }, , { setValue: setUnknownPatient }] = useField<string>(
39
+ `attributes.${unidentifiedPatientAttributeTypeUuid}`,
40
+ );
41
+
42
+ const isPatientUnknown = isPatientUnknownValue === 'true';
33
43
 
34
44
  const onCapturePhoto = useCallback(
35
45
  (dataUri: string, photoDateTime: string) => {
@@ -47,11 +57,11 @@ export const NameField = () => {
47
57
  if (e.name === 'known') {
48
58
  setFieldValue('givenName', '');
49
59
  setFieldValue('familyName', '');
50
- setFieldValue('unidentifiedPatient', false);
60
+ setUnknownPatient('false');
51
61
  } else {
52
- setFieldValue('givenName', fieldConfigs.defaultUnknownGivenName);
53
- setFieldValue('familyName', fieldConfigs.defaultUnknownFamilyName);
54
- setFieldValue('unidentifiedPatient', true);
62
+ setFieldValue('givenName', defaultUnknownGivenName);
63
+ setFieldValue('familyName', defaultUnknownFamilyName);
64
+ setUnknownPatient('true');
55
65
  }
56
66
  };
57
67
 
@@ -65,12 +75,11 @@ export const NameField = () => {
65
75
  />
66
76
  );
67
77
 
68
- const middleNameField = fieldConfigs.displayMiddleName && (
78
+ const middleNameField = displayMiddleName && (
69
79
  <Input
70
80
  id="middleName"
71
81
  name="middleName"
72
82
  labelText={t('middleNameLabelText', 'Middle Name')}
73
- light
74
83
  checkWarning={checkNumber}
75
84
  />
76
85
  );
@@ -98,14 +107,21 @@ export const NameField = () => {
98
107
  )}
99
108
 
100
109
  <div className={styles.nameField}>
101
- <div className={styles.dobContentSwitcherLabel}>
102
- <span className={styles.label01}>{t('patientNameKnown', "Patient's Name is Known?")}</span>
103
- </div>
104
- <ContentSwitcher className={styles.contentSwitcher} onChange={toggleNameKnown}>
105
- <Switch name="known" text={t('yes', 'Yes')} />
106
- <Switch name="unknown" text={t('no', 'No')} />
107
- </ContentSwitcher>
108
- {nameKnown &&
110
+ {(allowUnidentifiedPatients || isPatientUnknown) && (
111
+ <>
112
+ <div className={styles.dobContentSwitcherLabel}>
113
+ <span className={styles.label01}>{t('patientNameKnown', "Patient's Name is Known?")}</span>
114
+ </div>
115
+ <ContentSwitcher
116
+ className={styles.contentSwitcher}
117
+ selectedIndex={isPatientUnknown ? 1 : 0}
118
+ onChange={toggleNameKnown}>
119
+ <Switch name="known" text={t('yes', 'Yes')} />
120
+ <Switch name="unknown" text={t('no', 'No')} />
121
+ </ContentSwitcher>
122
+ </>
123
+ )}
124
+ {!isPatientUnknown &&
109
125
  (!displayReverseFieldOrder ? (
110
126
  <>
111
127
  {firstNameField}
@@ -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';