@kenyaemr/esm-patient-registration-app 4.3.0 → 4.4.0

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 (36) hide show
  1. package/dist/574.js +1 -1
  2. package/dist/68.js +1 -1
  3. package/dist/68.js.map +1 -1
  4. package/dist/822.js +1 -1
  5. package/dist/822.js.map +1 -1
  6. package/dist/main.js +1 -1
  7. package/dist/main.js.map +1 -1
  8. package/dist/openmrs-esm-patient-registration-app.js.buildmanifest.json +12 -12
  9. package/package.json +2 -2
  10. package/src/index.ts +0 -18
  11. package/src/offline.resources.ts +8 -1
  12. package/src/patient-registration/field/address/address-field.component.tsx +0 -1
  13. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +13 -11
  14. package/src/patient-registration/form-manager.ts +27 -10
  15. package/src/patient-registration/input/basic-input/input/input.test.tsx +47 -10
  16. package/src/patient-registration/input/basic-input/select/select-input.test.tsx +16 -3
  17. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.test.tsx +25 -14
  18. package/src/patient-registration/patient-registration-hooks.ts +21 -75
  19. package/src/patient-registration/patient-registration-types.tsx +2 -8
  20. package/src/patient-registration/patient-registration.component.tsx +3 -26
  21. package/src/patient-registration/section/section-wrapper.component.tsx +1 -1
  22. package/src/root.component.tsx +1 -5
  23. package/translations/en.json +0 -15
  24. package/src/patient-registration/input/custom-input/estimated-age/estimated-age-input.component.tsx +0 -32
  25. package/src/patient-registration/input/custom-input/estimated-age/estimated-age-input.test.tsx +0 -36
  26. package/src/patient-registration/input/custom-input/unidentified-patient/unidentified-patient-input.component.tsx +0 -24
  27. package/src/patient-registration/input/custom-input/unidentified-patient/unidentified-patient-input.test.tsx +0 -39
  28. package/src/patient-verification/assets/counties.json +0 -236
  29. package/src/patient-verification/assets/verification-assets.ts +0 -11
  30. package/src/patient-verification/patient-verification-hook.tsx +0 -156
  31. package/src/patient-verification/patient-verification-utils.ts +0 -173
  32. package/src/patient-verification/patient-verification.component.tsx +0 -118
  33. package/src/patient-verification/patient-verification.scss +0 -30
  34. package/src/patient-verification/verification-modal/confirm-prompt.component.tsx +0 -69
  35. package/src/patient-verification/verification-modal/empty-prompt.component.tsx +0 -35
  36. package/src/patient-verification/verification-types.ts +0 -50
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-patient-registration-app",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "Patient registration microfrontend for the OpenMRS SPA",
5
5
  "browser": "dist/openmrs-esm-patient-registration-app.js",
6
6
  "main": "src/index.ts",
@@ -12,7 +12,7 @@
12
12
  "serve": "webpack serve --mode=development",
13
13
  "debug": "npm run serve",
14
14
  "build": "webpack --mode production",
15
- "analyze": "webpack --mode=production --env analyze=true",
15
+ "analyze": "webpack --mode=production --env.analyze=true",
16
16
  "lint": "eslint src --ext ts,tsx",
17
17
  "typescript": "tsc",
18
18
  "extract-translations": "i18next 'src/**/*.component.tsx'"
package/src/index.ts CHANGED
@@ -106,24 +106,6 @@ function setupOpenMRS() {
106
106
  online: true,
107
107
  offline: true,
108
108
  },
109
- {
110
- id: 'empty-client-registry-modal',
111
- load: getAsyncLifecycle(
112
- () => import('./patient-verification/verification-modal/empty-prompt.component'),
113
- options,
114
- ),
115
- online: true,
116
- offline: true,
117
- },
118
- {
119
- id: 'confirm-client-registry-modal',
120
- load: getAsyncLifecycle(
121
- () => import('./patient-verification/verification-modal/confirm-prompt.component'),
122
- options,
123
- ),
124
- online: true,
125
- offline: true,
126
- },
127
109
  ],
128
110
  };
129
111
  }
@@ -64,7 +64,14 @@ async function fetchPatientIdentifierTypes(): Promise<Array<FetchedPatientIdenti
64
64
 
65
65
  const primaryIdentifierTypeUuid = primaryIdentifierTypeResponse?.data?.results?.[0]?.metadataUuid;
66
66
 
67
- let identifierTypes = [];
67
+ let identifierTypes = primaryIdentifierTypeResponse?.ok
68
+ ? [
69
+ mapPatientIdentifierType(
70
+ patientIdentifierTypes?.find((type) => type.uuid === primaryIdentifierTypeUuid),
71
+ true,
72
+ ),
73
+ ]
74
+ : [];
68
75
 
69
76
  patientIdentifierTypes.forEach((type) => {
70
77
  if (type.uuid !== primaryIdentifierTypeUuid) {
@@ -21,7 +21,6 @@ export const AddressField: React.FC<AddressFieldProps> = ({ fieldDefinition }) =
21
21
  id={fieldDefinition.id}
22
22
  labelText={t(`${fieldDefinition.label}`, `${fieldDefinition.label}`)}
23
23
  {...field}
24
- required={fieldDefinition.validation.required}
25
24
  />
26
25
  );
27
26
  }}
@@ -31,17 +31,19 @@ export function CodedPersonAttributeField({
31
31
  <Field name={fieldName}>
32
32
  {({ field, form: { touched, errors }, meta }) => {
33
33
  return (
34
- <Select
35
- id={id}
36
- name={`person-attribute-${personAttributeType.uuid}`}
37
- labelText={label ?? personAttributeType?.display}
38
- invalid={errors[fieldName] && touched[fieldName]}
39
- {...field}>
40
- <SelectItem value={null} text={t('selectAnOption', 'Select an option')} />
41
- {conceptAnswers.map((answer) => (
42
- <SelectItem key={answer.uuid} value={answer.uuid} text={answer.display} />
43
- ))}
44
- </Select>
34
+ <>
35
+ <Select
36
+ id={id}
37
+ name={`person-attribute-${personAttributeType.uuid}`}
38
+ labelText={label ?? personAttributeType?.display}
39
+ invalid={errors[fieldName] && touched[fieldName]}
40
+ {...field}>
41
+ <SelectItem value={''} text={t('selectAnOption', 'Select an option')} />
42
+ {conceptAnswers.map((answer) => (
43
+ <SelectItem key={answer.uuid} value={answer.uuid} text={answer.display} />
44
+ ))}
45
+ </Select>
46
+ </>
45
47
  );
46
48
  }}
47
49
  </Field>
@@ -1,4 +1,4 @@
1
- import { FetchResponse, queueSynchronizationItem, Session, toOmrsIsoString } from '@openmrs/esm-framework';
1
+ import { FetchResponse, openmrsFetch, queueSynchronizationItem, Session } from '@openmrs/esm-framework';
2
2
  import { patientRegistration } from '../constants';
3
3
  import {
4
4
  FormValues,
@@ -24,7 +24,6 @@ import {
24
24
  updatePatientIdentifier,
25
25
  saveEncounter,
26
26
  } from './patient-registration.resource';
27
- import isEqual from 'lodash-es/isEqual';
28
27
  import { RegistrationConfig } from '../config-schema';
29
28
 
30
29
  export type SavePatientForm = (
@@ -54,7 +53,7 @@ export class FormManager {
54
53
  ) => {
55
54
  const syncItem: PatientRegistration = {
56
55
  fhirPatient: FormManager.mapPatientToFhirPatient(
57
- FormManager.getPatientToCreate(values, patientUuidMap, initialAddressFieldValues, []),
56
+ FormManager.getPatientToCreate(isNewPatient, values, patientUuidMap, initialAddressFieldValues, []),
58
57
  ),
59
58
  _patientRegistrationData: {
60
59
  isNewPatient,
@@ -102,6 +101,7 @@ export class FormManager {
102
101
  );
103
102
 
104
103
  const createdPatient = FormManager.getPatientToCreate(
104
+ isNewPatient,
105
105
  values,
106
106
  patientUuidMap,
107
107
  initialAddressFieldValues,
@@ -180,7 +180,7 @@ export class FormManager {
180
180
  );
181
181
  } else {
182
182
  const encounterToSave: Encounter = {
183
- encounterDatetime: toOmrsIsoString(new Date()),
183
+ encounterDatetime: new Date(),
184
184
  patient: savePatientResponse.data.uuid,
185
185
  encounterType: config.registrationObs.encounterTypeUuid,
186
186
  location: currentLocation,
@@ -282,6 +282,7 @@ export class FormManager {
282
282
  }
283
283
 
284
284
  static getPatientToCreate(
285
+ isNewPatient: boolean,
285
286
  values: FormValues,
286
287
  patientUuidMap: PatientUuidMapType,
287
288
  initialAddressFieldValues: Record<string, any>,
@@ -304,7 +305,7 @@ export class FormManager {
304
305
  gender: values.gender.charAt(0),
305
306
  birthdate,
306
307
  birthdateEstimated: values.birthdateEstimated,
307
- attributes: FormManager.getPatientAttributes(values),
308
+ attributes: FormManager.getPatientAttributes(isNewPatient, values, patientUuidMap),
308
309
  addresses: [values.address],
309
310
  ...FormManager.getPatientDeathInfo(values),
310
311
  },
@@ -336,16 +337,32 @@ export class FormManager {
336
337
  return names;
337
338
  }
338
339
 
339
- static getPatientAttributes(values: FormValues) {
340
+ static getPatientAttributes(isNewPatient: boolean, values: FormValues, patientUuidMap: PatientUuidMapType) {
340
341
  const attributes: Array<AttributeValue> = [];
341
342
  if (values.attributes) {
342
- for (const [key, value] of Object.entries(values.attributes)) {
343
- attributes.push({
344
- attributeType: key,
345
- value,
343
+ Object.entries(values.attributes)
344
+ .filter(([, value]) => !!value)
345
+ .forEach(([key, value]) => {
346
+ attributes.push({
347
+ attributeType: key,
348
+ value,
349
+ });
346
350
  });
351
+
352
+ if (!isNewPatient && values.patientUuid) {
353
+ Object.entries(values.attributes)
354
+ .filter(([, value]) => !value)
355
+ .forEach(async ([key]) => {
356
+ const attributeUuid = patientUuidMap[`attribute.${key}`];
357
+ await openmrsFetch(`/ws/rest/v1/person/${values.patientUuid}/attribute/${attributeUuid}`, {
358
+ method: 'DELETE',
359
+ }).catch((err) => {
360
+ console.error(err);
361
+ });
362
+ });
347
363
  }
348
364
  }
365
+
349
366
  if (values.unidentifiedPatient) {
350
367
  attributes.push({
351
368
  // The UUID of the 'Unknown Patient' attribute-type will always be static across all implementations of OpenMRS
@@ -9,11 +9,11 @@ describe.skip('number input', () => {
9
9
  render(
10
10
  <Formik initialValues={{ number: 0 }} onSubmit={null}>
11
11
  <Form>
12
- <Input id="number" labelText="Number" name="number" />
12
+ <Input id="number" type="number" labelText="Number" name="number" />
13
13
  </Form>
14
14
  </Formik>,
15
15
  );
16
- return screen.getByLabelText('number') as HTMLInputElement;
16
+ return screen.getByLabelText('Number (optional)') as HTMLInputElement;
17
17
  };
18
18
 
19
19
  it('exists', async () => {
@@ -34,16 +34,27 @@ describe.skip('number input', () => {
34
34
  });
35
35
  });
36
36
 
37
- describe.skip('text input', () => {
37
+ describe('text input', () => {
38
38
  const setupInput = async () => {
39
39
  render(
40
- <Formik initialValues={{ text: '' }} onSubmit={null}>
40
+ <Formik initialValues={{ text: '' }} onSubmit={() => {}}>
41
41
  <Form>
42
- <Input id="text" labelText="Text" name="text" placeholder="Enter text" />
42
+ <Input
43
+ id="text"
44
+ labelText="Text"
45
+ name="text"
46
+ placeholder="Enter text"
47
+ required
48
+ checkWarning={(value) => {
49
+ if (value.length > 5) {
50
+ return 'name should be of 5 char';
51
+ }
52
+ }}
53
+ />
43
54
  </Form>
44
55
  </Formik>,
45
56
  );
46
- return screen.getByLabelText('text') as HTMLInputElement;
57
+ return screen.getByLabelText('Text') as HTMLInputElement;
47
58
  };
48
59
 
49
60
  it('exists', async () => {
@@ -51,16 +62,42 @@ describe.skip('text input', () => {
51
62
  expect(input.type).toEqual('text');
52
63
  });
53
64
 
54
- it('can input data', async () => {
65
+ it('can input valid data without warning', async () => {
55
66
  const user = userEvent.setup();
56
67
 
57
68
  const input = await setupInput();
58
- const expected = 'Some text';
69
+ const userInput = 'text';
59
70
 
60
- await user.type(input, expected);
71
+ await user.type(input, userInput);
61
72
  await user.tab();
62
73
 
63
- expect(input.value).toEqual(expected);
74
+ expect(input.value).toEqual(userInput);
75
+ expect(screen.queryByText('name should be of 5 char')).not.toBeInTheDocument();
76
+ });
77
+
78
+ it('should show a warning when the invalid input is entered', async () => {
79
+ const user = userEvent.setup();
80
+
81
+ const input = await setupInput();
82
+ const userInput = 'Hello World';
83
+
84
+ await userEvent.clear(input);
85
+
86
+ await user.type(input, userInput);
87
+ await user.tab();
88
+
89
+ expect(screen.getByText('name should be of 5 char')).toBeInTheDocument();
90
+ });
91
+
92
+ it('should show the correct label text if the field is not required', () => {
93
+ render(
94
+ <Formik initialValues={{ text: '' }} onSubmit={() => {}}>
95
+ <Form>
96
+ <Input id="text" labelText="Text" name="text" placeholder="Enter text" />
97
+ </Form>
98
+ </Formik>,
99
+ );
100
+ expect(screen.getByLabelText('Text (optional)')).toBeInTheDocument();
64
101
  });
65
102
  });
66
103
 
@@ -3,16 +3,16 @@ import { render, fireEvent, waitFor, screen } from '@testing-library/react';
3
3
  import { Formik, Form } from 'formik';
4
4
  import { SelectInput } from './select-input.component';
5
5
 
6
- describe.skip('select input', () => {
6
+ describe('the select input', () => {
7
7
  const setupSelect = async () => {
8
8
  render(
9
9
  <Formik initialValues={{ select: '' }} onSubmit={null}>
10
10
  <Form>
11
- <SelectInput label="Select" name="select" options={['A Option', 'B Option']} />
11
+ <SelectInput label="Select" name="select" options={['A Option', 'B Option']} required />
12
12
  </Form>
13
13
  </Formik>,
14
14
  );
15
- return screen.getByLabelText('select') as HTMLInputElement;
15
+ return screen.getByLabelText('Select') as HTMLInputElement;
16
16
  };
17
17
 
18
18
  it('exists', async () => {
@@ -29,4 +29,17 @@ describe.skip('select input', () => {
29
29
 
30
30
  await waitFor(() => expect(input.value).toEqual(expected));
31
31
  });
32
+
33
+ it('should show optional label if the input is not required', () => {
34
+ render(
35
+ <Formik initialValues={{ select: '' }} onSubmit={null}>
36
+ <Form>
37
+ <SelectInput label="Select" name="select" options={['A Option', 'B Option']} />
38
+ </Form>
39
+ </Formik>,
40
+ );
41
+ const selectInput = screen.getByRole('combobox', { name: 'Select (optional)' }) as HTMLSelectElement;
42
+ expect(selectInput.labels).toHaveLength(1);
43
+ expect(selectInput.labels[0]).toHaveTextContent('Select (optional)');
44
+ });
32
45
  });
@@ -55,7 +55,7 @@ describe('autosuggest', () => {
55
55
  expect(screen.queryByRole('list')).toBeNull();
56
56
  });
57
57
 
58
- it('shows search results in an ul', async () => {
58
+ it('should show the search results in a list', async () => {
59
59
  setup();
60
60
  const searchbox = screen.getByRole('searchbox');
61
61
  fireEvent.change(searchbox, { target: { value: 'john' } });
@@ -64,7 +64,7 @@ describe('autosuggest', () => {
64
64
  expect(list.children).toHaveLength(2);
65
65
  });
66
66
 
67
- it('creates li items whose inner text is gotten through getDisplayValue', async () => {
67
+ it('should creates the li items whose inner text is gotten through getDisplayValue', async () => {
68
68
  setup();
69
69
  const searchbox = screen.getByRole('searchbox');
70
70
  fireEvent.change(searchbox, { target: { value: 'john' } });
@@ -73,7 +73,7 @@ describe('autosuggest', () => {
73
73
  expect(list[1].textContent).toBe('John Smith');
74
74
  });
75
75
 
76
- xit('triggers onSuggestionSelected with correct values when li is clicked', async () => {
76
+ it('should trigger the onSuggestionSelected with correct values when li is clicked', async () => {
77
77
  setup();
78
78
  const searchbox = screen.getByRole('searchbox');
79
79
  fireEvent.change(searchbox, { target: { value: 'john' } });
@@ -82,28 +82,39 @@ describe('autosuggest', () => {
82
82
  expect(handleSuggestionSelected).toHaveBeenNthCalledWith(1, 'person', 'randomuuid1');
83
83
  });
84
84
 
85
- it.skip('sets search box value to selected suggestion', async () => {
85
+ it('should clear the suggestions when a suggestion is selected', async () => {
86
86
  setup();
87
- let searchbox = screen.getByRole('searchbox');
87
+ let list = screen.queryByRole('list');
88
+ expect(list).toBeNull();
89
+ const searchbox = screen.getByRole('searchbox');
88
90
  fireEvent.change(searchbox, { target: { value: 'john' } });
89
- const listitems = await waitFor(() => screen.getAllByRole('listitem'));
91
+ list = await waitFor(() => screen.getByRole('list'));
92
+ expect(list).toBeInTheDocument();
93
+ const listitems = screen.getAllByRole('listitem');
90
94
  fireEvent.click(listitems[0]);
91
- searchbox = screen.getByRole('searchbox');
92
- expect(searchbox.textContent).toBe('John Doe');
95
+ list = screen.queryByRole('list');
96
+ expect(list).toBeNull();
93
97
  });
94
98
 
95
- xit('clears suggestions when a suggestion is selected', async () => {
99
+ it('should change suggestions when a search input is changed', async () => {
96
100
  setup();
97
- // screen.getByRole('x');
98
101
  let list = screen.queryByRole('list');
99
102
  expect(list).toBeNull();
100
103
  const searchbox = screen.getByRole('searchbox');
101
104
  fireEvent.change(searchbox, { target: { value: 'john' } });
102
- list = await waitFor(() => screen.getByRole('list'));
103
- expect(list).toBeInTheDocument();
104
- const listitems = screen.getAllByRole('listitem');
105
- fireEvent.click(listitems[0]);
105
+ const suggestion = await screen.findByText('John Doe');
106
+ expect(suggestion).toBeInTheDocument();
107
+ fireEvent.change(searchbox, { target: { value: '' } });
106
108
  list = screen.queryByRole('list');
107
109
  expect(list).toBeNull();
108
110
  });
111
+
112
+ it('should hide suggestions when clicked outside of component', async () => {
113
+ setup();
114
+ const input = screen.getByRole('searchbox');
115
+ fireEvent.change(input, { target: { value: 'john' } });
116
+ await screen.findByText('John Doe');
117
+ fireEvent.mouseDown(document.body);
118
+ expect(screen.queryByText('John Doe')).not.toBeInTheDocument();
119
+ });
109
120
  });
@@ -1,20 +1,16 @@
1
1
  import { FetchResponse, getSynchronizationItems, openmrsFetch, useConfig, usePatient } from '@openmrs/esm-framework';
2
- import last from 'lodash-es/last';
3
2
  import camelCase from 'lodash-es/camelCase';
4
3
  import { Dispatch, useEffect, useMemo, useState } from 'react';
5
4
  import useSWR from 'swr';
6
5
  import { v4 } from 'uuid';
7
6
  import { RegistrationConfig } from '../config-schema';
8
7
  import { patientRegistration } from '../constants';
9
- import { useConceptAnswers, useGlobalProperties } from '../patient-verification/patient-verification-hook';
10
8
  import {
11
9
  FormValues,
12
10
  PatientRegistration,
13
11
  PatientUuidMapType,
14
12
  PersonAttributeResponse,
15
13
  PatientIdentifierResponse,
16
- ObsResponse,
17
- ConceptAnswers,
18
14
  Encounter,
19
15
  } from './patient-registration-types';
20
16
  import {
@@ -27,13 +23,12 @@ import {
27
23
  import { useInitialPatientRelationships } from './section/patient-relationships/relationships.resource';
28
24
 
29
25
  export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch<FormValues>] {
30
- const { martialStatus, education, occupation, educationLoad, loadingStatus } = useConcepts();
31
26
  const { isLoading: isLoadingPatientToEdit, patient: patientToEdit } = usePatient(patientUuid);
32
27
  const { data: attributes, isLoading: isLoadingAttributes } = useInitialPersonAttributes(patientUuid);
33
28
  const { data: identifiers, isLoading: isLoadingIdentifiers } = useInitialPatientIdentifiers(patientUuid);
34
29
  const { data: relationships, isLoading: isLoadingRelationships } = useInitialPatientRelationships(patientUuid);
35
- const { data: obs, isLoading: isLoadingObs, obs: observations } = usePatientObs(patientUuid);
36
- const { data: token, isLoading: isLoadingToken } = useGlobalProperties();
30
+ const { data: encounters } = useInitialEncounters(patientUuid, patientToEdit);
31
+
37
32
  const [initialFormValues, setInitialFormValues] = useState<FormValues>({
38
33
  patientUuid: v4(),
39
34
  givenName: '',
@@ -82,14 +77,6 @@ export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch
82
77
  })();
83
78
  }, [isLoadingPatientToEdit, patientToEdit, patientUuid]);
84
79
 
85
- // Setting authentication token
86
-
87
- useEffect(() => {
88
- if (!isLoadingToken && token) {
89
- setInitialFormValues((initialFormValues) => ({ ...initialFormValues, token: String(token.access_token) }));
90
- }
91
- }, [isLoadingToken, token]);
92
-
93
80
  // Set initial patient relationships
94
81
  useEffect(() => {
95
82
  if (!isLoadingRelationships && relationships) {
@@ -127,24 +114,15 @@ export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch
127
114
  }
128
115
  }, [attributes, setInitialFormValues, isLoadingAttributes]);
129
116
 
130
- // Set initial patient obs
131
-
117
+ // Set Initial registration encounters
132
118
  useEffect(() => {
133
- if (!isLoadingObs) {
134
- setInitialFormValues((initialFormValues) => ({ ...initialFormValues, obs: obs, observation: observations }));
135
- }
136
- }, [isLoadingObs]);
137
-
138
- // Set Initial encounter
139
-
140
- useEffect(() => {
141
- if (!educationLoad || !loadingStatus) {
119
+ if (patientToEdit && encounters) {
142
120
  setInitialFormValues((initialFormValues) => ({
143
121
  ...initialFormValues,
144
- concepts: [...occupation, ...martialStatus, ...education],
122
+ obs: encounters as Record<string, string>,
145
123
  }));
146
124
  }
147
- }, [educationLoad, loadingStatus]);
125
+ }, [encounters, patientToEdit]);
148
126
 
149
127
  return [initialFormValues, setInitialFormValues];
150
128
  }
@@ -175,6 +153,7 @@ export function usePatientUuidMap(
175
153
  fallback: PatientUuidMapType = {},
176
154
  ): [PatientUuidMapType, Dispatch<PatientUuidMapType>] {
177
155
  const { isLoading: isLoadingPatientToEdit, patient: patientToEdit } = usePatient(patientUuid);
156
+ const { data: attributes } = useInitialPersonAttributes(patientUuid);
178
157
  const [patientUuidMap, setPatientUuidMap] = useState(fallback);
179
158
 
180
159
  useEffect(() => {
@@ -187,6 +166,15 @@ export function usePatientUuidMap(
187
166
  }
188
167
  }, [isLoadingPatientToEdit, patientToEdit, patientUuid]);
189
168
 
169
+ useEffect(() => {
170
+ if (attributes) {
171
+ setPatientUuidMap((prevPatientUuidMap) => ({
172
+ ...prevPatientUuidMap,
173
+ ...getPatientAttributeUuidMapForPatient(attributes),
174
+ }));
175
+ }
176
+ }, [attributes]);
177
+
190
178
  return [patientUuidMap, setPatientUuidMap];
191
179
  }
192
180
 
@@ -269,52 +257,10 @@ function useInitialPersonAttributes(personUuid: string) {
269
257
  return result;
270
258
  }
271
259
 
272
- export function usePatientObs(patientUuid: string) {
273
- const {
274
- registrationObs: { encounterTypeUuid },
275
- } = useConfig() as RegistrationConfig;
276
- const url = `/ws/rest/v1/encounter?patient=${patientUuid}&encounterType=${encounterTypeUuid}&v=custom:(obs:(uuid,display,concept:(uuid,display),value:(uuid,display)))`;
277
- const { data, isLoading, error } = useSWR<{ data: ObsResponse }>(patientUuid ? url : null, openmrsFetch);
278
- let obsObject = {};
279
- const patientObs = last(data?.data?.results)?.obs?.forEach((ob) => {
280
- Object.assign(obsObject, { [ob.concept.uuid]: ob.value.uuid });
260
+ function getPatientAttributeUuidMapForPatient(attributes: Array<PersonAttributeResponse>) {
261
+ const attributeUuidMap = {};
262
+ attributes.forEach((attribute) => {
263
+ attributeUuidMap[`attribute.${attribute?.attributeType?.uuid}`] = attribute?.uuid;
281
264
  });
282
- return { data: obsObject, isLoading, error, obs: data?.data };
283
- }
284
-
285
- function useConcepts() {
286
- const { data: martialStatus, isLoading: loadingStatus } = useConceptAnswers('1054AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
287
- const { data: education, isLoading: educationLoad } = useConceptAnswers('1712AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
288
- const occupation: Array<ConceptAnswers> = [
289
- {
290
- uuid: '1538AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
291
- display: 'Farmer',
292
- },
293
- {
294
- uuid: '1540AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
295
- display: 'Employee',
296
- },
297
- {
298
- uuid: '1539AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
299
- display: 'Trader',
300
- },
301
- {
302
- uuid: '159465AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
303
- display: 'Student',
304
- },
305
- {
306
- uuid: '159466AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
307
- display: 'Driver',
308
- },
309
- {
310
- uuid: '1107AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
311
- display: 'None',
312
- },
313
- {
314
- uuid: '5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
315
- display: 'Other',
316
- },
317
- ];
318
-
319
- return { martialStatus, education, occupation, loadingStatus, educationLoad };
265
+ return attributeUuidMap;
320
266
  }
@@ -1,4 +1,4 @@
1
- import { OpenmrsResource, Session } from '@openmrs/esm-framework';
1
+ import { Session } from '@openmrs/esm-framework';
2
2
  import { RegistrationConfig } from '../config-schema';
3
3
  import { SavePatientTransactionManager } from './form-manager';
4
4
 
@@ -118,7 +118,7 @@ export type Patient = {
118
118
  };
119
119
 
120
120
  export interface Encounter {
121
- encounterDatetime: Date | string;
121
+ encounterDatetime: Date;
122
122
  patient: string;
123
123
  encounterType: string;
124
124
  location: string;
@@ -185,9 +185,6 @@ export interface FormValues {
185
185
  address: {
186
186
  [addressField: string]: string;
187
187
  };
188
- observation?: ObsResponse;
189
- concepts?: Array<ConceptAnswers>;
190
- token?: string;
191
188
  }
192
189
 
193
190
  export interface PatientUuidMapType {
@@ -266,6 +263,3 @@ export interface ConceptAnswers {
266
263
  display: string;
267
264
  uuid: string;
268
265
  }
269
- export interface ObsResponse {
270
- results: Array<{ obs: Array<{ uuid: string; display: string; value: OpenmrsResource; concept: OpenmrsResource }> }>;
271
- }
@@ -1,6 +1,6 @@
1
1
  import React, { useState, useEffect, useContext, useMemo, useRef } from 'react';
2
2
  import { Button, Link } from '@carbon/react';
3
- import { XAxis, ShareKnowledge } from '@carbon/react/icons';
3
+ import { XAxis } from '@carbon/react/icons';
4
4
  import { Router, useLocation, useParams } from 'react-router-dom';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Formik, Form, FormikHelpers } from 'formik';
@@ -17,19 +17,12 @@ import {
17
17
  parseAddressTemplateXml,
18
18
  scrollIntoView,
19
19
  } from './patient-registration-utils';
20
- import {
21
- useInitialAddressFieldValues,
22
- useInitialFormValues,
23
- usePatientObs,
24
- usePatientUuidMap,
25
- } from './patient-registration-hooks';
20
+ import { useInitialAddressFieldValues, useInitialFormValues, usePatientUuidMap } from './patient-registration-hooks';
26
21
  import { ResourcesContext } from '../offline.resources';
27
22
  import { builtInSections, RegistrationConfig, SectionDefinition } from '../config-schema';
28
23
  import { SectionWrapper } from './section/section-wrapper.component';
29
24
  import BeforeSavePrompt from './before-save-prompt';
30
25
  import styles from './patient-registration.scss';
31
- import PatientVerification from '../patient-verification/patient-verification.component';
32
- import { handleSavePatientToClientRegistry } from '../patient-verification/patient-verification-hook';
33
26
 
34
27
  let exportedInitialFormValuesForTesting = {} as FormValues;
35
28
 
@@ -57,9 +50,6 @@ export const PatientRegistration: React.FC<PatientRegistrationProps> = ({ savePa
57
50
  const { data: photo } = usePatientPhoto(patientToEdit?.id);
58
51
  const savePatientTransactionManager = useRef(new SavePatientTransactionManager());
59
52
  const fieldDefinition = config?.fieldDefinitions?.filter((def) => def.type === 'address');
60
- const [enableClientRegistry, setEnableClientRegistry] = useState(
61
- inEditMode ? initialFormValues.identifiers['nationalUniquePatientIdentifier']?.identifierValue : false,
62
- );
63
53
 
64
54
  useEffect(() => {
65
55
  exportedInitialFormValuesForTesting = initialFormValues;
@@ -185,18 +175,6 @@ export const PatientRegistration: React.FC<PatientRegistrationProps> = ({ savePa
185
175
  </Link>
186
176
  </div>
187
177
  ))}
188
- <Button
189
- renderIcon={ShareKnowledge}
190
- disabled={!currentSession || !identifierTypes}
191
- onClick={() => {
192
- setEnableClientRegistry(true);
193
- props.isValid
194
- ? handleSavePatientToClientRegistry(props.values, props.setValues, inEditMode)
195
- : props.validateForm().then((errors) => displayErrors(errors));
196
- }}
197
- className={styles.submitButton}>
198
- {t('postToRegistry', 'Post to registry')}
199
- </Button>
200
178
  <Button
201
179
  className={styles.submitButton}
202
180
  type="submit"
@@ -204,7 +182,7 @@ export const PatientRegistration: React.FC<PatientRegistrationProps> = ({ savePa
204
182
  // Current session and identifiers are required for patient registration.
205
183
  // If currentSession or identifierTypes are not available, then the
206
184
  // user should be blocked to register the patient.
207
- disabled={!enableClientRegistry}>
185
+ disabled={!currentSession || !identifierTypes}>
208
186
  {inEditMode ? t('updatePatient', 'Update Patient') : t('registerPatient', 'Register Patient')}
209
187
  </Button>
210
188
  <Button className={styles.cancelButton} kind="tertiary" onClick={cancelRegistration}>
@@ -226,7 +204,6 @@ export const PatientRegistration: React.FC<PatientRegistrationProps> = ({ savePa
226
204
  isOffline,
227
205
  initialFormValues: props.initialValues,
228
206
  }}>
229
- <PatientVerification props={props} />
230
207
  {sections.map((section, index) => (
231
208
  <SectionWrapper
232
209
  key={`registration-section-${section.id}`}