@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.
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,187 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { usePersonAttributeType } from './person-attributes.resource';
4
+ import { PersonAttributeField } from './person-attribute-field.component';
5
+ import { useConceptAnswers } from '../field.resource';
6
+ import { Form, Formik } from 'formik';
7
+ import { FieldDefinition } from '../../../config-schema';
8
+
9
+ jest.mock('./person-attributes.resource'); // Mock the usePersonAttributeType hook
10
+ jest.mock('../field.resource'); // Mock the useConceptAnswers hook
11
+
12
+ jest.mock('formik', () => ({
13
+ ...jest.requireActual('formik'),
14
+ }));
15
+
16
+ const mockedUsePersonAttributeType = usePersonAttributeType as jest.Mock;
17
+ const mockedUseConceptAnswers = useConceptAnswers as jest.Mock;
18
+
19
+ let fieldDefinition: FieldDefinition;
20
+
21
+ describe('PersonAttributeField', () => {
22
+ let mockPersonAttributeType = {
23
+ format: 'java.lang.String',
24
+ display: 'Referred by',
25
+ uuid: '4dd56a75-14ab-4148-8700-1f4f704dc5b0',
26
+ };
27
+
28
+ beforeEach(() => {
29
+ fieldDefinition = {
30
+ id: 'referredby',
31
+ name: 'Referred by',
32
+ type: 'person attribute',
33
+ uuid: '4dd56a75-14ab-4148-8700-1f4f704dc5b0',
34
+ answerConceptSetUuid: '6682d17f-0777-45e4-a39b-93f77eb3531c',
35
+ validation: {
36
+ matches: '',
37
+ required: true,
38
+ },
39
+ showHeading: true,
40
+ };
41
+ mockedUsePersonAttributeType.mockReturnValue({
42
+ data: mockPersonAttributeType,
43
+ isLoading: false,
44
+ error: null,
45
+ uuid: '14d4f066-15f5-102d-96e4-000c29c2a5d7d',
46
+ });
47
+ });
48
+
49
+ afterEach(() => {
50
+ jest.resetAllMocks();
51
+ });
52
+
53
+ it('renders the text input field for String format', () => {
54
+ render(
55
+ <Formik initialValues={{}} onSubmit={() => {}}>
56
+ <Form>
57
+ <PersonAttributeField fieldDefinition={fieldDefinition} />
58
+ </Form>
59
+ </Formik>,
60
+ );
61
+
62
+ const input = screen.getByLabelText(/Referred by/i) as HTMLInputElement;
63
+ expect(screen.getByRole('heading')).toBeInTheDocument();
64
+ expect(input).toBeInTheDocument();
65
+ expect(input.type).toBe('text');
66
+ });
67
+
68
+ it('should not show heading if showHeading is false', () => {
69
+ fieldDefinition = {
70
+ ...fieldDefinition,
71
+ showHeading: false,
72
+ };
73
+
74
+ render(
75
+ <Formik initialValues={{}} onSubmit={() => {}}>
76
+ <Form>
77
+ <PersonAttributeField fieldDefinition={fieldDefinition} />
78
+ </Form>
79
+ </Formik>,
80
+ );
81
+ expect(screen.queryByRole('heading')).not.toBeInTheDocument();
82
+ });
83
+
84
+ it('renders the coded attribute field for Concept format', () => {
85
+ mockedUsePersonAttributeType.mockReturnValue({
86
+ data: { ...mockPersonAttributeType, format: 'org.openmrs.Concept' },
87
+ isLoading: false,
88
+ error: null,
89
+ });
90
+
91
+ fieldDefinition = {
92
+ id: 'referredby',
93
+ ...fieldDefinition,
94
+ label: 'Referred by',
95
+ };
96
+
97
+ mockedUseConceptAnswers.mockReturnValueOnce({
98
+ data: [
99
+ { uuid: '1', display: 'Option 1' },
100
+ { uuid: '2', display: 'Option 2' },
101
+ ],
102
+ isLoading: false,
103
+ });
104
+
105
+ render(
106
+ <Formik initialValues={{}} onSubmit={() => {}}>
107
+ <Form>
108
+ <PersonAttributeField fieldDefinition={fieldDefinition} />
109
+ </Form>
110
+ </Formik>,
111
+ );
112
+
113
+ const input = screen.getByLabelText(/Referred by/i) as HTMLInputElement;
114
+ expect(input).toBeInTheDocument();
115
+ expect(input.type).toBe('select-one');
116
+ expect(screen.getByText('Option 1')).toBeInTheDocument();
117
+ expect(screen.getByText('Option 2')).toBeInTheDocument();
118
+ });
119
+
120
+ it('renders an error notification if attribute type has unknown format', () => {
121
+ mockedUsePersonAttributeType.mockReturnValue({
122
+ data: { ...mockPersonAttributeType, format: 'unknown' },
123
+ isLoading: false,
124
+ error: null,
125
+ });
126
+
127
+ render(
128
+ <Formik initialValues={{}} onSubmit={() => {}}>
129
+ <Form>
130
+ <PersonAttributeField fieldDefinition={fieldDefinition} />
131
+ </Form>
132
+ </Formik>,
133
+ );
134
+
135
+ expect(screen.getByText('Error')).toBeInTheDocument();
136
+ expect(screen.getByText(/Patient attribute type has unknown format/i)).toBeInTheDocument();
137
+ });
138
+ it('renders an error notification if unable to fetch attribute type', () => {
139
+ mockedUsePersonAttributeType.mockReturnValue({
140
+ data: null,
141
+ isLoading: false,
142
+ error: new Error('Failed to fetch attribute type'),
143
+ });
144
+
145
+ fieldDefinition = {
146
+ uuid: 'attribute-uuid',
147
+ label: 'Attribute',
148
+ showHeading: false,
149
+ };
150
+
151
+ render(
152
+ <Formik initialValues={{}} onSubmit={() => {}}>
153
+ <Form>
154
+ <PersonAttributeField fieldDefinition={fieldDefinition} />
155
+ </Form>
156
+ </Formik>,
157
+ );
158
+
159
+ expect(screen.getByText('Error')).toBeInTheDocument();
160
+ expect(screen.getByText(/Unable to fetch person attribute type/i)).toBeInTheDocument();
161
+ });
162
+
163
+ it('renders a skeleton if attribute type is loading', () => {
164
+ mockedUsePersonAttributeType.mockReturnValue({
165
+ data: null,
166
+ isLoading: true,
167
+ error: null,
168
+ });
169
+
170
+ fieldDefinition = {
171
+ uuid: 'attribute-uuid',
172
+ label: 'Attribute',
173
+ showHeading: true,
174
+ };
175
+
176
+ render(
177
+ <Formik initialValues={{}} onSubmit={() => {}}>
178
+ <Form>
179
+ <PersonAttributeField fieldDefinition={fieldDefinition} />
180
+ </Form>
181
+ </Formik>,
182
+ );
183
+ const input = screen.findByLabelText(/Reffered by/i);
184
+ expect(screen.getByText(/Attribute/i)).toBeInTheDocument();
185
+ expect(input).not.toBeNull(); // checks that the input is not rendered when the attribute type is loading
186
+ });
187
+ });
@@ -1,6 +1,6 @@
1
1
  import { FetchResponse, openmrsFetch, showToast } from '@openmrs/esm-framework';
2
2
  import useSWRImmutable from 'swr/immutable';
3
- import { PersonAttributeTypeResponse } from '../../patient-registration-types';
3
+ import { PersonAttributeTypeResponse } from '../../patient-registration.types';
4
4
 
5
5
  export function usePersonAttributeType(personAttributeTypeUuid: string): {
6
6
  data: PersonAttributeTypeResponse;
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
- import styles from './../field.scss';
3
- import { Input } from '../../input/basic-input/input/input.component';
4
2
  import { Field } from 'formik';
5
3
  import { useTranslation } from 'react-i18next';
6
- import { PersonAttributeTypeResponse } from '../../patient-registration-types';
4
+ import { Input } from '../../input/basic-input/input/input.component';
5
+ import styles from './../field.scss';
6
+ import { PersonAttributeTypeResponse } from '../../patient-registration.types';
7
7
 
8
8
  export interface TextPersonAttributeFieldProps {
9
9
  id: string;
@@ -0,0 +1,88 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { Form, Formik } from 'formik';
5
+ import { TextPersonAttributeField } from './text-person-attribute-field.component';
6
+
7
+ describe('TextPersonAttributeField', () => {
8
+ const mockPersonAttributeType = {
9
+ format: 'java.lang.String',
10
+ display: 'Referred by',
11
+ uuid: '4dd56a75-14ab-4148-8700-1f4f704dc5b0',
12
+ };
13
+
14
+ it('renders the input field with a label', () => {
15
+ render(
16
+ <Formik initialValues={{}} onSubmit={() => {}}>
17
+ <Form>
18
+ <TextPersonAttributeField
19
+ id="attributeId"
20
+ personAttributeType={mockPersonAttributeType}
21
+ label="Custom Label"
22
+ />
23
+ </Form>
24
+ </Formik>,
25
+ );
26
+
27
+ expect(screen.getByRole('textbox', { name: /custom label \(optional\)/i })).toBeInTheDocument();
28
+ });
29
+
30
+ it('renders the input field with the default label if label prop is not provided', () => {
31
+ render(
32
+ <Formik initialValues={{}} onSubmit={() => {}}>
33
+ <Form>
34
+ <TextPersonAttributeField id="attributeId" personAttributeType={mockPersonAttributeType} />
35
+ </Form>
36
+ </Formik>,
37
+ );
38
+
39
+ expect(screen.getByRole('textbox', { name: /referred by \(optional\)/i })).toBeInTheDocument();
40
+ });
41
+
42
+ it('validates the input with the provided validationRegex', async () => {
43
+ const user = userEvent.setup();
44
+ const validationRegex = '^[A-Z]+$'; // Accepts only uppercase letters
45
+
46
+ render(
47
+ <Formik initialValues={{}} onSubmit={() => {}}>
48
+ <Form>
49
+ <TextPersonAttributeField
50
+ id="attributeId"
51
+ personAttributeType={mockPersonAttributeType}
52
+ validationRegex={validationRegex}
53
+ />
54
+ </Form>
55
+ </Formik>,
56
+ );
57
+
58
+ const textbox = screen.getByRole('textbox', { name: /referred by \(optional\)/i });
59
+ expect(textbox).toBeInTheDocument();
60
+
61
+ // Valid input: "ABC"
62
+ await user.type(textbox, 'ABC');
63
+ await user.tab();
64
+
65
+ expect(screen.queryByText(/invalid input/i)).not.toBeInTheDocument();
66
+ await user.clear(textbox);
67
+
68
+ // // Invalid input: "abc" (contains lowercase letters)
69
+ await user.type(textbox, 'abc');
70
+ await user.tab();
71
+ expect(screen.getByText(/invalid input/i)).toBeInTheDocument();
72
+ });
73
+
74
+ it('renders the input field as required when required prop is true', () => {
75
+ render(
76
+ <Formik initialValues={{}} onSubmit={() => {}}>
77
+ <Form>
78
+ <TextPersonAttributeField id="attributeId" personAttributeType={mockPersonAttributeType} required />
79
+ </Form>
80
+ </Formik>,
81
+ );
82
+ const textbox = screen.getByRole('textbox', { name: /referred by/i });
83
+
84
+ // Required attribute should be truthy on the input element
85
+ expect(textbox).toBeInTheDocument();
86
+ expect(textbox).toBeRequired();
87
+ });
88
+ });
@@ -1,5 +1,5 @@
1
1
  import { FormManager } from './form-manager';
2
- import { FormValues } from './patient-registration-types';
2
+ import { FormValues } from './patient-registration.types';
3
3
 
4
4
  jest.mock('./patient-registration.resource');
5
5
 
@@ -10,7 +10,7 @@ import {
10
10
  PatientRegistration,
11
11
  RelationshipValue,
12
12
  Encounter,
13
- } from './patient-registration-types';
13
+ } from './patient-registration.types';
14
14
  import {
15
15
  addPatientIdentifier,
16
16
  deletePatientIdentifier,
@@ -4,36 +4,6 @@ import userEvent from '@testing-library/user-event';
4
4
  import { Formik, Form } from 'formik';
5
5
  import { Input } from './input.component';
6
6
 
7
- describe.skip('number input', () => {
8
- const setupInput = async () => {
9
- render(
10
- <Formik initialValues={{ number: 0 }} onSubmit={null}>
11
- <Form>
12
- <Input id="number" type="number" labelText="Number" name="number" />
13
- </Form>
14
- </Formik>,
15
- );
16
- return screen.getByLabelText('Number (optional)') as HTMLInputElement;
17
- };
18
-
19
- it('exists', async () => {
20
- const input = await setupInput();
21
- expect(input.type).toEqual('number');
22
- });
23
-
24
- it('can input data', async () => {
25
- const user = userEvent.setup();
26
-
27
- const input = await setupInput();
28
- const expected = 1;
29
-
30
- await user.type(input, expected.toString());
31
- await user.tab();
32
-
33
- expect(input.valueAsNumber).toEqual(expected);
34
- });
35
- });
36
-
37
7
  describe('text input', () => {
38
8
  const setupInput = async () => {
39
9
  render(
@@ -100,108 +70,3 @@ describe('text input', () => {
100
70
  expect(screen.getByLabelText('Text (optional)')).toBeInTheDocument();
101
71
  });
102
72
  });
103
-
104
- describe.skip('telephone number input', () => {
105
- const setupInput = async () => {
106
- render(
107
- <Formik initialValues={{ telephoneNumber: '' }} onSubmit={null}>
108
- <Form>
109
- <Input id="tel" labelText="Telephone Number" name="telephoneNumber" placeholder="Enter telephone number" />
110
- </Form>
111
- </Formik>,
112
- );
113
- return screen.getByLabelText('telephoneNumber') as HTMLInputElement;
114
- };
115
-
116
- it('exists', async () => {
117
- const input = await setupInput();
118
- expect(input.type).toEqual('tel');
119
- });
120
-
121
- it('can input data', async () => {
122
- const user = userEvent.setup();
123
-
124
- const input = await setupInput();
125
- const expected = '0800001066';
126
-
127
- await user.type(input, expected);
128
- await user.tab();
129
-
130
- expect(input.value).toEqual(expected);
131
- });
132
- });
133
-
134
- describe.skip('date input', () => {
135
- const setupInput = async () => {
136
- render(
137
- <Formik initialValues={{ date: '' }} onSubmit={null}>
138
- <Form>
139
- <Input id="date" labelText="date" name="date" />
140
- </Form>
141
- </Formik>,
142
- );
143
- return screen.getByLabelText('date') as HTMLInputElement;
144
- };
145
-
146
- it('exists', async () => {
147
- const input = await setupInput();
148
- expect(input.type).toEqual('date');
149
- });
150
-
151
- it('can input data', async () => {
152
- const user = userEvent.setup();
153
-
154
- const input = await setupInput();
155
- const expected = '1990-09-10';
156
-
157
- await user.type(input, expected);
158
- await user.tab();
159
-
160
- expect(input.value).toEqual(expected);
161
- });
162
- });
163
-
164
- describe.skip('checkbox input', () => {
165
- const setupInput = async () => {
166
- render(
167
- <Formik initialValues={{ checkbox: false }} onSubmit={null}>
168
- <Form>
169
- <Input id="checkbox" labelText="checkbox" name="checkbox" />
170
- </Form>
171
- </Formik>,
172
- );
173
- return screen.getByLabelText('checkbox') as HTMLInputElement;
174
- };
175
-
176
- it('exists', async () => {
177
- const input = await setupInput();
178
- expect(input.type).toEqual('checkbox');
179
- });
180
-
181
- it('can input data', async () => {
182
- const user = userEvent.setup();
183
- const input = await setupInput();
184
-
185
- const expected = true;
186
-
187
- await user.click(input);
188
- await user.tab();
189
-
190
- expect(input.checked).toEqual(expected);
191
- });
192
-
193
- it('can update data', async () => {
194
- const user = userEvent.setup();
195
- const input = await setupInput();
196
-
197
- const expected = false;
198
-
199
- await user.click(input);
200
- await user.tab();
201
-
202
- await user.click(input);
203
- await user.tab();
204
-
205
- expect(input.checked).toEqual(expected);
206
- });
207
- });
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { render, fireEvent, waitFor, screen } from '@testing-library/react';
2
+ import { render, waitFor, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
3
4
  import { Formik, Form } from 'formik';
4
5
  import { SelectInput } from './select-input.component';
5
6
 
@@ -21,16 +22,16 @@ describe('the select input', () => {
21
22
  });
22
23
 
23
24
  it('can input data', async () => {
25
+ const user = userEvent.setup();
24
26
  const input = await setupSelect();
25
27
  const expected = 'A Option';
26
28
 
27
- fireEvent.change(input, { target: { value: expected } });
28
- fireEvent.blur(input);
29
+ await user.selectOptions(input, expected);
29
30
 
30
31
  await waitFor(() => expect(input.value).toEqual(expected));
31
32
  });
32
33
 
33
- it('should show optional label if the input is not required', () => {
34
+ it('should show optional label if the input is not required', async () => {
34
35
  render(
35
36
  <Formik initialValues={{ select: '' }} onSubmit={null}>
36
37
  <Form>
@@ -38,6 +39,9 @@ describe('the select input', () => {
38
39
  </Form>
39
40
  </Formik>,
40
41
  );
42
+
43
+ await waitFor(() => expect(screen.findByRole('combobox')));
44
+
41
45
  const selectInput = screen.getByRole('combobox', { name: 'Select (optional)' }) as HTMLSelectElement;
42
46
  expect(selectInput.labels).toHaveLength(1);
43
47
  expect(selectInput.labels[0]).toHaveTextContent('Select (optional)');
@@ -94,20 +94,22 @@ const ComboInput: React.FC<ComboInputProps> = ({ entries, fieldProps, handleInpu
94
94
  </Layer>
95
95
  <div className={styles.comboInputEntries}>
96
96
  {showEntries && (
97
- <div id="downshift-1-menu" style={{ height: filteredEntries.length > 5 ? "15rem" : "" }} className="cds--list-box__menu" role="listbox">
97
+ <div id="downshift-1-menu" className="cds--list-box__menu" role="listbox">
98
98
  {filteredEntries.map((entry, indx) => (
99
99
  <div
100
100
  key={indx}
101
101
  id="downshift-1-item-0"
102
102
  role="option"
103
- className={`cds--list-box__menu-item ${indx === highlightedEntry && 'cds--list-box__menu-item--highlighted'
104
- }`}
103
+ className={`cds--list-box__menu-item ${
104
+ indx === highlightedEntry && 'cds--list-box__menu-item--highlighted'
105
+ }`}
105
106
  tabIndex={-1}
106
107
  aria-selected="true"
107
108
  onClick={() => handleOptionClick(entry)}>
108
109
  <div
109
- className={`cds--list-box__menu-item__option ${styles.comboInputItemOption} ${entry === value && 'cds--list-box__menu-item--active'
110
- }`}>
110
+ className={`cds--list-box__menu-item__option ${styles.comboInputItemOption} ${
111
+ entry === value && 'cds--list-box__menu-item--active'
112
+ }`}>
111
113
  {entry}
112
114
  {entry === value && <SelectionTick />}
113
115
  </div>
@@ -116,7 +118,7 @@ const ComboInput: React.FC<ComboInputProps> = ({ entries, fieldProps, handleInpu
116
118
  </div>
117
119
  )}
118
120
  </div>
119
- </div >
121
+ </div>
120
122
  );
121
123
  };
122
124
 
@@ -7,7 +7,7 @@ import { ResourcesContext } from '../../../../offline.resources';
7
7
  import { showModal, useConfig, UserHasAccess } from '@openmrs/esm-framework';
8
8
  import { shouldBlockPatientIdentifierInOfflineMode } from './utils';
9
9
  import { deleteIdentifierType, setIdentifierSource } from '../../../field/id/id-field.component';
10
- import { PatientIdentifierValue } from '../../../patient-registration-types';
10
+ import { PatientIdentifierValue } from '../../../patient-registration.types';
11
11
  import { PatientRegistrationContext } from '../../../patient-registration-context';
12
12
  import { Input } from '../../basic-input/input/input.component';
13
13
  import styles from '../../input.scss';
@@ -0,0 +1,81 @@
1
+ import { isUniqueIdentifierTypeForOffline, shouldBlockPatientIdentifierInOfflineMode } from './utils';
2
+
3
+ interface IdentifierTypeOptions {
4
+ uniquenessBehavior?: 'UNIQUE' | 'LOCATION' | 'NON_UNIQUE';
5
+ manualEntryEnabled?: boolean;
6
+ automaticGenerationEnabled?: boolean;
7
+ }
8
+
9
+ function createIdentifierType(options: IdentifierTypeOptions) {
10
+ return {
11
+ uniquenessBehavior: options.uniquenessBehavior,
12
+ identifierSources: [
13
+ {
14
+ uuid: 'identifier-source-uuid',
15
+ name: 'Identifier Source Name',
16
+ autoGenerationOption: {
17
+ manualEntryEnabled: options.manualEntryEnabled,
18
+ automaticGenerationEnabled: options.automaticGenerationEnabled,
19
+ },
20
+ },
21
+ ],
22
+ name: 'Identifier Type Name',
23
+ required: true,
24
+ uuid: 'identifier-type-uuid',
25
+ fieldName: 'identifierFieldName',
26
+ format: 'identifierFormat',
27
+ isPrimary: true,
28
+ };
29
+ }
30
+
31
+ describe('shouldBlockPatientIdentifierInOfflineMode function', () => {
32
+ it('should return false if identifierType is not unique', () => {
33
+ const identifierType = createIdentifierType({ uniquenessBehavior: null });
34
+
35
+ const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
36
+
37
+ expect(result).toBe(false);
38
+ });
39
+
40
+ it('should return false if identifierType is unique and no manual entry is enabled', () => {
41
+ const identifierType = createIdentifierType({ uniquenessBehavior: null });
42
+
43
+ const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
44
+
45
+ expect(result).toBe(false);
46
+ });
47
+
48
+ it('should return true if identifierType is unique and manual entry is enabled', () => {
49
+ const identifierType = createIdentifierType({ manualEntryEnabled: true, uniquenessBehavior: 'UNIQUE' });
50
+
51
+ const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
52
+
53
+ expect(result).toBe(true);
54
+ });
55
+ });
56
+
57
+ describe('isUniqueIdentifierTypeForOffline function', () => {
58
+ it('should return true if uniquenessBehavior is UNIQUE', () => {
59
+ const identifierType = createIdentifierType({ uniquenessBehavior: 'UNIQUE' });
60
+
61
+ const result = isUniqueIdentifierTypeForOffline(identifierType);
62
+
63
+ expect(result).toBe(true);
64
+ });
65
+
66
+ it('should return true if uniquenessBehavior is LOCATION', () => {
67
+ const identifierType = createIdentifierType({ uniquenessBehavior: 'LOCATION' });
68
+
69
+ const result = isUniqueIdentifierTypeForOffline(identifierType);
70
+
71
+ expect(result).toBe(true);
72
+ });
73
+
74
+ it('should return false for other uniqueness behaviors', () => {
75
+ const identifierType = createIdentifierType({ uniquenessBehavior: null });
76
+
77
+ const result = isUniqueIdentifierTypeForOffline(identifierType);
78
+
79
+ expect(result).toBe(false);
80
+ });
81
+ });
@@ -1,4 +1,4 @@
1
- import { FetchedPatientIdentifierType, PatientIdentifierType } from '../../../patient-registration-types';
1
+ import { FetchedPatientIdentifierType, PatientIdentifierType } from '../../../patient-registration.types';
2
2
 
3
3
  export function shouldBlockPatientIdentifierInOfflineMode(identifierType: PatientIdentifierType) {
4
4
  // Patient Identifiers which are unique and can be manually entered are prohibited while offline because
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { v4 } from 'uuid';
3
- import { FormValues } from '../../patient-registration-types';
3
+ import { FormValues } from '../../patient-registration.types';
4
4
  import styles from './../input.scss';
5
5
 
6
6
  interface DummyDataInputProps {
@@ -1,7 +1,7 @@
1
1
  import { useConfig } from '@openmrs/esm-framework';
2
2
  import { createContext, SetStateAction } from 'react';
3
3
  import { RegistrationConfig } from '../config-schema';
4
- import { FormValues, CapturePhotoProps } from './patient-registration-types';
4
+ import { FormValues, CapturePhotoProps } from './patient-registration.types';
5
5
 
6
6
  export interface PatientRegistrationContextProps {
7
7
  identifierTypes: Array<any>;
@@ -16,7 +16,7 @@ import {
16
16
  ObsResponse,
17
17
  ConceptAnswers,
18
18
  Encounter,
19
- } from './patient-registration-types';
19
+ } from './patient-registration.types';
20
20
  import {
21
21
  getAddressFieldValuesFromFhirPatient,
22
22
  getFormValuesFromFhirPatient,
@@ -6,7 +6,7 @@ import {
6
6
  PatientUuidMapType,
7
7
  PatientIdentifierValue,
8
8
  Encounter,
9
- } from './patient-registration-types';
9
+ } from './patient-registration.types';
10
10
  import { parseDate } from '@openmrs/esm-framework';
11
11
  import camelCase from 'lodash-es/camelCase';
12
12
  import capitalize from 'lodash-es/capitalize';