@kenyaemr/esm-patient-registration-app 4.5.2 → 4.5.4

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.
package/src/index.ts CHANGED
@@ -57,3 +57,6 @@ export const deleteIdentifierConfirmationModal = getAsyncLifecycle(
57
57
  () => import('./widgets/delete-identifier-confirmation-modal'),
58
58
  options,
59
59
  );
60
+
61
+ export const emptyVerificationModal = getAsyncLifecycle(() => import('./patient-verification/verification-modal/empty-prompt.component'), options);
62
+ export const confirmationVerificationModal = getAsyncLifecycle(() => import('./patient-verification/verification-modal/confirm-prompt.component'), options);
@@ -25,9 +25,9 @@ export const DobField: React.FC = () => {
25
25
  const { t } = useTranslation();
26
26
  const {
27
27
  fieldConfigurations: { dateOfBirth },
28
- } = useConfig() as RegistrationConfig;
29
- const [dobUnknown] = useField('birthdateEstimated');
30
- const dobKnown = !dobUnknown.value;
28
+ } = useConfig<RegistrationConfig>();
29
+ const allowEstimatedBirthDate = dateOfBirth?.allowEstimatedDateOfBirth;
30
+ const [{ value: dobUnknown }] = useField('birthdateEstimated');
31
31
  const [birthdate, birthdateMeta] = useField('birthdate');
32
32
  const [yearsEstimated, yearsEstimateMeta] = useField('yearsEstimated');
33
33
  const [monthsEstimated, monthsEstimateMeta] = useField('monthsEstimated');
@@ -75,17 +75,19 @@ export const DobField: React.FC = () => {
75
75
  return (
76
76
  <div className={styles.halfWidthInDesktopView}>
77
77
  <h4 className={styles.productiveHeading02Light}>{t('birthFieldLabelText', 'Birth')}</h4>
78
- <div className={styles.dobField}>
79
- <div className={styles.dobContentSwitcherLabel}>
80
- <span className={styles.label01}>{t('dobToggleLabelText', 'Date of Birth Known?')}</span>
78
+ {(allowEstimatedBirthDate || dobUnknown) && (
79
+ <div className={styles.dobField}>
80
+ <div className={styles.dobContentSwitcherLabel}>
81
+ <span className={styles.label01}>{t('dobToggleLabelText', 'Date of Birth Known?')}</span>
82
+ </div>
83
+ <ContentSwitcher onChange={onToggle} selectedIndex={dobUnknown ? 1 : 0}>
84
+ <Switch name="known" text={t('yes', 'Yes')} />
85
+ <Switch name="unknown" text={t('no', 'No')} />
86
+ </ContentSwitcher>
81
87
  </div>
82
- <ContentSwitcher onChange={onToggle}>
83
- <Switch name="known" text={t('yes', 'Yes')} />
84
- <Switch name="unknown" text={t('no', 'No')} />
85
- </ContentSwitcher>
86
- </div>
88
+ )}
87
89
  <Layer>
88
- {dobKnown ? (
90
+ {!dobUnknown ? (
89
91
  <div className={styles.dobField}>
90
92
  <DatePicker dateFormat={dateFormat} datePickerType="single" onChange={onDateChange} maxDate={format(today)}>
91
93
  <DatePickerInput
@@ -14,7 +14,12 @@ jest.mock('@openmrs/esm-framework', () => {
14
14
  return {
15
15
  ...originalModule,
16
16
  useConfig: jest.fn().mockImplementation(() => ({
17
- fieldConfigurations: { dateOfBirth: { useEstimatedDateOfBirth: { enabled: true, dayOfMonth: 0, month: 0 } } },
17
+ fieldConfigurations: {
18
+ dateOfBirth: {
19
+ allowEstimatedDateOfBirth: true,
20
+ useEstimatedDateOfBirth: { enabled: true, dayOfMonth: 0, month: 0 },
21
+ },
22
+ },
18
23
  })),
19
24
  };
20
25
  });
@@ -8,6 +8,7 @@ import { PatientRegistrationContext } from '../../patient-registration-context';
8
8
  import styles from '../field.scss';
9
9
  import { RegistrationConfig } from '../../../config-schema';
10
10
 
11
+ export const unidentifiedPatientAttributeTypeUuid = '8b56eac7-5c76-4b9c-8c6f-1deab8d3fc47';
11
12
  const containsNoNumbers = /^([^0-9]*)$/;
12
13
 
13
14
  function checkNumber(value: string) {
@@ -19,17 +20,26 @@ function checkNumber(value: string) {
19
20
  }
20
21
 
21
22
  export const NameField = () => {
23
+ const { t } = useTranslation();
24
+ const { setCapturePhotoProps, currentPhoto, setFieldValue } = useContext(PatientRegistrationContext);
22
25
  const {
23
26
  fieldConfigurations: {
24
- name: { displayCapturePhoto, displayReverseFieldOrder },
27
+ name: {
28
+ displayCapturePhoto,
29
+ allowUnidentifiedPatients,
30
+ defaultUnknownGivenName,
31
+ defaultUnknownFamilyName,
32
+ displayMiddleName,
33
+ displayReverseFieldOrder,
34
+ },
25
35
  },
26
- } = useConfig() as RegistrationConfig;
27
- const { t } = useTranslation();
28
- const { setCapturePhotoProps, currentPhoto, setFieldValue } = useContext(PatientRegistrationContext);
29
- const { fieldConfigurations } = useConfig();
30
- const fieldConfigs = fieldConfigurations?.name;
31
- const [{ value: unidentified }] = useField('unidentifiedPatient');
32
- const nameKnown = !unidentified;
36
+ } = useConfig<RegistrationConfig>();
37
+
38
+ const [{ value: isPatientUnknownValue }, , { setValue: setUnknownPatient }] = useField<string>(
39
+ `attributes.${unidentifiedPatientAttributeTypeUuid}`,
40
+ );
41
+
42
+ const isPatientUnknown = isPatientUnknownValue === 'true';
33
43
 
34
44
  const onCapturePhoto = useCallback(
35
45
  (dataUri: string, photoDateTime: string) => {
@@ -47,11 +57,11 @@ export const NameField = () => {
47
57
  if (e.name === 'known') {
48
58
  setFieldValue('givenName', '');
49
59
  setFieldValue('familyName', '');
50
- setFieldValue('unidentifiedPatient', false);
60
+ setUnknownPatient('false');
51
61
  } else {
52
- setFieldValue('givenName', fieldConfigs.defaultUnknownGivenName);
53
- setFieldValue('familyName', fieldConfigs.defaultUnknownFamilyName);
54
- setFieldValue('unidentifiedPatient', true);
62
+ setFieldValue('givenName', defaultUnknownGivenName);
63
+ setFieldValue('familyName', defaultUnknownFamilyName);
64
+ setUnknownPatient('true');
55
65
  }
56
66
  };
57
67
 
@@ -65,7 +75,7 @@ export const NameField = () => {
65
75
  />
66
76
  );
67
77
 
68
- const middleNameField = fieldConfigs.displayMiddleName && (
78
+ const middleNameField = displayMiddleName && (
69
79
  <Input
70
80
  id="middleName"
71
81
  name="middleName"
@@ -98,14 +108,21 @@ export const NameField = () => {
98
108
  )}
99
109
 
100
110
  <div className={styles.nameField}>
101
- <div className={styles.dobContentSwitcherLabel}>
102
- <span className={styles.label01}>{t('patientNameKnown', "Patient's Name is Known?")}</span>
103
- </div>
104
- <ContentSwitcher className={styles.contentSwitcher} onChange={toggleNameKnown}>
105
- <Switch name="known" text={t('yes', 'Yes')} />
106
- <Switch name="unknown" text={t('no', 'No')} />
107
- </ContentSwitcher>
108
- {nameKnown &&
111
+ {(allowUnidentifiedPatients || isPatientUnknown) && (
112
+ <>
113
+ <div className={styles.dobContentSwitcherLabel}>
114
+ <span className={styles.label01}>{t('patientNameKnown', "Patient's Name is Known?")}</span>
115
+ </div>
116
+ <ContentSwitcher
117
+ className={styles.contentSwitcher}
118
+ selectedIndex={isPatientUnknown ? 1 : 0}
119
+ onChange={toggleNameKnown}>
120
+ <Switch name="known" text={t('yes', 'Yes')} />
121
+ <Switch name="unknown" text={t('no', 'No')} />
122
+ </ContentSwitcher>
123
+ </>
124
+ )}
125
+ {!isPatientUnknown &&
109
126
  (!displayReverseFieldOrder ? (
110
127
  <>
111
128
  {firstNameField}
@@ -8,7 +8,6 @@ const formValues: FormValues = {
8
8
  givenName: '',
9
9
  middleName: '',
10
10
  familyName: '',
11
- unidentifiedPatient: false,
12
11
  additionalGivenName: '',
13
12
  additionalMiddleName: '',
14
13
  additionalFamilyName: '',
@@ -364,14 +364,6 @@ export class FormManager {
364
364
  }
365
365
  }
366
366
 
367
- if (values.unidentifiedPatient) {
368
- attributes.push({
369
- // The UUID of the 'Unknown Patient' attribute-type will always be static across all implementations of OpenMRS
370
- attributeType: '8b56eac7-5c76-4b9c-8c6f-1deab8d3fc47',
371
- value: 'true',
372
- });
373
- }
374
-
375
367
  return attributes;
376
368
  }
377
369
 
@@ -12,7 +12,6 @@ export const dummyFormValues: FormValues = {
12
12
  givenName: 'John',
13
13
  middleName: '',
14
14
  familyName: 'Smith',
15
- unidentifiedPatient: false,
16
15
  additionalGivenName: 'Joey',
17
16
  additionalMiddleName: '',
18
17
  additionalFamilyName: 'Smitty',
@@ -25,6 +25,7 @@ import {
25
25
  latestFirstEncounter,
26
26
  } from './patient-registration-utils';
27
27
  import { useInitialPatientRelationships } from './section/patient-relationships/relationships.resource';
28
+ import dayjs from 'dayjs';
28
29
 
29
30
  export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch<FormValues>] {
30
31
  const { martialStatus, education, occupation, educationLoad, loadingStatus } = useConcepts();
@@ -39,7 +40,6 @@ export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch
39
40
  givenName: '',
40
41
  middleName: '',
41
42
  familyName: '',
42
- unidentifiedPatient: false,
43
43
  additionalGivenName: '',
44
44
  additionalMiddleName: '',
45
45
  additionalFamilyName: '',
@@ -61,11 +61,22 @@ export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch
61
61
  useEffect(() => {
62
62
  (async () => {
63
63
  if (patientToEdit) {
64
+ const birthdateEstimated = !/^\d{4}-\d{2}-\d{2}$/.test(patientToEdit.birthDate);
65
+ const [years = 0, months = 0] = patientToEdit.birthDate.split('-').map((val) => parseInt(val));
66
+ // Please refer: https://github.com/openmrs/openmrs-esm-patient-management/pull/697#issuecomment-1562706118
67
+ const estimatedMonthsAvailable = patientToEdit.birthDate.split('-').length > 1;
68
+ const yearsEstimated = birthdateEstimated ? Math.floor(dayjs().diff(patientToEdit.birthDate, 'month') / 12) : 0;
69
+ const monthsEstimated =
70
+ birthdateEstimated && estimatedMonthsAvailable ? dayjs().diff(patientToEdit.birthDate, 'month') % 12 : 0;
71
+
64
72
  setInitialFormValues({
65
73
  ...initialFormValues,
66
74
  ...getFormValuesFromFhirPatient(patientToEdit),
67
75
  address: getAddressFieldValuesFromFhirPatient(patientToEdit),
68
76
  ...getPhonePersonAttributeValueFromFhirPatient(patientToEdit),
77
+ birthdateEstimated: !/^\d{4}-\d{2}-\d{2}$/.test(patientToEdit.birthDate),
78
+ yearsEstimated,
79
+ monthsEstimated,
69
80
  });
70
81
  } else if (!isLoadingPatientToEdit && patientUuid) {
71
82
  const registration = await getPatientRegistration(patientUuid);
@@ -120,6 +131,7 @@ export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch
120
131
  ? attribute.value?.uuid
121
132
  : attribute.value;
122
133
  });
134
+
123
135
  setInitialFormValues((initialFormValues) => ({
124
136
  ...initialFormValues,
125
137
  attributes: personAttributes,
@@ -158,7 +158,6 @@ export interface FormValues {
158
158
  givenName: string;
159
159
  middleName: string;
160
160
  familyName: string;
161
- unidentifiedPatient: boolean;
162
161
  additionalGivenName: string;
163
162
  additionalMiddleName: string;
164
163
  additionalFamilyName: string;
@@ -115,9 +115,6 @@ export function getFormValuesFromFhirPatient(patient: fhir.Patient) {
115
115
  result.givenName = patientName?.given[0];
116
116
  result.middleName = patientName?.given[1];
117
117
  result.familyName = patientName?.family;
118
- result.unidentifiedPatient =
119
- patientName.given[0] === 'UNKNOWN' && patientName.family === 'unknown' ? true : undefined;
120
-
121
118
  result.addNameInLocalLanguage = !!additionalPatientName ? true : undefined;
122
119
  result.additionalGivenName = additionalPatientName?.given[0];
123
120
  result.additionalMiddleName = additionalPatientName?.given[1];
package/src/routes.json CHANGED
@@ -42,5 +42,15 @@
42
42
  "name": "delete-identifier-confirmation-modal",
43
43
  "online": true,
44
44
  "offline": true
45
+ }, {
46
+ "component": "emptyVerificationModal",
47
+ "name":"empty-client-registry-modal",
48
+ "online": true,
49
+ "offline": false
50
+ },{
51
+ "component": "confirmationVerificationModal",
52
+ "name": "confirm-client-registry-modal",
53
+ "online": true,
54
+ "offline": false
45
55
  }]
46
56
  }
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { screen, render, fireEvent } from '@testing-library/react';
3
+ import CancelPatientEdit from './cancel-patient-edit.component';
4
+
5
+ describe('CancelPatientEdit component', () => {
6
+ const mockClose = jest.fn();
7
+ const mockOnConfirm = jest.fn();
8
+
9
+ beforeEach(() => {
10
+ jest.clearAllMocks();
11
+ });
12
+
13
+ it('renders the modal and triggers close and onConfirm functions', () => {
14
+ render(<CancelPatientEdit close={mockClose} onConfirm={mockOnConfirm} />);
15
+
16
+ const cancelButton = screen.getByRole('button', { name: /Cancel/i });
17
+ fireEvent.click(cancelButton);
18
+ expect(mockClose).toHaveBeenCalledTimes(1);
19
+
20
+ const discardButton = screen.getByRole('button', { name: /discard/i });
21
+ fireEvent.click(discardButton);
22
+ expect(mockOnConfirm).toHaveBeenCalledTimes(1);
23
+ });
24
+ });
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, screen } from '@testing-library/react';
3
+ import DeleteIdentifierConfirmationModal from './delete-identifier-confirmation-modal';
4
+
5
+ describe('DeleteIdentifierConfirmationModal component', () => {
6
+ const mockDeleteIdentifier = jest.fn();
7
+ const mockIdentifierName = 'Identifier Name';
8
+ const mockIdentifierValue = 'Identifier Value';
9
+
10
+ beforeEach(() => {
11
+ jest.clearAllMocks();
12
+ });
13
+
14
+ it('renders the modal and triggers deleteIdentifier function', () => {
15
+ render(
16
+ <DeleteIdentifierConfirmationModal
17
+ deleteIdentifier={mockDeleteIdentifier}
18
+ identifierName={mockIdentifierName}
19
+ identifierValue={mockIdentifierValue}
20
+ />,
21
+ );
22
+
23
+ const cancelButton = screen.getByRole('button', { name: /cancel/i });
24
+ fireEvent.click(cancelButton);
25
+ expect(mockDeleteIdentifier).toHaveBeenCalledWith(false);
26
+
27
+ const removeButton = screen.getByRole('button', { name: /remove identifier/i });
28
+ fireEvent.click(removeButton);
29
+ expect(mockDeleteIdentifier).toHaveBeenCalledWith(true);
30
+ });
31
+ });