@kenyaemr/esm-patient-registration-app 8.1.1-pre.111 → 8.1.1-pre.116
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/.turbo/turbo-build.log +22 -23
- package/dist/108.js +1 -1
- package/dist/130.js +1 -1
- package/dist/130.js.LICENSE.txt +2 -0
- package/dist/130.js.map +1 -1
- package/dist/2.js +1 -0
- package/dist/2.js.map +1 -0
- package/dist/250.js +1 -0
- package/dist/250.js.map +1 -0
- package/dist/271.js +1 -1
- package/dist/319.js +1 -1
- package/dist/325.js +1 -0
- package/dist/325.js.map +1 -0
- package/dist/372.js +2 -0
- package/dist/372.js.map +1 -0
- package/dist/460.js +1 -1
- package/dist/471.js +1 -0
- package/dist/471.js.map +1 -0
- package/dist/574.js +1 -1
- package/dist/644.js +1 -1
- package/dist/662.js +1 -0
- package/dist/662.js.map +1 -0
- package/dist/757.js +1 -1
- package/dist/76.js +1 -1
- package/dist/788.js +1 -1
- package/dist/807.js +1 -1
- package/dist/833.js +1 -1
- package/dist/895.js +2 -0
- package/dist/{745.js.LICENSE.txt → 895.js.LICENSE.txt} +10 -0
- package/dist/895.js.map +1 -0
- package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
- package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +150 -177
- package/dist/kenyaemr-esm-patient-registration-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +2 -2
- package/src/config-schema.ts +28 -2
- package/src/index.ts +1 -4
- package/src/patient-registration/field/cause-of-death/cause-of-death.component.tsx +98 -0
- package/src/patient-registration/field/date-and-time-of-death/date-and-time-of-death.component.tsx +84 -0
- package/src/patient-registration/field/dob/dob.component.tsx +21 -7
- package/src/patient-registration/field/field.component.tsx +11 -5
- package/src/patient-registration/field/field.resource.ts +11 -4
- package/src/patient-registration/field/field.scss +23 -1
- package/src/patient-registration/field/gender/gender-field.component.tsx +2 -1
- package/src/patient-registration/field/gender/gender-field.test.tsx +1 -0
- package/src/patient-registration/field/name/name-field.component.tsx +5 -1
- package/src/patient-registration/form-manager.test.ts +3 -0
- package/src/patient-registration/form-manager.ts +30 -15
- package/src/patient-registration/input/basic-input/input/input.component.tsx +5 -1
- package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +2 -2
- package/src/patient-registration/input/custom-input/identifier/identifier-input.test.tsx +122 -71
- package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +3 -0
- package/src/patient-registration/patient-registration-context.ts +4 -3
- package/src/patient-registration/patient-registration-hooks.ts +63 -8
- package/src/patient-registration/patient-registration-utils.ts +3 -7
- package/src/patient-registration/patient-registration.component.tsx +20 -13
- package/src/patient-registration/patient-registration.resource.ts +8 -0
- package/src/patient-registration/patient-registration.test.tsx +9 -3
- package/src/patient-registration/patient-registration.types.ts +4 -1
- package/src/patient-registration/section/death-info/death-info-section.component.tsx +22 -17
- package/src/patient-registration/section/death-info/death-info-section.test.tsx +4 -14
- package/src/patient-registration/section/section.component.tsx +1 -1
- package/src/patient-registration/section/section.scss +5 -0
- package/src/patient-registration/validation/{patient-registration-validation.test.tsx → patient-registration-validation.test.ts} +26 -4
- package/src/patient-registration/validation/patient-registration-validation.ts +126 -0
- package/src/routes.json +10 -18
- package/src/widgets/cancel-patient-edit.modal.tsx +33 -0
- package/src/widgets/cancel-patient-edit.test.tsx +2 -3
- package/src/widgets/delete-identifier-confirmation.modal.tsx +22 -15
- package/src/widgets/delete-identifier-confirmation.test.tsx +2 -1
- package/translations/am.json +36 -25
- package/translations/ar.json +37 -26
- package/translations/en.json +37 -20
- package/translations/es.json +38 -26
- package/translations/fr.json +47 -35
- package/translations/he.json +37 -30
- package/translations/km.json +37 -30
- package/translations/zh.json +37 -20
- package/translations/zh_CN.json +37 -20
- package/dist/152.js +0 -1
- package/dist/152.js.map +0 -1
- package/dist/255.js +0 -2
- package/dist/255.js.map +0 -1
- package/dist/303.js +0 -1
- package/dist/303.js.map +0 -1
- package/dist/623.js +0 -1
- package/dist/623.js.map +0 -1
- package/dist/729.js +0 -1
- package/dist/729.js.map +0 -1
- package/dist/735.js +0 -1
- package/dist/735.js.map +0 -1
- package/dist/745.js +0 -2
- package/dist/745.js.map +0 -1
- package/dist/830.js +0 -1
- package/dist/830.js.map +0 -1
- package/src/patient-registration/validation/patient-registration-validation.tsx +0 -60
- package/src/widgets/cancel-patient-edit.component.tsx +0 -37
- package/src/widgets/delete-identifier-confirmation.scss +0 -34
- /package/dist/{255.js.LICENSE.txt → 372.js.LICENSE.txt} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import {
|
|
3
|
+
import { Form, Formik } from 'formik';
|
|
4
4
|
import { initialFormValues } from '../../patient-registration.component';
|
|
5
|
-
import { DeathInfoSection } from './death-info-section.component';
|
|
6
5
|
import { type FormValues } from '../../patient-registration.types';
|
|
7
6
|
import { PatientRegistrationContext } from '../../patient-registration-context';
|
|
7
|
+
import { DeathInfoSection } from './death-info-section.component';
|
|
8
8
|
|
|
9
9
|
const initialContextValues = {
|
|
10
10
|
currentPhoto: 'data:image/png;base64,1234567890',
|
|
@@ -29,7 +29,7 @@ describe('Death info section', () => {
|
|
|
29
29
|
<PatientRegistrationContext.Provider value={initialContextValues}>
|
|
30
30
|
<Formik initialValues={initialFormValues} onSubmit={jest.fn()}>
|
|
31
31
|
<Form>
|
|
32
|
-
<DeathInfoSection />
|
|
32
|
+
<DeathInfoSection fields={[]} />
|
|
33
33
|
</Form>
|
|
34
34
|
</Formik>
|
|
35
35
|
</PatientRegistrationContext.Provider>,
|
|
@@ -40,16 +40,6 @@ describe('Death info section', () => {
|
|
|
40
40
|
renderDeathInfoSection(true);
|
|
41
41
|
|
|
42
42
|
expect(screen.getByRole('region', { name: /death info section/i })).toBeInTheDocument();
|
|
43
|
-
expect(screen.getByRole('
|
|
44
|
-
expect(screen.getByRole('textbox', { name: /is dead \(optional\)/i })).toBeInTheDocument();
|
|
45
|
-
expect(screen.getByRole('textbox', { name: /date of death \(optional\)/i })).toBeInTheDocument();
|
|
46
|
-
expect(screen.getByRole('combobox', { name: /cause of death \(optional\)/i })).toBeInTheDocument();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('has the correct number of inputs if is dead is not checked', async () => {
|
|
50
|
-
renderDeathInfoSection(false);
|
|
51
|
-
|
|
52
|
-
expect(screen.queryByRole('textbox', { name: /date of death \(optional\)/i })).not.toBeInTheDocument();
|
|
53
|
-
expect(screen.queryByRole('combobox', { name: /cause of death \(optional\)/i })).not.toBeInTheDocument();
|
|
43
|
+
expect(screen.getByRole('checkbox', { name: /is dead/i })).toBeInTheDocument();
|
|
54
44
|
});
|
|
55
45
|
});
|
|
@@ -14,7 +14,7 @@ export function Section({ sectionDefinition }: SectionProps) {
|
|
|
14
14
|
case 'demographics':
|
|
15
15
|
return <DemographicsSection fields={sectionDefinition.fields} />;
|
|
16
16
|
case 'death':
|
|
17
|
-
return <DeathInfoSection />;
|
|
17
|
+
return <DeathInfoSection fields={sectionDefinition.fields} />;
|
|
18
18
|
case 'relationships':
|
|
19
19
|
return <RelationshipsSection />;
|
|
20
20
|
default: // includes 'contact'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getConfig } from '@openmrs/esm-framework';
|
|
2
2
|
import { type RegistrationConfig } from '../../config-schema';
|
|
3
3
|
import { getValidationSchema } from './patient-registration-validation';
|
|
4
|
+
import dayjs from 'dayjs';
|
|
4
5
|
|
|
5
6
|
const mockGetConfig = jest.mocked(getConfig);
|
|
6
7
|
|
|
@@ -35,6 +36,8 @@ describe('Patient registration validation', () => {
|
|
|
35
36
|
additionalGivenName: '',
|
|
36
37
|
birthdate: new Date('1990-01-01'),
|
|
37
38
|
birthdateEstimated: false,
|
|
39
|
+
isDead: false,
|
|
40
|
+
causeOfDeath: null,
|
|
38
41
|
deathDate: null,
|
|
39
42
|
email: 'john.doe@example.com',
|
|
40
43
|
familyName: 'Doe',
|
|
@@ -142,7 +145,7 @@ describe('Patient registration validation', () => {
|
|
|
142
145
|
expect(validationError).toBeFalsy();
|
|
143
146
|
});
|
|
144
147
|
|
|
145
|
-
it('should throw error when date of birth is a future date', async () => {
|
|
148
|
+
it('should throw an error when date of birth is a future date', async () => {
|
|
146
149
|
const invalidFormValues = {
|
|
147
150
|
...validFormValues,
|
|
148
151
|
birthdate: new Date('2100-01-01'),
|
|
@@ -151,6 +154,15 @@ describe('Patient registration validation', () => {
|
|
|
151
154
|
expect(validationError.errors).toContain('birthdayNotInTheFuture');
|
|
152
155
|
});
|
|
153
156
|
|
|
157
|
+
it('should throw an error when date of birth is more than 140 years ago', async () => {
|
|
158
|
+
const invalidFormValues = {
|
|
159
|
+
...validFormValues,
|
|
160
|
+
birthdate: dayjs().subtract(141, 'years').toDate(),
|
|
161
|
+
};
|
|
162
|
+
const validationError = await validateFormValues(invalidFormValues);
|
|
163
|
+
expect(validationError.errors).toContain('birthdayNotOver140YearsAgo');
|
|
164
|
+
});
|
|
165
|
+
|
|
154
166
|
it('should require yearsEstimated when birthdateEstimated is true', async () => {
|
|
155
167
|
const invalidFormValues = {
|
|
156
168
|
...validFormValues,
|
|
@@ -160,7 +172,7 @@ describe('Patient registration validation', () => {
|
|
|
160
172
|
expect(validationError.errors).toContain('yearsEstimateRequired');
|
|
161
173
|
});
|
|
162
174
|
|
|
163
|
-
it('should throw error when monthEstimated is negative', async () => {
|
|
175
|
+
it('should throw an error when monthEstimated is negative', async () => {
|
|
164
176
|
const invalidFormValues = {
|
|
165
177
|
...validFormValues,
|
|
166
178
|
birthdateEstimated: true,
|
|
@@ -171,12 +183,22 @@ describe('Patient registration validation', () => {
|
|
|
171
183
|
expect(validationError.errors).toContain('negativeMonths');
|
|
172
184
|
});
|
|
173
185
|
|
|
174
|
-
it('should throw error when
|
|
186
|
+
it('should throw an error when yearsEstimated is more than 140', async () => {
|
|
187
|
+
const invalidFormValues = {
|
|
188
|
+
...validFormValues,
|
|
189
|
+
birthdateEstimated: true,
|
|
190
|
+
yearsEstimated: 141,
|
|
191
|
+
};
|
|
192
|
+
const validationError = await validateFormValues(invalidFormValues);
|
|
193
|
+
expect(validationError.errors).toContain('nonsensicalYears');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should throw an error when deathDate is in future', async () => {
|
|
175
197
|
const invalidFormValues = {
|
|
176
198
|
...validFormValues,
|
|
177
199
|
deathDate: new Date('2100-01-01'),
|
|
178
200
|
};
|
|
179
201
|
const validationError = await validateFormValues(invalidFormValues);
|
|
180
|
-
expect(validationError.errors).toContain('
|
|
202
|
+
expect(validationError.errors).toContain('deathDateInFuture');
|
|
181
203
|
});
|
|
182
204
|
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import * as Yup from 'yup';
|
|
3
|
+
import mapValues from 'lodash/mapValues';
|
|
4
|
+
import { translateFrom } from '@openmrs/esm-framework';
|
|
5
|
+
import { type RegistrationConfig } from '../../config-schema';
|
|
6
|
+
import { type FormValues } from '../patient-registration.types';
|
|
7
|
+
import { getDatetime } from '../patient-registration.resource';
|
|
8
|
+
|
|
9
|
+
const t = (key: string, value: string) => translateFrom('@openmrs/esm-framework', key, value);
|
|
10
|
+
|
|
11
|
+
export function getValidationSchema(config: RegistrationConfig) {
|
|
12
|
+
return Yup.object({
|
|
13
|
+
givenName: Yup.string().required(t('givenNameRequired', 'Given name is required')),
|
|
14
|
+
familyName: Yup.string().required(t('familyNameRequired', 'Family name is required')),
|
|
15
|
+
additionalGivenName: Yup.string().when('addNameInLocalLanguage', {
|
|
16
|
+
is: true,
|
|
17
|
+
then: Yup.string().required(t('givenNameRequired', 'Given name is required')),
|
|
18
|
+
otherwise: Yup.string().notRequired(),
|
|
19
|
+
}),
|
|
20
|
+
additionalFamilyName: Yup.string().when('addNameInLocalLanguage', {
|
|
21
|
+
is: true,
|
|
22
|
+
then: Yup.string().required(t('familyNameRequired', 'Family name is required')),
|
|
23
|
+
otherwise: Yup.string().notRequired(),
|
|
24
|
+
}),
|
|
25
|
+
gender: Yup.string()
|
|
26
|
+
.oneOf(
|
|
27
|
+
config.fieldConfigurations.gender.map((g) => g.value),
|
|
28
|
+
t('genderUnspecified', 'Gender unspecified'),
|
|
29
|
+
)
|
|
30
|
+
.required(t('genderRequired', 'Gender is required')),
|
|
31
|
+
birthdate: Yup.date().when('birthdateEstimated', {
|
|
32
|
+
is: false,
|
|
33
|
+
then: Yup.date()
|
|
34
|
+
.required(t('birthdayRequired', 'Birthday is required'))
|
|
35
|
+
.max(Date(), t('birthdayNotInTheFuture', 'Birthday cannot be in future'))
|
|
36
|
+
.min(
|
|
37
|
+
dayjs().subtract(140, 'years').toDate(),
|
|
38
|
+
t('birthdayNotOver140YearsAgo', 'Birthday cannot be more than 140 years ago'),
|
|
39
|
+
)
|
|
40
|
+
.nullable(),
|
|
41
|
+
otherwise: Yup.date().nullable(),
|
|
42
|
+
}),
|
|
43
|
+
yearsEstimated: Yup.number().when('birthdateEstimated', {
|
|
44
|
+
is: true,
|
|
45
|
+
then: Yup.number()
|
|
46
|
+
.required(t('yearsEstimateRequired', 'Estimated years required'))
|
|
47
|
+
.min(0, t('negativeYears', 'Estimated years cannot be negative'))
|
|
48
|
+
.max(140, t('nonsensicalYears', 'Estimated years cannot be more than 140')),
|
|
49
|
+
otherwise: Yup.number().nullable(),
|
|
50
|
+
}),
|
|
51
|
+
monthsEstimated: Yup.number().min(0, t('negativeMonths', 'Estimated months cannot be negative')),
|
|
52
|
+
isDead: Yup.boolean(),
|
|
53
|
+
deathDate: Yup.date()
|
|
54
|
+
.when('isDead', {
|
|
55
|
+
is: true,
|
|
56
|
+
then: Yup.date().required(t('deathDateRequired', 'Death date is required')),
|
|
57
|
+
otherwise: Yup.date().nullable(),
|
|
58
|
+
})
|
|
59
|
+
.max(new Date(), 'deathDateInFuture')
|
|
60
|
+
.test(
|
|
61
|
+
'deathDate-after-birthdate',
|
|
62
|
+
t('deathdayInvalidDate', 'Death date and time cannot be before the birthday'),
|
|
63
|
+
function (value) {
|
|
64
|
+
const { birthdate } = this.parent;
|
|
65
|
+
if (birthdate && value) {
|
|
66
|
+
return dayjs(value).isAfter(birthdate);
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
.test('deathDate-before-today', t('deathDateInFuture', 'Death date cannot be in future'), function (value) {
|
|
72
|
+
const { deathTime, deathTimeFormat } = this.parent;
|
|
73
|
+
if (value && deathTime && deathTimeFormat && /^(1[0-2]|0?[1-9]):([0-5]?[0-9])$/.test(deathTime)) {
|
|
74
|
+
return dayjs(getDatetime(value, deathTime, deathTimeFormat)).isBefore(dayjs());
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}),
|
|
78
|
+
deathTime: Yup.string()
|
|
79
|
+
.when('isDead', {
|
|
80
|
+
is: true,
|
|
81
|
+
then: Yup.string().required(t('deathTimeRequired', 'Death time is required')),
|
|
82
|
+
otherwise: Yup.string().nullable(),
|
|
83
|
+
})
|
|
84
|
+
.matches(/^(1[0-2]|0?[1-9]):([0-5]?[0-9])$/, t('deathTimeInvalid', "Time doesn't match the format 'hh:mm'")),
|
|
85
|
+
|
|
86
|
+
deathTimeFormat: Yup.string()
|
|
87
|
+
.when('isDead', {
|
|
88
|
+
is: true,
|
|
89
|
+
then: Yup.string().required(t('deathTimeFormatRequired', 'Time format is required')),
|
|
90
|
+
otherwise: Yup.string().nullable(),
|
|
91
|
+
})
|
|
92
|
+
.oneOf(['AM', 'PM'], t('deathTimeFormatInvalid', 'Time format is invalid')),
|
|
93
|
+
|
|
94
|
+
deathCause: Yup.string().when('isDead', {
|
|
95
|
+
is: true,
|
|
96
|
+
then: Yup.string().required(t('deathCauseRequired', 'Cause of death is required')),
|
|
97
|
+
otherwise: Yup.string().nullable(),
|
|
98
|
+
}),
|
|
99
|
+
nonCodedCauseOfDeath: Yup.string().when(['isDead', 'deathCause'], {
|
|
100
|
+
is: (isDead, deathCause) => isDead && deathCause === config.freeTextFieldConceptUuid,
|
|
101
|
+
then: Yup.string().required(t('nonCodedCauseOfDeathRequired', 'Cause of death is required')),
|
|
102
|
+
otherwise: Yup.string().nullable(),
|
|
103
|
+
}),
|
|
104
|
+
email: Yup.string().optional().email(t('invalidEmail', 'Invalid email')),
|
|
105
|
+
identifiers: Yup.lazy((obj: FormValues['identifiers']) =>
|
|
106
|
+
Yup.object(
|
|
107
|
+
mapValues(obj, () =>
|
|
108
|
+
Yup.object({
|
|
109
|
+
required: Yup.bool(),
|
|
110
|
+
identifierValue: Yup.string().when('required', {
|
|
111
|
+
is: true,
|
|
112
|
+
then: Yup.string().required(t('identifierValueRequired', 'Identifier value is required')),
|
|
113
|
+
otherwise: Yup.string().notRequired(),
|
|
114
|
+
}),
|
|
115
|
+
}),
|
|
116
|
+
),
|
|
117
|
+
),
|
|
118
|
+
),
|
|
119
|
+
relationships: Yup.array().of(
|
|
120
|
+
Yup.object().shape({
|
|
121
|
+
relatedPersonUuid: Yup.string().required(),
|
|
122
|
+
relationshipType: Yup.string().required(),
|
|
123
|
+
}),
|
|
124
|
+
),
|
|
125
|
+
});
|
|
126
|
+
}
|
package/src/routes.json
CHANGED
|
@@ -25,12 +25,6 @@
|
|
|
25
25
|
"online": true,
|
|
26
26
|
"offline": true
|
|
27
27
|
},
|
|
28
|
-
{
|
|
29
|
-
"component": "cancelPatientEditModal",
|
|
30
|
-
"name": "cancel-patient-edit-modal",
|
|
31
|
-
"online": true,
|
|
32
|
-
"offline": true
|
|
33
|
-
},
|
|
34
28
|
{
|
|
35
29
|
"component": "patientPhotoExtension",
|
|
36
30
|
"name": "patient-photo-widget",
|
|
@@ -51,27 +45,25 @@
|
|
|
51
45
|
"slot": "patient-search-actions-slot",
|
|
52
46
|
"online": true,
|
|
53
47
|
"offline": true
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"modals": [
|
|
51
|
+
{
|
|
52
|
+
"name": "cancel-patient-edit-modal",
|
|
53
|
+
"component": "cancelPatientEditModal"
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
|
-
"component": "deleteIdentifierConfirmationModal",
|
|
57
56
|
"name": "delete-identifier-confirmation-modal",
|
|
58
|
-
"
|
|
59
|
-
"offline": true
|
|
57
|
+
"component": "deleteIdentifierConfirmationModal"
|
|
60
58
|
},
|
|
61
59
|
{
|
|
62
60
|
"component": "emptyClientRegistryModal",
|
|
63
|
-
"name": "empty-client-registry-modal"
|
|
64
|
-
"online": true,
|
|
65
|
-
"offline": true
|
|
61
|
+
"name": "empty-client-registry-modal"
|
|
66
62
|
},
|
|
67
63
|
{
|
|
68
64
|
"component": "confirmClientRegistryModal",
|
|
69
|
-
"name": "confirm-client-registry-modal"
|
|
70
|
-
|
|
71
|
-
"offline": true
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
|
-
"modals": [
|
|
65
|
+
"name": "confirm-client-registry-modal"
|
|
66
|
+
},
|
|
75
67
|
{
|
|
76
68
|
"component": "hieConfirmationModal",
|
|
77
69
|
"name": "hie-confirmation-modal"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
|
|
4
|
+
|
|
5
|
+
interface CancelPatientEditPropsModal {
|
|
6
|
+
close(): void;
|
|
7
|
+
onConfirm(): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const CancelPatientEditModal: React.FC<CancelPatientEditPropsModal> = ({ close, onConfirm }) => {
|
|
11
|
+
const { t } = useTranslation();
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
<ModalHeader
|
|
15
|
+
closeModal={close}
|
|
16
|
+
title={t('confirmDiscardChangesTitle', 'Are you sure you want to discard these changes?')}
|
|
17
|
+
/>
|
|
18
|
+
<ModalBody>
|
|
19
|
+
<p>{t('confirmDiscardChangesBody', 'Your unsaved changes will be lost if you proceed to discard the form')}.</p>
|
|
20
|
+
</ModalBody>
|
|
21
|
+
<ModalFooter>
|
|
22
|
+
<Button kind="secondary" onClick={close}>
|
|
23
|
+
{t('cancel', 'Cancel')}
|
|
24
|
+
</Button>
|
|
25
|
+
<Button kind="danger" onClick={onConfirm}>
|
|
26
|
+
{t('discard', 'Discard')}
|
|
27
|
+
</Button>
|
|
28
|
+
</ModalFooter>
|
|
29
|
+
</>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default CancelPatientEditModal;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { screen, render } from '@testing-library/react';
|
|
4
|
-
import CancelPatientEdit from './cancel-patient-edit.
|
|
4
|
+
import CancelPatientEdit from './cancel-patient-edit.modal';
|
|
5
5
|
|
|
6
|
-
describe('CancelPatientEdit
|
|
6
|
+
describe('CancelPatientEdit modal', () => {
|
|
7
7
|
const mockClose = jest.fn();
|
|
8
8
|
const mockOnConfirm = jest.fn();
|
|
9
9
|
|
|
10
10
|
it('renders the modal and triggers close and onConfirm functions', async () => {
|
|
11
11
|
const user = userEvent.setup();
|
|
12
|
-
|
|
13
12
|
render(<CancelPatientEdit close={mockClose} onConfirm={mockOnConfirm} />);
|
|
14
13
|
|
|
15
14
|
const cancelButton = screen.getByRole('button', { name: /Cancel/i });
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import { Button } from '@carbon/react';
|
|
4
|
-
import styles from './delete-identifier-confirmation.scss';
|
|
3
|
+
import { Button, ModalBody, ModalHeader, ModalFooter } from '@carbon/react';
|
|
5
4
|
|
|
6
5
|
interface DeleteIdentifierConfirmationModalProps {
|
|
6
|
+
closeModal: () => void;
|
|
7
7
|
deleteIdentifier: (x: boolean) => void;
|
|
8
8
|
identifierName: string;
|
|
9
9
|
identifierValue: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const DeleteIdentifierConfirmationModal: React.FC<DeleteIdentifierConfirmationModalProps> = ({
|
|
13
|
+
closeModal,
|
|
13
14
|
deleteIdentifier,
|
|
14
15
|
identifierName,
|
|
15
16
|
identifierValue,
|
|
@@ -17,24 +18,30 @@ const DeleteIdentifierConfirmationModal: React.FC<DeleteIdentifierConfirmationMo
|
|
|
17
18
|
const { t } = useTranslation();
|
|
18
19
|
|
|
19
20
|
return (
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
<>
|
|
22
|
+
<ModalHeader
|
|
23
|
+
closeModal={closeModal}
|
|
24
|
+
title={t('deleteIdentifierModalHeading', 'Delete identifier?')}></ModalHeader>
|
|
25
|
+
<ModalBody>
|
|
26
|
+
<p>
|
|
27
|
+
{identifierName && identifierValue && (
|
|
28
|
+
<span>
|
|
29
|
+
<strong>{identifierName}</strong>
|
|
30
|
+
{t('deleteIdentifierModalText', ' has a value of ')} <strong>{identifierValue}</strong>.{' '}
|
|
31
|
+
</span>
|
|
32
|
+
)}
|
|
33
|
+
{t('confirmIdentifierDeletionText', 'Are you sure you want to delete this identifier?')}
|
|
34
|
+
</p>
|
|
35
|
+
</ModalBody>
|
|
36
|
+
<ModalFooter>
|
|
30
37
|
<Button kind="secondary" size="lg" onClick={() => deleteIdentifier(false)}>
|
|
31
38
|
{t('cancel', 'Cancel')}
|
|
32
39
|
</Button>
|
|
33
40
|
<Button kind="danger" size="lg" onClick={() => deleteIdentifier(true)}>
|
|
34
|
-
{t('removeIdentifierButton', 'Remove
|
|
41
|
+
{t('removeIdentifierButton', 'Remove identifier')}
|
|
35
42
|
</Button>
|
|
36
|
-
</
|
|
37
|
-
|
|
43
|
+
</ModalFooter>
|
|
44
|
+
</>
|
|
38
45
|
);
|
|
39
46
|
};
|
|
40
47
|
|
|
@@ -3,7 +3,7 @@ import userEvent from '@testing-library/user-event';
|
|
|
3
3
|
import { render, screen } from '@testing-library/react';
|
|
4
4
|
import DeleteIdentifierConfirmationModal from './delete-identifier-confirmation.modal';
|
|
5
5
|
|
|
6
|
-
describe('DeleteIdentifierConfirmationModal
|
|
6
|
+
describe('DeleteIdentifierConfirmationModal', () => {
|
|
7
7
|
const mockDeleteIdentifier = jest.fn();
|
|
8
8
|
const mockIdentifierName = 'Identifier Name';
|
|
9
9
|
const mockIdentifierValue = 'Identifier Value';
|
|
@@ -13,6 +13,7 @@ describe('DeleteIdentifierConfirmationModal component', () => {
|
|
|
13
13
|
|
|
14
14
|
render(
|
|
15
15
|
<DeleteIdentifierConfirmationModal
|
|
16
|
+
closeModal={jest.fn()}
|
|
16
17
|
deleteIdentifier={mockDeleteIdentifier}
|
|
17
18
|
identifierName={mockIdentifierName}
|
|
18
19
|
identifierValue={mockIdentifierValue}
|
package/translations/am.json
CHANGED
|
@@ -4,68 +4,78 @@
|
|
|
4
4
|
"age": "Age",
|
|
5
5
|
"allFieldsRequiredText": "All fields are required unless marked optional",
|
|
6
6
|
"autoGeneratedPlaceholderText": "Auto-generated",
|
|
7
|
-
"birthdayNotInTheFuture": "Birthday cannot be in
|
|
7
|
+
"birthdayNotInTheFuture": "Birthday cannot be in future",
|
|
8
|
+
"birthdayNotOver140YearsAgo": "Birthday cannot be more than 140 years ago",
|
|
8
9
|
"birthdayRequired": "Birthday is required",
|
|
9
10
|
"birthFieldLabelText": "Birth",
|
|
10
11
|
"cancel": "Cancel",
|
|
11
|
-
"causeOfDeathInputLabel": "Cause of
|
|
12
|
-
"clientRegistryEmpty": "Create & Post Patient",
|
|
13
|
-
"clientVerificationWithClientRegistry": "Client verification with client registry",
|
|
12
|
+
"causeOfDeathInputLabel": "Cause of death",
|
|
14
13
|
"closeOverlay": "Close overlay",
|
|
15
14
|
"codedPersonAttributeAnswerSetEmpty": "The coded person attribute field '{{codedPersonAttributeFieldId}}' has been defined with an answer concept set UUID '{{answerConceptSetUuid}}' that does not have any concept answers.",
|
|
16
15
|
"codedPersonAttributeAnswerSetInvalid": "The coded person attribute field '{{codedPersonAttributeFieldId}}' has been defined with an invalid answer concept set UUID '{{answerConceptSetUuid}}'.",
|
|
17
16
|
"codedPersonAttributeNoAnswerSet": "The person attribute field '{{codedPersonAttributeFieldId}}' is of type 'coded' but has been defined without an answer concept set UUID. The 'answerConceptSetUuid' key is required.",
|
|
18
17
|
"configure": "Configure",
|
|
19
18
|
"configureIdentifiers": "Configure identifiers",
|
|
19
|
+
"confirmDiscardChangesBody": "Your unsaved changes will be lost if you proceed to discard the form",
|
|
20
|
+
"confirmDiscardChangesTitle": "Are you sure you want to discard these changes?",
|
|
20
21
|
"confirmIdentifierDeletionText": "Are you sure you want to remove this identifier?",
|
|
21
22
|
"contactSection": "Contact Details",
|
|
22
23
|
"createNewPatient": "Create new patient",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
24
|
+
"dateOfBirthLabelText": "Date of birth",
|
|
25
|
+
"deathCauseRequired": "Cause of death is required",
|
|
26
|
+
"deathDateInFuture": "Death date cannot be in future",
|
|
27
|
+
"deathDateInputLabel": "Date of death",
|
|
28
|
+
"deathDateRequired": "Death date is required",
|
|
29
|
+
"deathdayInvalidDate": "Death date and time cannot be before the birthday",
|
|
30
|
+
"deathdayIsRequired": "Death date is required when the patient is marked as deceased.",
|
|
31
|
+
"deathdayNotInTheFuture": "",
|
|
29
32
|
"deathSection": "Death Info",
|
|
33
|
+
"deathTimeFormatInvalid": "Time format is invalid",
|
|
34
|
+
"deathTimeFormatRequired": "Time format is required",
|
|
35
|
+
"deathTimeInvalid": "Time doesn't match the format 'hh:mm'",
|
|
36
|
+
"deathTimeRequired": "Death time is required",
|
|
30
37
|
"deleteIdentifierModalHeading": "Remove identifier?",
|
|
31
38
|
"deleteIdentifierModalText": " has a value of ",
|
|
32
39
|
"deleteIdentifierTooltip": "Delete",
|
|
33
40
|
"deleteRelationshipTooltipText": "Delete",
|
|
34
41
|
"demographicsSection": "Basic Info",
|
|
35
42
|
"discard": "Discard",
|
|
36
|
-
"discardModalBody": "The changes you made to this patient's details have not been saved. Discard changes?",
|
|
37
|
-
"discardModalHeader": "Confirm Discard Changes",
|
|
38
43
|
"dobToggleLabelText": "Date of Birth Known?",
|
|
39
44
|
"editIdentifierTooltip": "Edit",
|
|
40
45
|
"editPatientDetails": "Edit patient details",
|
|
41
46
|
"editPatientDetailsBreadcrumb": "Edit patient details",
|
|
47
|
+
"enterNonCodedCauseOfDeath": "Enter non-coded cause of death",
|
|
42
48
|
"error": "Error",
|
|
49
|
+
"errorFetchingCodedCausesOfDeath": "Error fetching coded causes of death",
|
|
43
50
|
"errorFetchingOrderedFields": "Error occured fetching ordered fields for address hierarchy",
|
|
44
51
|
"estimatedAgeInMonthsLabelText": "Estimated age in months",
|
|
45
52
|
"estimatedAgeInYearsLabelText": "Estimated age in years",
|
|
46
53
|
"familyNameLabelText": "Family Name",
|
|
47
54
|
"familyNameRequired": "Family name is required",
|
|
48
55
|
"female": "Female",
|
|
56
|
+
"fieldsWithErrors": "The following fields have errors: ",
|
|
49
57
|
"fullNameLabelText": "Full Name",
|
|
50
58
|
"gender": "Gender",
|
|
51
59
|
"genderLabelText": "Sex",
|
|
52
60
|
"genderRequired": "Gender is required",
|
|
53
|
-
"genderUnspecified": "Gender
|
|
61
|
+
"genderUnspecified": "Gender unspecified",
|
|
54
62
|
"givenNameLabelText": "First Name",
|
|
55
63
|
"givenNameRequired": "Given name is required",
|
|
56
64
|
"identifierValueRequired": "Identifier value is required",
|
|
57
65
|
"idFieldLabelText": "Identifiers",
|
|
58
66
|
"IDInstructions": "Select the identifiers you'd like to add for this patient:",
|
|
59
|
-
"
|
|
60
|
-
"invalidEmail": "A valid email has to be given",
|
|
67
|
+
"invalidEmail": "Invalid email",
|
|
61
68
|
"invalidInput": "Invalid Input",
|
|
62
|
-
"isDeadInputLabel": "Is
|
|
69
|
+
"isDeadInputLabel": "Is dead",
|
|
63
70
|
"jumpTo": "Jump to",
|
|
64
71
|
"male": "Male",
|
|
65
72
|
"middleNameLabelText": "Middle Name",
|
|
66
|
-
"negativeMonths": "
|
|
67
|
-
"negativeYears": "
|
|
73
|
+
"negativeMonths": "Estimated months cannot be negative",
|
|
74
|
+
"negativeYears": "Estimated years cannot be negative",
|
|
68
75
|
"no": "No",
|
|
76
|
+
"nonCodedCauseOfDeath": "Non-coded cause of death",
|
|
77
|
+
"nonCodedCauseOfDeathRequired": "Cause of death is required",
|
|
78
|
+
"nonsensicalYears": "Estimated years cannot be more than 140",
|
|
69
79
|
"numberInNameDubious": "Number in name is dubious",
|
|
70
80
|
"obsFieldUnknownDatatype": "Concept for obs field '{{fieldDefinitionId}}' has unknown datatype '{{datatypeName}}'",
|
|
71
81
|
"optional": "optional",
|
|
@@ -78,8 +88,8 @@
|
|
|
78
88
|
"patientNameKnown": "Patient's Name is Known?",
|
|
79
89
|
"patientNotFound": "The patient records could not be found in Client registry, do you want to continue to create and post patient to registry",
|
|
80
90
|
"patientRegistrationBreadcrumb": "Patient Registration",
|
|
81
|
-
"
|
|
82
|
-
"registerPatient": "Register
|
|
91
|
+
"refreshOrContactAdmin": "Try refreshing the page or contact your system administrator",
|
|
92
|
+
"registerPatient": "Register patient",
|
|
83
93
|
"registerPatientSuccessSnackbarSubtitle": "The patient can now be found by searching for them using their name or ID number",
|
|
84
94
|
"registerPatientSuccessSnackbarTitle": "New Patient Created",
|
|
85
95
|
"registrationErrorSnackbarTitle": "Patient Registration Failed",
|
|
@@ -89,9 +99,9 @@
|
|
|
89
99
|
"relationshipRemovedText": "Relationship removed",
|
|
90
100
|
"relationshipsSection": "Relationships",
|
|
91
101
|
"relationshipToPatient": "Relationship to patient",
|
|
92
|
-
"relativeFullNameLabelText": "
|
|
102
|
+
"relativeFullNameLabelText": "Full name",
|
|
93
103
|
"relativeNamePlaceholder": "Firstname Familyname",
|
|
94
|
-
"removeIdentifierButton": "Remove
|
|
104
|
+
"removeIdentifierButton": "Remove identifier",
|
|
95
105
|
"resetIdentifierTooltip": "Reset",
|
|
96
106
|
"restoreRelationshipActionButton": "Undo",
|
|
97
107
|
"searchAddress": "Search address",
|
|
@@ -101,15 +111,16 @@
|
|
|
101
111
|
"selectIdentifierType": "Select identifier type",
|
|
102
112
|
"sexFieldLabelText": "Sex",
|
|
103
113
|
"source": "Source",
|
|
104
|
-
"stroke": "Stroke",
|
|
105
114
|
"submitting": "Submitting",
|
|
115
|
+
"timeFormat": "Time Format",
|
|
116
|
+
"timeOfDeathInputLabel": "Time of death (hh:mm)",
|
|
106
117
|
"unableToFetch": "Unable to fetch person attribute type - {{personattributetype}}",
|
|
107
118
|
"unknown": "Unknown",
|
|
108
119
|
"unknownPatientAttributeType": "Patient attribute type has unknown format {{personAttributeTypeFormat}}",
|
|
109
|
-
"updatePatient": "Update
|
|
120
|
+
"updatePatient": "Update patient",
|
|
110
121
|
"updatePatientErrorSnackbarTitle": "Patient Details Update Failed",
|
|
111
122
|
"updatePatientSuccessSnackbarSubtitle": "The patient's information has been successfully updated",
|
|
112
123
|
"updatePatientSuccessSnackbarTitle": "Patient Details Updated",
|
|
113
|
-
"yearsEstimateRequired": "
|
|
124
|
+
"yearsEstimateRequired": "Estimated years required",
|
|
114
125
|
"yes": "Yes"
|
|
115
126
|
}
|