@openmrs/esm-patient-registration-app 3.0.2-pre.310 → 3.0.2-pre.332
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/dist/258.js +2 -0
- package/dist/258.js.map +1 -0
- package/dist/272.js +1 -1
- package/dist/272.js.map +1 -1
- package/dist/295.js +1 -1
- package/dist/295.js.map +1 -1
- package/dist/30.js +1 -1
- package/dist/30.js.map +1 -1
- package/dist/309.js +3 -0
- package/dist/{770.js.LICENSE.txt → 309.js.LICENSE.txt} +0 -0
- package/dist/309.js.map +1 -0
- package/dist/323.js +1 -1
- package/dist/323.js.map +1 -1
- package/dist/324.js +1 -1
- package/dist/324.js.map +1 -1
- package/dist/401.js +2 -0
- package/dist/401.js.map +1 -0
- package/dist/574.js +1 -1
- package/dist/71.js +1 -1
- package/dist/71.js.map +1 -1
- package/dist/817.js +1 -1
- package/dist/817.js.map +1 -1
- package/dist/831.js +3 -0
- package/dist/{932.js.LICENSE.txt → 831.js.LICENSE.txt} +0 -0
- package/dist/831.js.map +1 -0
- package/dist/916.js +2 -0
- package/dist/916.js.map +1 -0
- package/dist/932.js +1 -2
- package/dist/932.js.map +1 -1
- package/dist/openmrs-esm-patient-registration-app.js +1 -1
- package/dist/openmrs-esm-patient-registration-app.js.buildmanifest.json +103 -80
- package/dist/openmrs-esm-patient-registration-app.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +7 -1
- package/src/offline.resources.ts +34 -30
- package/src/offline.ts +9 -9
- package/src/patient-registration/field/id/id-field.component.tsx +15 -12
- package/src/patient-registration/{ui-components/identifier-selection-overlay/index.tsx → field/id/identifier-selection-overlay.tsx} +29 -30
- package/src/patient-registration/{ui-components/identifier-selection-overlay → field/id}/identifier-selection.scss +0 -0
- package/src/patient-registration/form-manager.test.ts +5 -14
- package/src/patient-registration/form-manager.ts +104 -72
- package/src/patient-registration/input/basic-input/input/input.component.tsx +2 -8
- package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +23 -34
- package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +2 -0
- package/src/patient-registration/patient-registration-hooks.ts +71 -62
- package/src/patient-registration/patient-registration-types.tsx +30 -17
- package/src/patient-registration/patient-registration-utils.ts +4 -3
- package/src/patient-registration/patient-registration.component.tsx +17 -19
- package/src/patient-registration/patient-registration.resource.tsx +6 -5
- package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +6 -6
- package/src/root.component.tsx +2 -2
- package/src/widgets/delete-identifier-confirmation-modal.tsx +41 -0
- package/src/widgets/delete-identifier-modal.scss +32 -0
- package/src/widgets/edit-patient-details-button.component.tsx +1 -1
- package/translations/en.json +1 -2
- package/dist/373.js +0 -2
- package/dist/373.js.map +0 -1
- package/dist/764.js +0 -2
- package/dist/764.js.map +0 -1
- package/dist/770.js +0 -3
- package/dist/770.js.map +0 -1
- package/dist/94.js +0 -2
- package/dist/94.js.map +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import FormManager from './form-manager';
|
|
2
|
+
import { FormValues } from './patient-registration-types';
|
|
2
3
|
|
|
3
4
|
jest.mock('./patient-registration.resource');
|
|
4
5
|
|
|
5
|
-
const formValues = {
|
|
6
|
+
const formValues: FormValues = {
|
|
7
|
+
patientUuid: '',
|
|
6
8
|
givenName: '',
|
|
7
9
|
middleName: '',
|
|
8
10
|
familyName: '',
|
|
@@ -42,20 +44,9 @@ const identifierSource = {
|
|
|
42
44
|
describe('FormManager', () => {
|
|
43
45
|
describe('createIdentifiers', () => {
|
|
44
46
|
it('uses the uuid of a field name if it exists', async () => {
|
|
45
|
-
const result = await FormManager.
|
|
47
|
+
const result = await FormManager.savePatientIdentifiers(
|
|
48
|
+
undefined,
|
|
46
49
|
formValues.identifiers,
|
|
47
|
-
[
|
|
48
|
-
{
|
|
49
|
-
name: 'foo',
|
|
50
|
-
required: false,
|
|
51
|
-
isPrimary: true,
|
|
52
|
-
fieldName: 'givenName',
|
|
53
|
-
uuid: 'identifierType',
|
|
54
|
-
format: 'n/a',
|
|
55
|
-
autoGenerationSource: identifierSource,
|
|
56
|
-
identifierSources: [],
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
50
|
'Nyc',
|
|
60
51
|
new AbortController(),
|
|
61
52
|
);
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
CapturePhotoProps,
|
|
11
11
|
PatientIdentifier,
|
|
12
12
|
PatientIdentifierValue,
|
|
13
|
+
PatientRegistration,
|
|
13
14
|
} from './patient-registration-types';
|
|
14
15
|
import {
|
|
15
16
|
addPatientIdentifier,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
import isEqual from 'lodash-es/isEqual';
|
|
25
26
|
|
|
26
27
|
export type SavePatientForm = (
|
|
27
|
-
|
|
28
|
+
isNewPatient: boolean,
|
|
28
29
|
values: FormValues,
|
|
29
30
|
patientUuidMap: PatientUuidMapType,
|
|
30
31
|
initialAddressFieldValues: Record<string, any>,
|
|
@@ -38,7 +39,7 @@ export type SavePatientForm = (
|
|
|
38
39
|
|
|
39
40
|
export default class FormManager {
|
|
40
41
|
static async savePatientFormOffline(
|
|
41
|
-
|
|
42
|
+
isNewPatient: boolean,
|
|
42
43
|
values: FormValues,
|
|
43
44
|
patientUuidMap: PatientUuidMapType,
|
|
44
45
|
initialAddressFieldValues: Record<string, any>,
|
|
@@ -48,10 +49,12 @@ export default class FormManager {
|
|
|
48
49
|
currentLocation: string,
|
|
49
50
|
personAttributeSections: any,
|
|
50
51
|
): Promise<null> {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const syncItem: PatientRegistration = {
|
|
53
|
+
fhirPatient: FormManager.mapPatientToFhirPatient(
|
|
54
|
+
FormManager.getPatientToCreate(values, personAttributeSections, patientUuidMap, initialAddressFieldValues, []),
|
|
55
|
+
),
|
|
56
|
+
_patientRegistrationData: {
|
|
57
|
+
isNewPatient,
|
|
55
58
|
formValues: values,
|
|
56
59
|
patientUuidMap,
|
|
57
60
|
initialAddressFieldValues,
|
|
@@ -61,18 +64,19 @@ export default class FormManager {
|
|
|
61
64
|
currentLocation,
|
|
62
65
|
personAttributeSections,
|
|
63
66
|
},
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
await queueSynchronizationItem(patientRegistration, syncItem, {
|
|
70
|
+
id: values.patientUuid,
|
|
71
|
+
displayName: 'Patient registration',
|
|
72
|
+
dependencies: [],
|
|
73
|
+
});
|
|
70
74
|
|
|
71
75
|
return null;
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
static async savePatientFormOnline(
|
|
75
|
-
|
|
79
|
+
isNewPatient: boolean,
|
|
76
80
|
values: FormValues,
|
|
77
81
|
patientUuidMap: PatientUuidMapType,
|
|
78
82
|
initialAddressFieldValues: Record<string, any>,
|
|
@@ -83,19 +87,13 @@ export default class FormManager {
|
|
|
83
87
|
personAttributeSections: any,
|
|
84
88
|
abortController: AbortController,
|
|
85
89
|
): Promise<string> {
|
|
86
|
-
const patientIdentifiers: PatientIdentifier
|
|
90
|
+
const patientIdentifiers: Array<PatientIdentifier> = await FormManager.savePatientIdentifiers(
|
|
91
|
+
values.patientUuid,
|
|
87
92
|
values.identifiers,
|
|
88
|
-
identifierTypes,
|
|
89
93
|
currentLocation,
|
|
90
94
|
abortController,
|
|
91
95
|
);
|
|
92
96
|
|
|
93
|
-
if (patientUuid) {
|
|
94
|
-
await Promise.all(
|
|
95
|
-
FormManager.savePatientIdentifiers(patientUuid, patientIdentifiers, values.identifiers, abortController),
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
97
|
const createdPatient = FormManager.getPatientToCreate(
|
|
100
98
|
values,
|
|
101
99
|
personAttributeSections,
|
|
@@ -104,11 +102,15 @@ export default class FormManager {
|
|
|
104
102
|
patientIdentifiers,
|
|
105
103
|
);
|
|
106
104
|
|
|
107
|
-
FormManager.getDeletedNames(patientUuidMap).forEach(async (name) => {
|
|
105
|
+
FormManager.getDeletedNames(values.patientUuid, patientUuidMap).forEach(async (name) => {
|
|
108
106
|
await deletePersonName(name.nameUuid, name.personUuid, abortController);
|
|
109
107
|
});
|
|
110
108
|
|
|
111
|
-
const savePatientResponse = await savePatient(
|
|
109
|
+
const savePatientResponse = await savePatient(
|
|
110
|
+
abortController,
|
|
111
|
+
createdPatient,
|
|
112
|
+
isNewPatient ? undefined : values.patientUuid,
|
|
113
|
+
);
|
|
112
114
|
|
|
113
115
|
if (savePatientResponse.ok) {
|
|
114
116
|
await Promise.all(
|
|
@@ -144,41 +146,39 @@ export default class FormManager {
|
|
|
144
146
|
return savePatientResponse.data.uuid;
|
|
145
147
|
}
|
|
146
148
|
|
|
147
|
-
static
|
|
148
|
-
|
|
149
|
-
|
|
149
|
+
static async savePatientIdentifiers(
|
|
150
|
+
patientUuid: string,
|
|
151
|
+
patientIdentifiers: Array<PatientIdentifierValue>, // values.identifiers
|
|
150
152
|
location: string,
|
|
151
153
|
abortController: AbortController,
|
|
152
154
|
): Promise<Array<PatientIdentifier>> {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
if (identifier) {
|
|
158
|
-
|
|
155
|
+
let identifierTypeRequests = patientIdentifiers
|
|
156
|
+
.filter((identifier) => identifier.action !== 'DELETE' && identifier.action !== 'NONE')
|
|
157
|
+
.map(async (patientIdentifier) => {
|
|
158
|
+
const { identifierTypeUuid, identifier, uuid, action, source, preferred, autoGeneration } = patientIdentifier;
|
|
159
|
+
if (identifier || (source && autoGeneration)) {
|
|
160
|
+
const identifierValue = identifier
|
|
161
|
+
? identifier
|
|
162
|
+
: await (
|
|
163
|
+
await generateIdentifier(patientIdentifier.source.uuid, abortController)
|
|
164
|
+
).data.identifier;
|
|
165
|
+
const identifierToCreate = {
|
|
159
166
|
uuid,
|
|
160
|
-
identifier,
|
|
167
|
+
identifier: identifierValue,
|
|
161
168
|
identifierType: identifierTypeUuid,
|
|
162
|
-
location: location,
|
|
163
|
-
preferred: identifierType?.isPrimary,
|
|
164
|
-
};
|
|
165
|
-
} else if (source && patientIdentifier?.autoGeneration) {
|
|
166
|
-
const generateIdentifierResponse = await generateIdentifier(patientIdentifier.source.uuid, abortController);
|
|
167
|
-
return {
|
|
168
|
-
// is this undefined?
|
|
169
|
-
uuid,
|
|
170
|
-
identifier: generateIdentifierResponse.data.identifier,
|
|
171
|
-
identifierType: identifierTypeUuid,
|
|
172
|
-
location: location,
|
|
173
|
-
preferred: identifierType?.isPrimary,
|
|
174
|
-
};
|
|
175
|
-
} else if (action === 'DELETE') {
|
|
176
|
-
return {
|
|
177
|
-
uuid,
|
|
178
|
-
identifier: identifierTypeUuid,
|
|
179
169
|
location,
|
|
180
|
-
preferred
|
|
170
|
+
preferred,
|
|
181
171
|
};
|
|
172
|
+
|
|
173
|
+
if (patientUuid) {
|
|
174
|
+
if (action === 'ADD') {
|
|
175
|
+
await addPatientIdentifier(patientUuid, identifierToCreate, abortController);
|
|
176
|
+
} else if (action === 'UPDATE') {
|
|
177
|
+
await updatePatientIdentifier(patientUuid, uuid, identifierToCreate.identifier, abortController);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return identifierToCreate;
|
|
182
182
|
} else {
|
|
183
183
|
// This is a case that should not occur.
|
|
184
184
|
// If it did, the subsequent network request (when creating the patient) would fail with
|
|
@@ -186,18 +186,26 @@ export default class FormManager {
|
|
|
186
186
|
// Better stop early.
|
|
187
187
|
throw new Error('No approach for generating a patient identifier could be found.');
|
|
188
188
|
}
|
|
189
|
-
}
|
|
190
|
-
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
if (patientUuid) {
|
|
192
|
+
patientIdentifiers
|
|
193
|
+
.filter((patientIdentifier) => patientIdentifier.action === 'DELETE')
|
|
194
|
+
.forEach(
|
|
195
|
+
async (patientIdentifier) =>
|
|
196
|
+
await deletePatientIdentifier(patientUuid, patientIdentifier.uuid, abortController),
|
|
197
|
+
);
|
|
198
|
+
}
|
|
191
199
|
|
|
192
200
|
return Promise.all(identifierTypeRequests);
|
|
193
201
|
}
|
|
194
202
|
|
|
195
|
-
static getDeletedNames(patientUuidMap: PatientUuidMapType) {
|
|
203
|
+
static getDeletedNames(patientUuid: string, patientUuidMap: PatientUuidMapType) {
|
|
196
204
|
if (patientUuidMap?.additionalNameUuid) {
|
|
197
205
|
return [
|
|
198
206
|
{
|
|
199
207
|
nameUuid: patientUuidMap.additionalNameUuid,
|
|
200
|
-
personUuid:
|
|
208
|
+
personUuid: patientUuid,
|
|
201
209
|
},
|
|
202
210
|
];
|
|
203
211
|
}
|
|
@@ -218,9 +226,9 @@ export default class FormManager {
|
|
|
218
226
|
}
|
|
219
227
|
|
|
220
228
|
return {
|
|
221
|
-
uuid:
|
|
229
|
+
uuid: values.patientUuid,
|
|
222
230
|
person: {
|
|
223
|
-
uuid:
|
|
231
|
+
uuid: values.patientUuid,
|
|
224
232
|
names: FormManager.getNames(values, patientUuidMap),
|
|
225
233
|
gender: values.gender.charAt(0),
|
|
226
234
|
birthdate: values.birthdate,
|
|
@@ -293,20 +301,44 @@ export default class FormManager {
|
|
|
293
301
|
};
|
|
294
302
|
}
|
|
295
303
|
|
|
296
|
-
static
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}
|
|
304
|
+
static mapPatientToFhirPatient(patient: Partial<Patient>): fhir.Patient {
|
|
305
|
+
// Important:
|
|
306
|
+
// When changing this code, ideally assume that `patient` can be missing any attribute.
|
|
307
|
+
// The `fhir.Patient` provides us with the benefit that all properties are nullable and thus
|
|
308
|
+
// not required (technically, at least). -> Even if we cannot map some props here, we still
|
|
309
|
+
// provide a valid fhir.Patient object. The various patient chart modules should be able to handle
|
|
310
|
+
// such missing props correctly (and should be updated if they don't).
|
|
311
|
+
|
|
312
|
+
// Gender in the original object only uses a single letter. fhir.Patient expects a full string.
|
|
313
|
+
const genderMap = {
|
|
314
|
+
M: 'male',
|
|
315
|
+
F: 'female',
|
|
316
|
+
O: 'other',
|
|
317
|
+
U: 'unknown',
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// Mapping inspired by:
|
|
321
|
+
// https://github.com/openmrs/openmrs-module-fhir/blob/669b3c52220bb9abc622f815f4dc0d8523687a57/api/src/main/java/org/openmrs/module/fhir/api/util/FHIRPatientUtil.java#L36
|
|
322
|
+
// https://github.com/openmrs/openmrs-esm-patient-management/blob/94e6f637fb37cf4984163c355c5981ea6b8ca38c/packages/esm-patient-search-app/src/patient-search-result/patient-search-result.component.tsx#L21
|
|
323
|
+
// Update as required.
|
|
324
|
+
return {
|
|
325
|
+
id: patient.uuid,
|
|
326
|
+
gender: genderMap[patient.person?.gender],
|
|
327
|
+
birthDate: patient.person?.birthdate,
|
|
328
|
+
deceasedBoolean: patient.person.dead,
|
|
329
|
+
deceasedDateTime: patient.person.deathDate,
|
|
330
|
+
name: patient.person?.names?.map((name) => ({
|
|
331
|
+
given: [name.givenName, name.middleName].filter(Boolean),
|
|
332
|
+
family: name.familyName,
|
|
333
|
+
})),
|
|
334
|
+
address: patient.person?.addresses.map((address) => ({
|
|
335
|
+
city: address.cityVillage,
|
|
336
|
+
country: address.country,
|
|
337
|
+
postalCode: address.postalCode,
|
|
338
|
+
state: address.stateProvince,
|
|
339
|
+
use: 'home',
|
|
340
|
+
})),
|
|
341
|
+
telecom: patient.person.attributes?.filter((attribute) => attribute.attributeType === 'Telephone Number'),
|
|
342
|
+
};
|
|
311
343
|
}
|
|
312
344
|
}
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
-
import { TextInput } from 'carbon-components-react';
|
|
2
|
+
import { TextInput, TextInputProps } from 'carbon-components-react';
|
|
3
3
|
import { useField } from 'formik';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
|
-
interface InputProps {
|
|
7
|
-
id: string;
|
|
8
|
-
name: string;
|
|
9
|
-
labelText: string;
|
|
10
|
-
light: boolean;
|
|
11
|
-
disabled?: boolean;
|
|
12
|
-
placeholder?: string;
|
|
6
|
+
interface InputProps extends TextInputProps {
|
|
13
7
|
checkWarning?(value: string): string;
|
|
14
8
|
}
|
|
15
9
|
|
package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as Yup from 'yup';
|
|
2
1
|
import React, { useState, useEffect, useCallback, useContext, useMemo } from 'react';
|
|
3
2
|
import styles from '../../input.scss';
|
|
4
3
|
import { useTranslation } from 'react-i18next';
|
|
5
4
|
import { Input } from '../../basic-input/input/input.component';
|
|
6
5
|
import { PatientIdentifierValue } from '../../../patient-registration-types';
|
|
7
6
|
import { PatientRegistrationContext } from '../../../patient-registration-context';
|
|
8
|
-
import { TrashCan16, Edit16
|
|
7
|
+
import { TrashCan16, Edit16 } from '@carbon/icons-react';
|
|
9
8
|
import { Button } from 'carbon-components-react';
|
|
10
9
|
import { ResourcesContext } from '../../../../offline.resources';
|
|
10
|
+
import { showModal } from '@openmrs/esm-framework';
|
|
11
11
|
|
|
12
12
|
interface IdentifierInputProps {
|
|
13
13
|
patientIdentifier: PatientIdentifierValue;
|
|
@@ -16,23 +16,21 @@ interface IdentifierInputProps {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export const IdentifierInput: React.FC<IdentifierInputProps> = ({ patientIdentifier, index, remove }) => {
|
|
19
|
-
const {
|
|
19
|
+
const { identifierTypes } = useContext(ResourcesContext);
|
|
20
20
|
const identifierType = useMemo(
|
|
21
|
-
() => identifierTypes.find((identifierType) => identifierType.uuid === patientIdentifier.
|
|
22
|
-
[patientIdentifier],
|
|
21
|
+
() => identifierTypes.find((identifierType) => identifierType.uuid === patientIdentifier.identifierTypeUuid),
|
|
22
|
+
[patientIdentifier, identifierTypes],
|
|
23
23
|
);
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
const { setFieldValue } = React.useContext(PatientRegistrationContext);
|
|
25
26
|
const { source, action, identifier } = patientIdentifier;
|
|
26
|
-
const identifierName = identifierType
|
|
27
|
+
const identifierName = identifierType?.name;
|
|
27
28
|
const fieldName = `identifiers[${index}].identifier`;
|
|
28
29
|
const { t } = useTranslation();
|
|
29
30
|
const [option, setAutoGenerationOption] = useState({
|
|
30
31
|
manualEntryEnabled: source ? true : undefined,
|
|
31
32
|
automaticGenerationEnabled: undefined,
|
|
32
33
|
});
|
|
33
|
-
const [identifierValidationSchema, setIdentifierValidationSchema] = useState(Yup.object({}));
|
|
34
|
-
// This will save the value, if value is to be restored is needed
|
|
35
|
-
const [restoredValue, setRestoredValue] = useState(patientIdentifier.identifier);
|
|
36
34
|
|
|
37
35
|
useEffect(() => {
|
|
38
36
|
if (source && source.autoGenerationOption && source.autoGenerationOption.automaticGenerationEnabled) {
|
|
@@ -61,16 +59,15 @@ export const IdentifierInput: React.FC<IdentifierInputProps> = ({ patientIdentif
|
|
|
61
59
|
manualEntryEnabled: true,
|
|
62
60
|
automaticGenerationEnabled: false,
|
|
63
61
|
});
|
|
64
|
-
setFieldValue(`identifiers[${index}].autoGeneration`,
|
|
62
|
+
setFieldValue(`identifiers[${index}].autoGeneration`, false);
|
|
65
63
|
}
|
|
66
64
|
}, [source]);
|
|
67
65
|
|
|
68
66
|
const handleEdit = useCallback(() => {
|
|
69
|
-
setRestoredValue(patientIdentifier.identifier);
|
|
70
67
|
setFieldValue(`identifiers[${index}]`, {
|
|
71
68
|
...patientIdentifier,
|
|
72
69
|
action: 'UPDATE',
|
|
73
|
-
source: identifierType
|
|
70
|
+
source: identifierType?.identifierSources?.[0],
|
|
74
71
|
} as PatientIdentifierValue);
|
|
75
72
|
}, [patientIdentifier]);
|
|
76
73
|
|
|
@@ -78,18 +75,18 @@ export const IdentifierInput: React.FC<IdentifierInputProps> = ({ patientIdentif
|
|
|
78
75
|
if (action === 'ADD') {
|
|
79
76
|
remove(index);
|
|
80
77
|
} else {
|
|
81
|
-
|
|
78
|
+
const confirmDeleteIdentifierModal = showModal('delete-identifier-confirmation-modal', {
|
|
79
|
+
deleteIdentifier: (deleteIdentifier) => {
|
|
80
|
+
if (deleteIdentifier) {
|
|
81
|
+
setFieldValue(`identifiers[${index}].action`, 'DELETE');
|
|
82
|
+
}
|
|
83
|
+
confirmDeleteIdentifierModal();
|
|
84
|
+
},
|
|
85
|
+
identifierName,
|
|
86
|
+
identifierValue: identifier,
|
|
87
|
+
});
|
|
82
88
|
}
|
|
83
|
-
}, [patientIdentifier]);
|
|
84
|
-
|
|
85
|
-
const handleUndo = useCallback(() => {
|
|
86
|
-
setFieldValue(`identifiers[${index}]`, {
|
|
87
|
-
...patientIdentifier,
|
|
88
|
-
action: 'NONE',
|
|
89
|
-
source: null,
|
|
90
|
-
identifier: restoredValue,
|
|
91
|
-
} as PatientIdentifierValue);
|
|
92
|
-
}, [patientIdentifier, restoredValue]);
|
|
89
|
+
}, [action, patientIdentifier, identifierName, identifier]);
|
|
93
90
|
|
|
94
91
|
const autoGenerated = !option.manualEntryEnabled || (option.manualEntryEnabled && option.automaticGenerationEnabled);
|
|
95
92
|
|
|
@@ -107,6 +104,7 @@ export const IdentifierInput: React.FC<IdentifierInputProps> = ({ patientIdentif
|
|
|
107
104
|
labelText={identifierName}
|
|
108
105
|
name={fieldName}
|
|
109
106
|
disabled={!option.manualEntryEnabled}
|
|
107
|
+
required
|
|
110
108
|
/>
|
|
111
109
|
) : (
|
|
112
110
|
<div className={styles.textID}>
|
|
@@ -117,16 +115,7 @@ export const IdentifierInput: React.FC<IdentifierInputProps> = ({ patientIdentif
|
|
|
117
115
|
</div>
|
|
118
116
|
)}
|
|
119
117
|
<div>
|
|
120
|
-
{patientIdentifier.action === '
|
|
121
|
-
<Button
|
|
122
|
-
kind="ghost"
|
|
123
|
-
onClick={handleUndo}
|
|
124
|
-
iconDescription={t('restoreIdentifierTooltip', 'Restore')}
|
|
125
|
-
hasIconOnly>
|
|
126
|
-
<Undo16 />
|
|
127
|
-
</Button>
|
|
128
|
-
)}
|
|
129
|
-
{patientIdentifier.action === 'NONE' && (
|
|
118
|
+
{!(identifierType.isPrimary || identifierType.required) && patientIdentifier.action === 'NONE' && (
|
|
130
119
|
<Button kind="ghost" onClick={handleEdit} iconDescription={t('editIdentifierTooltip', 'Edit')} hasIconOnly>
|
|
131
120
|
<Edit16 />
|
|
132
121
|
</Button>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { v4 } from 'uuid';
|
|
2
3
|
import { FormValues } from '../../patient-registration-types';
|
|
3
4
|
import styles from './../input.scss';
|
|
4
5
|
|
|
@@ -7,6 +8,7 @@ interface DummyDataInputProps {
|
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export const dummyFormValues: FormValues = {
|
|
11
|
+
patientUuid: v4(),
|
|
10
12
|
givenName: 'John',
|
|
11
13
|
middleName: '',
|
|
12
14
|
familyName: 'Smith',
|
|
@@ -1,71 +1,81 @@
|
|
|
1
1
|
import { getSynchronizationItems, usePatient } from '@openmrs/esm-framework';
|
|
2
2
|
import { Dispatch, useEffect, useState } from 'react';
|
|
3
|
+
import { v4 } from 'uuid';
|
|
3
4
|
import { patientRegistration } from '../constants';
|
|
4
|
-
import {
|
|
5
|
-
FormValues,
|
|
6
|
-
PatientIdentifierValue,
|
|
7
|
-
PatientRegistration,
|
|
8
|
-
PatientUuidMapType,
|
|
9
|
-
} from './patient-registration-types';
|
|
5
|
+
import { FormValues, PatientRegistration, PatientUuidMapType } from './patient-registration-types';
|
|
10
6
|
import {
|
|
11
7
|
getAddressFieldValuesFromFhirPatient,
|
|
12
8
|
getFormValuesFromFhirPatient,
|
|
13
|
-
|
|
9
|
+
getInitialPatientIdentifiers,
|
|
14
10
|
getPatientUuidMapFromFhirPatient,
|
|
15
11
|
getPhonePersonAttributeValueFromFhirPatient,
|
|
16
12
|
} from './patient-registration-utils';
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
fallback = blankFormValues,
|
|
49
|
-
): [FormValues, Dispatch<FormValues>] {
|
|
50
|
-
const { isLoading, patient } = usePatient(patientUuid);
|
|
51
|
-
const [initialFormValues, setInitialFormValues] = useState<FormValues>(fallback);
|
|
14
|
+
export function useInitialFormValues(patientUuid: string): [FormValues, Dispatch<FormValues>] {
|
|
15
|
+
const { isLoading: isLoadingPatientToEdit, patient: patientToEdit } = usePatient(patientUuid);
|
|
16
|
+
const [initialFormValues, setInitialFormValues] = useState<FormValues>({
|
|
17
|
+
patientUuid: v4(),
|
|
18
|
+
givenName: '',
|
|
19
|
+
middleName: '',
|
|
20
|
+
familyName: '',
|
|
21
|
+
unidentifiedPatient: false,
|
|
22
|
+
additionalGivenName: '',
|
|
23
|
+
additionalMiddleName: '',
|
|
24
|
+
additionalFamilyName: '',
|
|
25
|
+
addNameInLocalLanguage: false,
|
|
26
|
+
gender: '',
|
|
27
|
+
birthdate: null,
|
|
28
|
+
yearsEstimated: 0,
|
|
29
|
+
monthsEstimated: 0,
|
|
30
|
+
birthdateEstimated: false,
|
|
31
|
+
telephoneNumber: '',
|
|
32
|
+
address1: '',
|
|
33
|
+
address2: '',
|
|
34
|
+
cityVillage: '',
|
|
35
|
+
stateProvince: '',
|
|
36
|
+
country: '',
|
|
37
|
+
postalCode: '',
|
|
38
|
+
isDead: false,
|
|
39
|
+
deathDate: '',
|
|
40
|
+
deathCause: '',
|
|
41
|
+
relationships: [{ relatedPerson: '', relationship: '' }],
|
|
42
|
+
identifiers: [],
|
|
43
|
+
});
|
|
52
44
|
|
|
53
45
|
useEffect(() => {
|
|
54
46
|
(async () => {
|
|
55
|
-
if (
|
|
47
|
+
if (patientToEdit) {
|
|
56
48
|
setInitialFormValues({
|
|
57
49
|
...initialFormValues,
|
|
58
|
-
...getFormValuesFromFhirPatient(
|
|
59
|
-
...getAddressFieldValuesFromFhirPatient(
|
|
60
|
-
...getPhonePersonAttributeValueFromFhirPatient(
|
|
61
|
-
identifiers: await getPatientIdentifiers(patientUuid),
|
|
50
|
+
...getFormValuesFromFhirPatient(patientToEdit),
|
|
51
|
+
...getAddressFieldValuesFromFhirPatient(patientToEdit),
|
|
52
|
+
...getPhonePersonAttributeValueFromFhirPatient(patientToEdit),
|
|
62
53
|
});
|
|
63
|
-
} else if (!
|
|
54
|
+
} else if (!isLoadingPatientToEdit && patientUuid) {
|
|
64
55
|
const registration = await getPatientRegistration(patientUuid);
|
|
65
|
-
|
|
56
|
+
|
|
57
|
+
if (!registration._patientRegistrationData.formValues) {
|
|
58
|
+
console.error(
|
|
59
|
+
`Found a queued offline patient registration for patient ${patientUuid}, but without form values. Not using these values.`,
|
|
60
|
+
);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setInitialFormValues(registration._patientRegistrationData.formValues);
|
|
66
65
|
}
|
|
67
66
|
})();
|
|
68
|
-
}, [
|
|
67
|
+
}, [isLoadingPatientToEdit, patientToEdit, patientUuid]);
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (patientUuid) {
|
|
71
|
+
getInitialPatientIdentifiers(patientUuid).then((identifiers) =>
|
|
72
|
+
setInitialFormValues((initialFormValues) => ({
|
|
73
|
+
...initialFormValues,
|
|
74
|
+
identifiers,
|
|
75
|
+
})),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}, [patientUuid]);
|
|
69
79
|
|
|
70
80
|
return [initialFormValues, setInitialFormValues];
|
|
71
81
|
}
|
|
@@ -83,7 +93,7 @@ export function useInitialAddressFieldValues(patientUuid: string, fallback = {})
|
|
|
83
93
|
});
|
|
84
94
|
} else if (!isLoading && patientUuid) {
|
|
85
95
|
const registration = await getPatientRegistration(patientUuid);
|
|
86
|
-
setInitialAddressFieldValues(registration?.initialAddressFieldValues ?? fallback);
|
|
96
|
+
setInitialAddressFieldValues(registration?._patientRegistrationData.initialAddressFieldValues ?? fallback);
|
|
87
97
|
}
|
|
88
98
|
})();
|
|
89
99
|
}, [isLoading, patient, patientUuid]);
|
|
@@ -93,26 +103,25 @@ export function useInitialAddressFieldValues(patientUuid: string, fallback = {})
|
|
|
93
103
|
|
|
94
104
|
export function usePatientUuidMap(
|
|
95
105
|
patientUuid: string,
|
|
96
|
-
fallback = {},
|
|
106
|
+
fallback: PatientUuidMapType = {},
|
|
97
107
|
): [PatientUuidMapType, Dispatch<PatientUuidMapType>] {
|
|
98
|
-
const { isLoading, patient } = usePatient(patientUuid);
|
|
108
|
+
const { isLoading: isLoadingPatientToEdit, patient: patientToEdit } = usePatient(patientUuid);
|
|
99
109
|
const [patientUuidMap, setPatientUuidMap] = useState(fallback);
|
|
100
110
|
|
|
101
111
|
useEffect(() => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}, [isLoading, patient, patientUuid]);
|
|
112
|
+
if (patientToEdit) {
|
|
113
|
+
setPatientUuidMap({ ...patientUuidMap, ...getPatientUuidMapFromFhirPatient(patientToEdit) });
|
|
114
|
+
} else if (!isLoadingPatientToEdit && patientUuid) {
|
|
115
|
+
getPatientRegistration(patientUuid).then((registration) =>
|
|
116
|
+
setPatientUuidMap(registration?._patientRegistrationData.initialAddressFieldValues ?? fallback),
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}, [isLoadingPatientToEdit, patientToEdit, patientUuid]);
|
|
111
120
|
|
|
112
121
|
return [patientUuidMap, setPatientUuidMap];
|
|
113
122
|
}
|
|
114
123
|
|
|
115
124
|
async function getPatientRegistration(patientUuid: string) {
|
|
116
125
|
const items = await getSynchronizationItems<PatientRegistration>(patientRegistration);
|
|
117
|
-
return items.find((item) => item.patientUuid === patientUuid);
|
|
126
|
+
return items.find((item) => item._patientRegistrationData.formValues.patientUuid === patientUuid);
|
|
118
127
|
}
|