@kenyaemr/esm-patient-registration-app 5.2.1 → 5.2.3

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 (111) hide show
  1. package/dist/102.js +1 -0
  2. package/dist/102.js.map +1 -0
  3. package/dist/130.js +1 -1
  4. package/dist/130.js.map +1 -1
  5. package/dist/271.js +1 -0
  6. package/dist/319.js +1 -1
  7. package/dist/431.js +2 -0
  8. package/dist/431.js.map +1 -0
  9. package/dist/460.js +1 -1
  10. package/dist/537.js +1 -1
  11. package/dist/537.js.map +1 -1
  12. package/dist/574.js +1 -1
  13. package/dist/644.js +1 -0
  14. package/dist/757.js +1 -1
  15. package/dist/784.js +1 -1
  16. package/dist/788.js +1 -1
  17. package/dist/807.js +1 -1
  18. package/dist/833.js +1 -1
  19. package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
  20. package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +91 -47
  21. package/dist/kenyaemr-esm-patient-registration-app.js.map +1 -1
  22. package/dist/main.js +1 -1
  23. package/dist/main.js.map +1 -1
  24. package/dist/routes.json +1 -1
  25. package/dist.tar.gz +0 -0
  26. package/package.json +3 -2
  27. package/src/add-patient-link.test.tsx +9 -7
  28. package/src/config-schema.ts +31 -38
  29. package/src/constants.ts +1 -1
  30. package/src/offline.resources.ts +1 -1
  31. package/src/offline.ts +2 -2
  32. package/src/patient-registration/before-save-prompt.tsx +2 -1
  33. package/src/patient-registration/field/__mocks__/field.resource.ts +1 -1
  34. package/src/patient-registration/field/address/address-field.component.tsx +5 -4
  35. package/src/patient-registration/field/address/address-hierarchy.resource.tsx +2 -2
  36. package/src/patient-registration/field/address/address-search.component.tsx +1 -14
  37. package/src/patient-registration/field/address/custom-address-field.component.tsx +1 -1
  38. package/src/patient-registration/field/address/tests/address-hierarchy.test.tsx +3 -3
  39. package/src/patient-registration/field/address/tests/address-search-component.test.tsx +14 -7
  40. package/src/patient-registration/field/custom-field.component.tsx +1 -1
  41. package/src/patient-registration/field/dob/dob.component.tsx +2 -2
  42. package/src/patient-registration/field/dob/dob.test.tsx +0 -3
  43. package/src/patient-registration/field/field.component.tsx +4 -1
  44. package/src/patient-registration/field/field.resource.ts +2 -2
  45. package/src/patient-registration/field/field.test.tsx +98 -95
  46. package/src/patient-registration/field/gender/gender-field.component.tsx +4 -4
  47. package/src/patient-registration/field/gender/gender-field.test.tsx +7 -14
  48. package/src/patient-registration/field/id/id-field.component.tsx +6 -6
  49. package/src/patient-registration/field/id/id-field.test.tsx +9 -7
  50. package/src/patient-registration/field/id/identifier-selection-overlay.component.tsx +1 -1
  51. package/src/patient-registration/field/name/name-field.component.tsx +1 -1
  52. package/src/patient-registration/field/obs/obs-field.component.tsx +35 -33
  53. package/src/patient-registration/field/obs/obs-field.test.tsx +106 -28
  54. package/src/patient-registration/field/person-attributes/coded-attributes.component.tsx +1 -1
  55. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +67 -24
  56. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +54 -30
  57. package/src/patient-registration/field/person-attributes/person-attribute-field.component.tsx +4 -3
  58. package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +1 -1
  59. package/src/patient-registration/field/person-attributes/{person-attributes.resource.tsx → person-attributes.resource.ts} +2 -2
  60. package/src/patient-registration/field/person-attributes/text-person-attribute-field.component.tsx +1 -1
  61. package/src/patient-registration/field/phone/phone-field.component.tsx +16 -0
  62. package/src/patient-registration/form-manager.test.ts +1 -1
  63. package/src/patient-registration/form-manager.ts +14 -22
  64. package/src/patient-registration/input/basic-input/select/select-input.test.tsx +3 -3
  65. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.component.tsx +5 -5
  66. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.test.tsx +70 -58
  67. package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +1 -1
  68. package/src/patient-registration/input/custom-input/identifier/identifier-input.test.tsx +2 -5
  69. package/src/patient-registration/input/custom-input/identifier/utils.ts +1 -1
  70. package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +1 -1
  71. package/src/patient-registration/input/dummy-data/dummy-data-input.test.tsx +6 -6
  72. package/src/patient-registration/patient-registration-context.ts +3 -4
  73. package/src/patient-registration/patient-registration-hooks.ts +12 -12
  74. package/src/patient-registration/patient-registration-utils.ts +7 -7
  75. package/src/patient-registration/patient-registration.component.tsx +7 -7
  76. package/src/patient-registration/{patient-registration.resource.tsx → patient-registration.resource.ts} +1 -1
  77. package/src/patient-registration/patient-registration.test.tsx +270 -251
  78. package/src/patient-registration/{patient-registration.types.tsx → patient-registration.types.ts} +11 -3
  79. package/src/patient-registration/section/death-info/death-info-section.test.tsx +33 -45
  80. package/src/patient-registration/section/demographics/demographics-section.test.tsx +1 -2
  81. package/src/patient-registration/section/generic-section.component.tsx +1 -1
  82. package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +3 -3
  83. package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +17 -5
  84. package/src/patient-registration/section/patient-relationships/relationships.resource.tsx +3 -3
  85. package/src/patient-registration/section/section-wrapper.component.tsx +1 -1
  86. package/src/patient-registration/section/section.component.tsx +1 -1
  87. package/src/patient-registration/validation/patient-registration-validation.test.tsx +140 -126
  88. package/src/patient-registration/validation/patient-registration-validation.tsx +54 -46
  89. package/src/widgets/cancel-patient-edit.test.tsx +7 -4
  90. package/src/widgets/delete-identifier-confirmation-modal.test.tsx +7 -4
  91. package/src/widgets/display-photo.test.tsx +1 -1
  92. package/src/widgets/edit-patient-details-button.test.tsx +12 -7
  93. package/translations/am.json +4 -2
  94. package/translations/ar.json +4 -2
  95. package/translations/en.json +4 -2
  96. package/translations/es.json +4 -2
  97. package/translations/fr.json +4 -2
  98. package/translations/he.json +4 -2
  99. package/translations/km.json +4 -2
  100. package/translations/zh.json +89 -0
  101. package/translations/zh_CN.json +89 -0
  102. package/tsconfig.json +1 -1
  103. package/__mocks__/autogenerationoptions.mock.ts +0 -34
  104. package/dist/388.js +0 -2
  105. package/dist/388.js.map +0 -1
  106. package/dist/598.js +0 -1
  107. package/dist/598.js.map +0 -1
  108. package/src/patient-registration/field/__mocks__/identifier-types.mock.ts +0 -76
  109. package/src/patient-registration/field/__mocks__/identifiers.mock.ts +0 -27
  110. package/src/patient-registration/field/address/tests/mocks.ts +0 -98
  111. /package/dist/{388.js.LICENSE.txt → 431.js.LICENSE.txt} +0 -0
@@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react';
3
3
  import { Formik, Form } from 'formik';
4
4
  import { initialFormValues } from '../../patient-registration.component';
5
5
  import { DeathInfoSection } from './death-info-section.component';
6
- import { FormValues } from '../../patient-registration-types';
6
+ import { type FormValues } from '../../patient-registration.types';
7
7
  import { PatientRegistrationContext } from '../../patient-registration-context';
8
8
 
9
9
  jest.mock('@openmrs/esm-framework', () => {
@@ -15,62 +15,50 @@ jest.mock('@openmrs/esm-framework', () => {
15
15
  };
16
16
  });
17
17
 
18
- // TODO: Implement feature and get tests to pass
19
- describe('death info section', () => {
20
- const formValues: FormValues = initialFormValues;
18
+ const initialContextValues = {
19
+ currentPhoto: 'data:image/png;base64,1234567890',
20
+ identifierTypes: [],
21
+ inEditMode: false,
22
+ initialFormValues: {} as FormValues,
23
+ isOffline: false,
24
+ setCapturePhotoProps: jest.fn(),
25
+ setFieldValue: jest.fn(),
26
+ setInitialFormValues: jest.fn(),
27
+ validationSchema: null,
28
+ values: {
29
+ isDead: true,
30
+ } as FormValues,
31
+ };
21
32
 
22
- const setupSection = async (isDead?: boolean) => {
23
- render(
24
- <PatientRegistrationContext.Provider value={{ values: { isDead: isDead || false } }}>
25
- <Formik initialValues={{ ...initialFormValues, isDead }} onSubmit={null}>
33
+ describe('Death info section', () => {
34
+ const renderDeathInfoSection = (isDead) => {
35
+ initialContextValues.values.isDead = isDead;
36
+
37
+ return render(
38
+ <PatientRegistrationContext.Provider value={initialContextValues}>
39
+ <Formik initialValues={initialFormValues} onSubmit={jest.fn()}>
26
40
  <Form>
27
41
  <DeathInfoSection />
28
42
  </Form>
29
43
  </Formik>
30
44
  </PatientRegistrationContext.Provider>,
31
45
  );
32
- const allInputs = screen.queryAllByLabelText(
33
- (content, element) => element.tagName.toLowerCase() === 'input',
34
- ) as Array<HTMLInputElement>;
35
- const allSelects = screen.queryAllByRole('combobox') as Array<HTMLInputElement>;
36
- let inputAndSelectNames = [];
37
- allInputs.forEach((input) => inputAndSelectNames.push(input.name));
38
- allSelects.forEach((select) => inputAndSelectNames.push(select.name));
39
- return inputAndSelectNames;
40
46
  };
41
47
 
42
- it('has the correct number of inputs if is dead is checked', async () => {
43
- const inputAndSelectNames = await setupSection(true);
44
- expect(inputAndSelectNames.length).toBe(3);
45
- });
46
-
47
- it('has the correct number of inputs if is dead is not checked', async () => {
48
- const inputAndSelectNames = await setupSection(false);
49
- expect(inputAndSelectNames.length).toBe(1);
50
- });
48
+ it('shows fields for recording death info when the patient is marked as dead', () => {
49
+ renderDeathInfoSection(true);
51
50
 
52
- it('has isDead checkbox', async () => {
53
- const inputAndSelectNames = await setupSection();
54
- expect(inputAndSelectNames).toContain('isDead');
51
+ expect(screen.getByRole('region', { name: /death info section/i })).toBeInTheDocument();
52
+ expect(screen.getByRole('heading', { name: /death info/i })).toBeInTheDocument();
53
+ expect(screen.getByRole('textbox', { name: /is dead \(optional\)/i })).toBeInTheDocument();
54
+ expect(screen.getByRole('textbox', { name: /date of death \(optional\)/i })).toBeInTheDocument();
55
+ expect(screen.getByRole('combobox', { name: /cause of death \(optional\)/i })).toBeInTheDocument();
55
56
  });
56
57
 
57
- it('has death date if is dead is checked', async () => {
58
- const inputAndSelectNames = await setupSection(true);
59
- expect(inputAndSelectNames).toContain('deathDate');
60
- });
61
-
62
- it('has no death date if is dead is not checked', async () => {
63
- const inputAndSelectNames = await setupSection(false);
64
- expect(inputAndSelectNames).not.toContain('deathDate');
65
- });
66
-
67
- it('has death cause if is dead is checked', async () => {
68
- const inputAndSelectNames = await setupSection(true);
69
- expect(inputAndSelectNames).toContain('deathCause');
70
- });
58
+ it('has the correct number of inputs if is dead is not checked', async () => {
59
+ renderDeathInfoSection(false);
71
60
 
72
- it('has no death cause if is dead is not checked', async () => {
73
- const inputAndSelectNames = await setupSection(false);
74
- expect(inputAndSelectNames).not.toContain('deathCause');
61
+ expect(screen.queryByRole('textbox', { name: /date of death \(optional\)/i })).not.toBeInTheDocument();
62
+ expect(screen.queryByRole('combobox', { name: /cause of death \(optional\)/i })).not.toBeInTheDocument();
75
63
  });
76
64
  });
@@ -4,7 +4,7 @@ import { Formik, Form } from 'formik';
4
4
  import { initialFormValues } from '../../patient-registration.component';
5
5
  import { DemographicsSection } from './demographics-section.component';
6
6
  import { PatientRegistrationContext } from '../../patient-registration-context';
7
- import { FormValues } from '../../patient-registration.types';
7
+ import { type FormValues } from '../../patient-registration.types';
8
8
 
9
9
  jest.mock('@openmrs/esm-framework', () => {
10
10
  const originalModule = jest.requireActual('@openmrs/esm-framework');
@@ -60,7 +60,6 @@ describe('demographics section', () => {
60
60
  initialFormValues: null,
61
61
  identifierTypes: [],
62
62
  validationSchema: {},
63
- setValidationSchema: () => {},
64
63
  values: { ...initialFormValues, birthdateEstimated, addNameInLocalLanguage },
65
64
  inEditMode: false,
66
65
  setFieldValue: () => {},
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { SectionDefinition } from '../../config-schema';
2
+ import { type SectionDefinition } from '../../config-schema';
3
3
  import { Field } from '../field/field.component';
4
4
 
5
5
  export interface GenericSectionProps {
@@ -15,7 +15,7 @@ import { Autosuggest } from '../../input/custom-input/autosuggest/autosuggest.co
15
15
  import { PatientRegistrationContext } from '../../patient-registration-context';
16
16
  import { ResourcesContext } from '../../../offline.resources';
17
17
  import { fetchPerson } from '../../patient-registration.resource';
18
- import { RelationshipValue } from '../../patient-registration.types';
18
+ import { type RelationshipValue } from '../../patient-registration.types';
19
19
  import sectionStyles from '../section.scss';
20
20
  import styles from './relationships.scss';
21
21
 
@@ -168,12 +168,12 @@ export const RelationshipsSection = () => {
168
168
  const tmp: RelationshipType[] = [];
169
169
  relationshipTypes.results.forEach((type) => {
170
170
  const aIsToB = {
171
- display: type.displayAIsToB ? type.displayAIsToB : type.aIsToB,
171
+ display: type.displayAIsToB ? type.displayAIsToB : type.displayBIsToA,
172
172
  uuid: type.uuid,
173
173
  direction: 'aIsToB',
174
174
  };
175
175
  const bIsToA = {
176
- display: type.displayBIsToA ? type.displayBIsToA : type.bIsToA,
176
+ display: type.displayBIsToA ? type.displayBIsToA : type.displayAIsToB,
177
177
  uuid: type.uuid,
178
178
  direction: 'bIsToA',
179
179
  };
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { Form, Formik } from 'formik';
3
3
  import { render, screen } from '@testing-library/react';
4
4
  import { PatientRegistrationContext } from '../../patient-registration-context';
5
- import { Resources, ResourcesContext } from '../../../offline.resources';
5
+ import { type Resources, ResourcesContext } from '../../../offline.resources';
6
6
  import { RelationshipsSection } from './relationships-section.component';
7
7
 
8
8
  jest.mock('../../patient-registration.resource', () => ({
@@ -17,7 +17,7 @@ jest.mock('../../patient-registration.resource', () => ({
17
17
  }));
18
18
 
19
19
  let mockResourcesContextValue = {
20
- addressTemplate: [],
20
+ addressTemplate: null,
21
21
  currentSession: {
22
22
  authenticated: true,
23
23
  sessionId: 'JSESSION',
@@ -40,15 +40,27 @@ describe('RelationshipsSection', () => {
40
40
  );
41
41
 
42
42
  expect(screen.getByLabelText(/loading relationships section/i)).toBeInTheDocument();
43
- expect(screen.getByRole(/progressbar/i)).toBeInTheDocument();
43
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
44
44
  expect(screen.queryByText(/add relationship/i)).not.toBeInTheDocument();
45
45
  });
46
46
 
47
47
  it('renders relationships when relationshipTypes are available', () => {
48
48
  const relationshipTypes = {
49
49
  results: [
50
- { aIsToB: 'Mother', bIsToA: 'Child', uuid: '42ae5ce0-d64b-11ea-9064-5adc43bbdd34' },
51
- { aIsToB: 'Father', bIsToA: 'Child', uuid: '52ae5ce0-d64b-11ea-9064-5adc43bbdd24' },
50
+ {
51
+ displayAIsToB: 'Mother',
52
+ aIsToB: 'Mother',
53
+ bIsToA: 'Child',
54
+ displayBIsToA: 'Child',
55
+ uuid: '42ae5ce0-d64b-11ea-9064-5adc43bbdd34',
56
+ },
57
+ {
58
+ displayAIsToB: 'Father',
59
+ aIsToB: 'Father',
60
+ bIsToA: 'Child',
61
+ displayBIsToA: 'Child',
62
+ uuid: '52ae5ce0-d64b-11ea-9064-5adc43bbdd24',
63
+ },
52
64
  ],
53
65
  };
54
66
  mockResourcesContextValue = {
@@ -1,7 +1,7 @@
1
- import { FetchResponse, openmrsFetch } from '@openmrs/esm-framework';
2
- import { RelationshipValue } from '../../patient-registration.types';
3
- import useSWR from 'swr';
4
1
  import { useMemo } from 'react';
2
+ import useSWR from 'swr';
3
+ import { type FetchResponse, openmrsFetch } from '@openmrs/esm-framework';
4
+ import { type RelationshipValue } from '../../patient-registration.types';
5
5
  import { personRelationshipRepresentation } from '../../../constants';
6
6
 
7
7
  export function useInitialPatientRelationships(patientUuid: string): {
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import styles from '../patient-registration.scss';
3
3
  import { Tile } from '@carbon/react';
4
4
  import { useTranslation } from 'react-i18next';
5
- import { SectionDefinition } from '../../config-schema';
5
+ import { type SectionDefinition } from '../../config-schema';
6
6
  import { Section } from './section.component';
7
7
 
8
8
  export interface SectionWrapperProps {
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { SectionDefinition } from '../../config-schema';
2
+ import { type SectionDefinition } from '../../config-schema';
3
3
  import { GenericSection } from './generic-section.component';
4
4
  import { DeathInfoSection } from './death-info/death-info-section.component';
5
5
  import { DemographicsSection } from './demographics/demographics-section.component';
@@ -1,143 +1,157 @@
1
- import { validationSchema } from './patient-registration-validation';
2
-
1
+ import { defineConfigSchema, getConfig } from '@openmrs/esm-framework';
2
+ import { getValidationSchema } from './patient-registration-validation';
3
+ import { type RegistrationConfig, esmPatientRegistrationSchema } from '../../config-schema';
3
4
  describe('Patient Registration Validation', () => {
4
- describe('validationSchema', () => {
5
- const validFormValues = {
6
- givenName: 'John',
7
- familyName: 'Doe',
8
- additionalGivenName: '',
9
- additionalFamilyName: '',
10
- gender: 'Male',
11
- birthdate: new Date('1990-01-01'),
12
- birthdateEstimated: false,
13
- deathDate: null,
14
- email: 'john.doe@example.com',
15
- identifiers: {
16
- nationalId: {
17
- required: true,
18
- identifierValue: '123456789',
19
- },
20
- passportId: {
21
- required: false,
22
- identifierValue: '',
23
- },
5
+ beforeAll(() => {
6
+ defineConfigSchema('@openmrs/esm-patient-registration-app', esmPatientRegistrationSchema);
7
+ });
8
+
9
+ const validFormValues = {
10
+ givenName: 'John',
11
+ familyName: 'Doe',
12
+ additionalGivenName: '',
13
+ additionalFamilyName: '',
14
+ gender: 'male',
15
+ birthdate: new Date('1990-01-01'),
16
+ birthdateEstimated: false,
17
+ deathDate: null,
18
+ email: 'john.doe@example.com',
19
+ identifiers: {
20
+ nationalId: {
21
+ required: true,
22
+ identifierValue: '123456789',
24
23
  },
25
- };
24
+ passportId: {
25
+ required: false,
26
+ identifierValue: '',
27
+ },
28
+ },
29
+ };
26
30
 
27
- const validateFormValues = async (formValues) => {
28
- try {
29
- await validationSchema.validate(formValues, { abortEarly: false });
30
- } catch (err) {
31
- return err;
32
- }
33
- };
31
+ const validateFormValues = async (formValues) => {
32
+ const config = (await getConfig('@openmrs/esm-patient-registration-app')) as any as RegistrationConfig;
33
+ const validationSchema = getValidationSchema(config);
34
+ try {
35
+ await validationSchema.validate(formValues, { abortEarly: false });
36
+ } catch (err) {
37
+ return err;
38
+ }
39
+ };
34
40
 
35
- it('should allow valid form values', async () => {
36
- const validationError = await validateFormValues(validFormValues);
37
- expect(validationError).toBeFalsy();
38
- });
41
+ it('should allow valid form values', async () => {
42
+ const validationError = await validateFormValues(validFormValues);
43
+ expect(validationError).toBeFalsy();
44
+ });
39
45
 
40
- it('should require givenName', async () => {
41
- const invalidFormValues = {
42
- ...validFormValues,
43
- givenName: '',
44
- };
45
- const validationError = await validateFormValues(invalidFormValues);
46
- expect(validationError.errors).toContain('givenNameRequired');
47
- });
46
+ it('should require givenName', async () => {
47
+ const invalidFormValues = {
48
+ ...validFormValues,
49
+ givenName: '',
50
+ };
51
+ const validationError = await validateFormValues(invalidFormValues);
52
+ expect(validationError.errors).toContain('givenNameRequired');
53
+ });
48
54
 
49
- it('should require familyName', async () => {
50
- const invalidFormValues = {
51
- ...validFormValues,
52
- familyName: '',
53
- };
54
- const validationError = await validateFormValues(invalidFormValues);
55
- expect(validationError.errors).toContain('familyNameRequired');
56
- });
55
+ it('should require familyName', async () => {
56
+ const invalidFormValues = {
57
+ ...validFormValues,
58
+ familyName: '',
59
+ };
60
+ const validationError = await validateFormValues(invalidFormValues);
61
+ expect(validationError.errors).toContain('familyNameRequired');
62
+ });
57
63
 
58
- it('should require additionalGivenName when addNameInLocalLanguage is true', async () => {
59
- const invalidFormValues = {
60
- ...validFormValues,
61
- addNameInLocalLanguage: true,
62
- additionalGivenName: '',
63
- };
64
- const validationError = await validateFormValues(invalidFormValues);
65
- expect(validationError.errors).toContain('givenNameRequired');
66
- });
64
+ it('should require additionalGivenName when addNameInLocalLanguage is true', async () => {
65
+ const invalidFormValues = {
66
+ ...validFormValues,
67
+ addNameInLocalLanguage: true,
68
+ additionalGivenName: '',
69
+ };
70
+ const validationError = await validateFormValues(invalidFormValues);
71
+ expect(validationError.errors).toContain('givenNameRequired');
72
+ });
67
73
 
68
- it('should require additionalFamilyName when addNameInLocalLanguage is true', async () => {
69
- const invalidFormValues = {
70
- ...validFormValues,
71
- addNameInLocalLanguage: true,
72
- additionalFamilyName: '',
73
- };
74
- const validationError = await validateFormValues(invalidFormValues);
75
- expect(validationError.errors).toContain('familyNameRequired');
76
- });
74
+ it('should require additionalFamilyName when addNameInLocalLanguage is true', async () => {
75
+ const invalidFormValues = {
76
+ ...validFormValues,
77
+ addNameInLocalLanguage: true,
78
+ additionalFamilyName: '',
79
+ };
80
+ const validationError = await validateFormValues(invalidFormValues);
81
+ expect(validationError.errors).toContain('familyNameRequired');
82
+ });
77
83
 
78
- it('should require gender', async () => {
79
- const invalidFormValues = {
80
- ...validFormValues,
81
- gender: '',
82
- };
83
- const validationError = await validateFormValues(invalidFormValues);
84
- expect(validationError.errors).toContain('genderUnspecified');
85
- });
84
+ it('should require gender', async () => {
85
+ const invalidFormValues = {
86
+ ...validFormValues,
87
+ gender: '',
88
+ };
89
+ const validationError = await validateFormValues(invalidFormValues);
90
+ expect(validationError.errors).toContain('genderUnspecified');
91
+ });
86
92
 
87
- it('should allow Male as a valid gender', async () => {
88
- const validFormValuesWithOtherGender = {
89
- ...validFormValues,
90
- gender: 'Male',
91
- };
92
- const validationError = await validateFormValues(validFormValuesWithOtherGender);
93
- expect(validationError).toBeFalsy();
94
- });
93
+ it('should allow female as a valid gender', async () => {
94
+ const validFormValuesWithOtherGender = {
95
+ ...validFormValues,
96
+ gender: 'female',
97
+ };
98
+ const validationError = await validateFormValues(validFormValuesWithOtherGender);
99
+ expect(validationError).toBeFalsy();
100
+ });
95
101
 
96
- it('should allow Female as a valid gender', async () => {
97
- const validFormValuesWithOtherGender = {
98
- ...validFormValues,
99
- gender: 'Female',
100
- };
101
- const validationError = await validateFormValues(validFormValuesWithOtherGender);
102
- expect(validationError).toBeFalsy();
103
- });
102
+ it('should allow other as a valid gender', async () => {
103
+ const validFormValuesWithOtherGender = {
104
+ ...validFormValues,
105
+ gender: 'other',
106
+ };
107
+ const validationError = await validateFormValues(validFormValuesWithOtherGender);
108
+ expect(validationError).toBeFalsy();
109
+ });
104
110
 
105
- it('should throw error when date of birth is a future date', async () => {
106
- const invalidFormValues = {
107
- ...validFormValues,
108
- birthdate: new Date('2100-01-01'),
109
- };
110
- const validationError = await validateFormValues(invalidFormValues);
111
- expect(validationError.errors).toContain('birthdayNotInTheFuture');
112
- });
111
+ it('should allow unknown as a valid gender', async () => {
112
+ const validFormValuesWithOtherGender = {
113
+ ...validFormValues,
114
+ gender: 'unknown',
115
+ };
116
+ const validationError = await validateFormValues(validFormValuesWithOtherGender);
117
+ expect(validationError).toBeFalsy();
118
+ });
113
119
 
114
- it('should require yearsEstimated when birthdateEstimated is true', async () => {
115
- const invalidFormValues = {
116
- ...validFormValues,
117
- birthdateEstimated: true,
118
- };
119
- const validationError = await validateFormValues(invalidFormValues);
120
- expect(validationError.errors).toContain('yearsEstimateRequired');
121
- });
120
+ it('should throw error when date of birth is a future date', async () => {
121
+ const invalidFormValues = {
122
+ ...validFormValues,
123
+ birthdate: new Date('2100-01-01'),
124
+ };
125
+ const validationError = await validateFormValues(invalidFormValues);
126
+ expect(validationError.errors).toContain('birthdayNotInTheFuture');
127
+ });
128
+
129
+ it('should require yearsEstimated when birthdateEstimated is true', async () => {
130
+ const invalidFormValues = {
131
+ ...validFormValues,
132
+ birthdateEstimated: true,
133
+ };
134
+ const validationError = await validateFormValues(invalidFormValues);
135
+ expect(validationError.errors).toContain('yearsEstimateRequired');
136
+ });
122
137
 
123
- it('should throw error when monthEstimated is negative', async () => {
124
- const invalidFormValues = {
125
- ...validFormValues,
126
- birthdateEstimated: true,
127
- yearsEstimated: 0,
128
- monthsEstimated: -1,
129
- };
130
- const validationError = await validateFormValues(invalidFormValues);
131
- expect(validationError.errors).toContain('negativeMonths');
132
- });
138
+ it('should throw error when monthEstimated is negative', async () => {
139
+ const invalidFormValues = {
140
+ ...validFormValues,
141
+ birthdateEstimated: true,
142
+ yearsEstimated: 0,
143
+ monthsEstimated: -1,
144
+ };
145
+ const validationError = await validateFormValues(invalidFormValues);
146
+ expect(validationError.errors).toContain('negativeMonths');
147
+ });
133
148
 
134
- it('should throw error when deathDate is in future', async () => {
135
- const invalidFormValues = {
136
- ...validFormValues,
137
- deathDate: new Date('2100-01-01'),
138
- };
139
- const validationError = await validateFormValues(invalidFormValues);
140
- expect(validationError.errors).toContain('deathdayNotInTheFuture');
141
- });
149
+ it('should throw error when deathDate is in future', async () => {
150
+ const invalidFormValues = {
151
+ ...validFormValues,
152
+ deathDate: new Date('2100-01-01'),
153
+ };
154
+ const validationError = await validateFormValues(invalidFormValues);
155
+ expect(validationError.errors).toContain('deathdayNotInTheFuture');
142
156
  });
143
157
  });
@@ -1,52 +1,60 @@
1
1
  import * as Yup from 'yup';
2
2
  import mapValues from 'lodash/mapValues';
3
- import { FormValues } from '../patient-registration.types';
3
+ import { type FormValues } from '../patient-registration.types';
4
+ import { type RegistrationConfig } from '../../config-schema';
4
5
 
5
- export const validationSchema = Yup.object({
6
- givenName: Yup.string().required('givenNameRequired'),
7
- familyName: Yup.string().required('familyNameRequired'),
8
- additionalGivenName: Yup.string().when('addNameInLocalLanguage', {
9
- is: true,
10
- then: Yup.string().required('givenNameRequired'),
11
- otherwise: Yup.string().notRequired(),
12
- }),
13
- additionalFamilyName: Yup.string().when('addNameInLocalLanguage', {
14
- is: true,
15
- then: Yup.string().required('familyNameRequired'),
16
- otherwise: Yup.string().notRequired(),
17
- }),
18
- gender: Yup.string().oneOf(['Male', 'Female', 'Other', 'Unknown'], 'genderUnspecified').required('genderRequired'),
19
- birthdate: Yup.date().when('birthdateEstimated', {
20
- is: false,
21
- then: Yup.date().required('birthdayRequired').max(Date(), 'birthdayNotInTheFuture').nullable(),
22
- otherwise: Yup.date().nullable(),
23
- }),
24
- yearsEstimated: Yup.number().when('birthdateEstimated', {
25
- is: true,
26
- then: Yup.number().required('yearsEstimateRequired').min(0, 'negativeYears'),
27
- otherwise: Yup.number().nullable(),
28
- }),
29
- monthsEstimated: Yup.number().min(0, 'negativeMonths'),
30
- deathDate: Yup.date().max(Date(), 'deathdayNotInTheFuture').nullable(),
31
- email: Yup.string().optional().email('invalidEmail'),
32
- identifiers: Yup.lazy((obj: FormValues['identifiers']) =>
33
- Yup.object(
34
- mapValues(obj, () =>
35
- Yup.object({
36
- required: Yup.bool(),
37
- identifierValue: Yup.string().when('required', {
38
- is: true,
39
- then: Yup.string().required('identifierValueRequired'),
40
- otherwise: Yup.string().notRequired(),
6
+ export function getValidationSchema(config: RegistrationConfig) {
7
+ return Yup.object({
8
+ givenName: Yup.string().required('givenNameRequired'),
9
+ familyName: Yup.string().required('familyNameRequired'),
10
+ additionalGivenName: Yup.string().when('addNameInLocalLanguage', {
11
+ is: true,
12
+ then: Yup.string().required('givenNameRequired'),
13
+ otherwise: Yup.string().notRequired(),
14
+ }),
15
+ additionalFamilyName: Yup.string().when('addNameInLocalLanguage', {
16
+ is: true,
17
+ then: Yup.string().required('familyNameRequired'),
18
+ otherwise: Yup.string().notRequired(),
19
+ }),
20
+ gender: Yup.string()
21
+ .oneOf(
22
+ config.fieldConfigurations.gender.map((g) => g.value),
23
+ 'genderUnspecified',
24
+ )
25
+ .required('genderRequired'),
26
+ birthdate: Yup.date().when('birthdateEstimated', {
27
+ is: false,
28
+ then: Yup.date().required('birthdayRequired').max(Date(), 'birthdayNotInTheFuture').nullable(),
29
+ otherwise: Yup.date().nullable(),
30
+ }),
31
+ yearsEstimated: Yup.number().when('birthdateEstimated', {
32
+ is: true,
33
+ then: Yup.number().required('yearsEstimateRequired').min(0, 'negativeYears'),
34
+ otherwise: Yup.number().nullable(),
35
+ }),
36
+ monthsEstimated: Yup.number().min(0, 'negativeMonths'),
37
+ deathDate: Yup.date().max(Date(), 'deathdayNotInTheFuture').nullable(),
38
+ email: Yup.string().optional().email('invalidEmail'),
39
+ identifiers: Yup.lazy((obj: FormValues['identifiers']) =>
40
+ Yup.object(
41
+ mapValues(obj, () =>
42
+ Yup.object({
43
+ required: Yup.bool(),
44
+ identifierValue: Yup.string().when('required', {
45
+ is: true,
46
+ then: Yup.string().required('identifierValueRequired'),
47
+ otherwise: Yup.string().notRequired(),
48
+ }),
41
49
  }),
42
- }),
50
+ ),
43
51
  ),
44
52
  ),
45
- ),
46
- relationships: Yup.array().of(
47
- Yup.object().shape({
48
- relatedPersonUuid: Yup.string().required(),
49
- relationshipType: Yup.string().required(),
50
- }),
51
- ),
52
- });
53
+ relationships: Yup.array().of(
54
+ Yup.object().shape({
55
+ relatedPersonUuid: Yup.string().required(),
56
+ relationshipType: Yup.string().required(),
57
+ }),
58
+ ),
59
+ });
60
+ }