@kenyaemr/esm-patient-registration-app 8.1.1-pre.118 → 8.1.1-pre.121

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 (29) hide show
  1. package/.turbo/turbo-build.log +13 -13
  2. package/dist/10.js +1 -0
  3. package/dist/10.js.map +1 -0
  4. package/dist/130.js +1 -1
  5. package/dist/130.js.map +1 -1
  6. package/dist/574.js +1 -1
  7. package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
  8. package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +37 -37
  9. package/dist/kenyaemr-esm-patient-registration-app.js.map +1 -1
  10. package/dist/main.js +1 -1
  11. package/dist/main.js.map +1 -1
  12. package/dist/routes.json +1 -1
  13. package/package.json +1 -1
  14. package/src/client-registry/hie-client-registry/hie-resource.ts +25 -23
  15. package/src/config-schema.ts +7 -0
  16. package/src/patient-registration/field/field.scss +17 -0
  17. package/src/patient-registration/field/id/id-field.component.tsx +8 -6
  18. package/src/patient-registration/field/id/id-field.test.tsx +27 -8
  19. package/src/patient-registration/field/person-attributes/location-person-attribute-field.component.tsx +105 -0
  20. package/src/patient-registration/field/person-attributes/location-person-attribute-field.resource.tsx +48 -0
  21. package/src/patient-registration/field/person-attributes/person-attribute-field.component.tsx +12 -1
  22. package/src/patient-registration/form-manager.test.ts +18 -0
  23. package/src/patient-registration/form-manager.ts +10 -5
  24. package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +17 -9
  25. package/src/patient-registration/input/custom-input/identifier/identifier-input.test.tsx +106 -58
  26. package/src/patient-registration/input/input.scss +5 -0
  27. package/translations/en.json +2 -0
  28. package/dist/471.js +0 -1
  29. package/dist/471.js.map +0 -1
@@ -2,25 +2,22 @@
2
2
  import React from 'react';
3
3
  import { render, screen } from '@testing-library/react';
4
4
  import { Form, Formik } from 'formik';
5
+ import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
6
+ import { esmPatientRegistrationSchema, type RegistrationConfig } from '../../../../config-schema';
5
7
  import { ResourcesContext, type Resources } from '../../../../offline.resources';
6
8
  import {
7
9
  PatientRegistrationContext,
8
10
  type PatientRegistrationContextProps,
9
11
  } from '../../../patient-registration-context';
10
- import type { AddressTemplate, FormValues, PatientIdentifierValue } from '../../../patient-registration.types';
12
+ import type {
13
+ AddressTemplate,
14
+ FormValues,
15
+ IdentifierSource,
16
+ PatientIdentifierValue,
17
+ } from '../../../patient-registration.types';
11
18
  import IdentifierInput from './identifier-input.component';
12
19
  import userEvent from '@testing-library/user-event';
13
20
 
14
- const predefinedAddressTemplate = {
15
- uuid: 'test-address-template-uuid',
16
- property: 'layout.address.format',
17
- description: 'Test Address Template',
18
- display:
19
- 'Layout - Address Format = <org.openmrs.layout.address.AddressTemplate>\n <nameMappings class="properties">\n <property name="postalCode" value="Location.postalCode"/>\n <property name="address2" value="Location.address2"/>\n <property name="address1" value="Location.address1"/>\n <property name="country" value="Location.country"/>\n <property name="stateProvince" value="Location.stateProvince"/>\n <property name="cityVillage" value="Location.cityVillage"/>\n </nameMappings>\n <sizeMappings class="properties">\n <property name="postalCode" value="10"/>\n <property name="address2" value="40"/>\n <property name="address1" value="40"/>\n <property name="country" value="10"/>\n <property name="stateProvince" value="10"/>\n <property name="cityVillage" value="10"/>\n </sizeMappings>\n <lineByLineFormat>\n <string>address1</string>\n <string>address2</string>\n <string>cityVillage stateProvince country postalCode</string>\n </lineByLineFormat>\n </org.openmrs.layout.address.AddressTemplate>',
20
- value:
21
- '<org.openmrs.layout.address.AddressTemplate>\r\n <nameMappings class="properties">\r\n <property name="postalCode" value="Location.postalCode"/>\r\n <property name="address2" value="Location.address2"/>\r\n <property name="address1" value="Location.address1"/>\r\n <property name="country" value="Location.country"/>\r\n <property name="stateProvince" value="Location.stateProvince"/>\r\n <property name="cityVillage" value="Location.cityVillage"/>\r\n </nameMappings>\r\n <sizeMappings class="properties">\r\n <property name="postalCode" value="4"/>\r\n <property name="address1" value="40"/>\r\n <property name="address2" value="40"/>\r\n <property name="country" value="10"/>\r\n <property name="stateProvince" value="10"/>\r\n <property name="cityVillage" value="10"/>\r\n <asset name="cityVillage" value="10"/>\r\n </sizeMappings>\r\n <lineByLineFormat>\r\n <string>address1 address2</string>\r\n <string>cityVillage stateProvince postalCode</string>\r\n <string>country</string>\r\n </lineByLineFormat>\r\n <elementDefaults class="properties">\r\n <property name="country" value=""/>\r\n </elementDefaults>\r\n <elementRegex class="properties">\r\n <property name="address1" value="[a-zA-Z]+$"/>\r\n </elementRegex>\r\n <elementRegexFormats class="properties">\r\n <property name="address1" value="Countries can only be letters"/>\r\n </elementRegexFormats>\r\n </org.openmrs.layout.address.AddressTemplate>',
22
- };
23
-
24
21
  const mockIdentifierTypes = [
25
22
  {
26
23
  fieldName: 'openMrsId',
@@ -44,7 +41,7 @@ const mockIdentifierTypes = [
44
41
  ];
45
42
 
46
43
  const mockResourcesContextValue: Resources = {
47
- addressTemplate: predefinedAddressTemplate as unknown as AddressTemplate,
44
+ addressTemplate: {} as AddressTemplate,
48
45
  currentSession: {
49
46
  authenticated: true,
50
47
  sessionId: 'JSESSION',
@@ -68,30 +65,35 @@ const mockContextValues: PatientRegistrationContextProps = {
68
65
  values: {} as FormValues,
69
66
  };
70
67
 
68
+ const mockUseConfig = jest.mocked(useConfig<RegistrationConfig>);
69
+
71
70
  describe('identifier input', () => {
71
+ mockUseConfig.mockReturnValue({
72
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
73
+ });
74
+
72
75
  const fieldName = 'openMrsId';
73
76
  const openmrsID = {
74
77
  identifierTypeUuid: '05a29f94-c0ed-11e2-94be-8c13b969e334',
75
78
  initialValue: '',
76
- identifierValue: '',
77
79
  identifierName: 'OpenMRS ID',
78
80
  selectedSource: {
79
81
  uuid: '01af8526-cea4-4175-aa90-340acb411771',
80
82
  name: 'Generator 2 for OpenMRS ID',
81
83
  autoGenerationOption: {
82
- manualEntryEnabled: true,
84
+ manualEntryEnabled: false,
83
85
  automaticGenerationEnabled: true,
84
86
  },
85
- },
87
+ } as IdentifierSource,
86
88
  autoGeneration: false,
87
89
  preferred: true,
88
90
  required: true,
89
- };
91
+ } as PatientIdentifierValue;
90
92
 
91
- const setupIdentifierInput = async (patientIdentifier: PatientIdentifierValue) => {
93
+ const setupIdentifierInput = (patientIdentifier: PatientIdentifierValue, initialValues = {}) => {
92
94
  render(
93
95
  <ResourcesContext.Provider value={mockResourcesContextValue}>
94
- <Formik initialValues={{}} onSubmit={jest.fn()}>
96
+ <Formik initialValues={initialValues} onSubmit={jest.fn()}>
95
97
  <Form>
96
98
  <PatientRegistrationContext.Provider value={mockContextValues}>
97
99
  <IdentifierInput patientIdentifier={patientIdentifier} fieldName={fieldName} />
@@ -100,56 +102,102 @@ describe('identifier input', () => {
100
102
  </Formik>
101
103
  </ResourcesContext.Provider>,
102
104
  );
103
-
104
- let identifierLabel: HTMLParagraphElement;
105
- let identifierInput: HTMLInputElement;
106
- if (patientIdentifier.autoGeneration) {
107
- identifierLabel = screen.getByTestId('identifier-label');
108
- identifierInput = screen.getByTestId('identifier-input');
109
- } else {
110
- identifierLabel = screen.getByText(patientIdentifier.identifierName);
111
- identifierInput = screen.getByLabelText(patientIdentifier.identifierName);
112
- }
113
- return {
114
- identifierLabel,
115
- identifierInput,
116
- };
117
105
  };
118
106
 
119
- it('shows the identifier input', async () => {
120
- const { identifierInput } = await setupIdentifierInput(openmrsID);
121
- expect(identifierInput).toBeInTheDocument();
107
+ it('shows the identifier input', () => {
108
+ openmrsID.autoGeneration = false;
109
+ setupIdentifierInput(openmrsID as PatientIdentifierValue);
110
+ expect(screen.getByLabelText(openmrsID.identifierName)).toBeInTheDocument();
122
111
  });
123
112
 
124
- describe('Auto-generated identifier', () => {
125
- openmrsID.autoGeneration = true;
113
+ it('displays an edit button when there is an initial value', async () => {
114
+ // setup
115
+ openmrsID.autoGeneration = false;
116
+ openmrsID.required = false;
117
+ openmrsID.initialValue = '1002UU9';
118
+ openmrsID.identifierValue = '1002UU9';
119
+ // replay
120
+ setupIdentifierInput(openmrsID as PatientIdentifierValue);
121
+ expect(screen.getByText('Edit')).toBeInTheDocument();
122
+ });
126
123
 
127
- it('hides the input when the identifier is auto-generated', async () => {
128
- const { identifierInput } = await setupIdentifierInput(openmrsID);
129
- expect(identifierInput.type).toBe('hidden');
130
- });
124
+ it('hides the edit button when the identifier is required', async () => {
125
+ // setup
126
+ openmrsID.autoGeneration = false;
127
+ openmrsID.required = true;
128
+ openmrsID.initialValue = '1002UU9';
129
+ openmrsID.identifierValue = '1002UU9';
130
+ // replay
131
+ setupIdentifierInput(openmrsID);
132
+ expect(screen.queryByText('Edit')).not.toBeInTheDocument();
133
+ });
134
+
135
+ it('displays a delete button when the identifier is not a default type', () => {
136
+ // setup
137
+ openmrsID.required = false;
138
+ // replay
139
+ setupIdentifierInput(openmrsID);
140
+ expect(screen.getByText('Delete')).toBeInTheDocument();
141
+ });
131
142
 
132
- it("displays 'Auto-Generated' when the indentifier has auto generation", async () => {
133
- const { identifierLabel, identifierInput } = await setupIdentifierInput(openmrsID);
134
- expect(identifierLabel.innerHTML).toBe('Auto-generated');
135
- expect(identifierInput.disabled).toBe(true);
143
+ describe('auto-generated identifier', () => {
144
+ it('hides the input when the identifier is auto-generated', () => {
145
+ openmrsID.autoGeneration = true;
146
+ setupIdentifierInput(openmrsID);
147
+ expect(screen.getByTestId('identifier-input')).toHaveAttribute('type', 'hidden');
136
148
  });
137
149
 
138
- it('displays an edit button when there is an initial value', async () => {
139
- // setup
140
- openmrsID.required = false;
141
- openmrsID.initialValue = '1002UU9';
142
- // replay
143
- await setupIdentifierInput(openmrsID);
144
- expect(screen.getByText('Edit')).toBeInTheDocument();
150
+ it("displays 'Auto-Generated' when the indentifier has auto generation", () => {
151
+ openmrsID.autoGeneration = true;
152
+ setupIdentifierInput(openmrsID);
153
+ expect(screen.getByTestId('identifier-placeholder').innerHTML).toBe('Auto-generated');
154
+ expect(screen.getByTestId('identifier-input')).toBeDisabled();
145
155
  });
146
156
 
147
- it('displays a delete button when the identifier is not a default type', async () => {
148
- // setup
149
- openmrsID.required = false;
150
- // replay
151
- await setupIdentifierInput(openmrsID);
152
- expect(screen.getByText('Delete')).toBeInTheDocument();
157
+ describe('manual entry allowed', () => {
158
+ openmrsID.selectedSource = {
159
+ autoGenerationOption: {
160
+ manualEntryEnabled: true,
161
+ },
162
+ } as IdentifierSource;
163
+
164
+ it('shows the edit button', () => {
165
+ openmrsID.autoGeneration = true;
166
+ setupIdentifierInput(openmrsID);
167
+ expect(screen.getByText('Edit')).toBeInTheDocument();
168
+ });
169
+
170
+ describe('edit button clicked', () => {
171
+ it('displays an empty input field', async () => {
172
+ const user = userEvent.setup();
173
+ openmrsID.autoGeneration = true;
174
+ openmrsID.required = false;
175
+ openmrsID.selectedSource = {
176
+ autoGenerationOption: {
177
+ manualEntryEnabled: true,
178
+ },
179
+ } as IdentifierSource;
180
+ setupIdentifierInput(openmrsID);
181
+ const editButton = screen.getByTestId('edit-button');
182
+ await user.click(editButton);
183
+ expect(screen.getByLabelText(new RegExp(`${openmrsID.identifierName}`))).toHaveValue('');
184
+ });
185
+
186
+ it('displays an input field with the identifier value if it exists', async () => {
187
+ const user = userEvent.setup();
188
+ openmrsID.autoGeneration = true;
189
+ openmrsID.required = false;
190
+ openmrsID.selectedSource = {
191
+ autoGenerationOption: {
192
+ manualEntryEnabled: true,
193
+ },
194
+ } as IdentifierSource;
195
+ setupIdentifierInput(openmrsID, { identifiers: { [fieldName]: { identifierValue: '10001V' } } });
196
+ const editButton = screen.getByTestId('edit-button');
197
+ await user.click(editButton);
198
+ expect(screen.getByLabelText(new RegExp(`${openmrsID.identifierName}`))).toHaveValue('10001V');
199
+ });
200
+ });
153
201
  });
154
202
  });
155
203
  });
@@ -116,3 +116,8 @@
116
116
  margin: 0;
117
117
  padding-left: layout.$spacing-05;
118
118
  }
119
+
120
+ .actionButtonContainer {
121
+ margin-left: layout.$spacing-05;
122
+ margin-bottom: layout.$spacing-05;
123
+ }
@@ -95,6 +95,7 @@
95
95
  "nupi": "NUPI",
96
96
  "obsFieldUnknownDatatype": "Concept for obs field '{{fieldDefinitionId}}' has unknown datatype '{{datatypeName}}'",
97
97
  "optional": "optional",
98
+ "optionalIdentifierLabel": "{{identifierName}} (optional)",
98
99
  "other": "Other",
99
100
  "patientDetailsFound": "Patient information found in the registry, do you want to use the information to continue with registration?",
100
101
  "patientName": "Patient name",
@@ -123,6 +124,7 @@
123
124
  "searchClientRegistry": "Search client registry",
124
125
  "searchIdentifierPlaceholder": "Search identifier",
125
126
  "searchingRegistry": "Searching registry...",
127
+ "searchLocationPersonAttribute": "Search location",
126
128
  "searchRegistry": "Search registry",
127
129
  "selectAnOption": "Select an option",
128
130
  "selectCountry": "Select country",