@openmrs/esm-patient-registration-app 3.0.2-pre.310 → 3.0.2-pre.316
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/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/401.js +2 -0
- package/dist/401.js.map +1 -0
- 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/932.js +1 -2
- package/dist/932.js.map +1 -1
- package/dist/94.js +1 -1
- package/dist/94.js.map +1 -1
- package/dist/openmrs-esm-patient-registration-app.js +1 -1
- package/dist/openmrs-esm-patient-registration-app.js.buildmanifest.json +76 -76
- package/dist/openmrs-esm-patient-registration-app.js.map +1 -1
- package/package.json +2 -2
- package/src/offline.resources.ts +33 -29
- package/src/offline.ts +9 -9
- package/src/patient-registration/form-manager.ts +71 -22
- package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +2 -0
- package/src/patient-registration/patient-registration-hooks.ts +59 -60
- package/src/patient-registration/patient-registration-types.tsx +20 -10
- package/src/patient-registration/patient-registration-utils.ts +1 -1
- package/src/patient-registration/patient-registration.component.tsx +14 -16
- package/src/patient-registration/patient-registration.resource.tsx +2 -2
- package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +6 -6
- 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/src/offline.resources.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import find from 'lodash-es/find';
|
|
3
3
|
import camelCase from 'lodash-es/camelCase';
|
|
4
|
-
import
|
|
4
|
+
import escapeRegExp from 'lodash-es/escapeRegExp';
|
|
5
|
+
import { FetchResponse, messageOmrsServiceWorker, openmrsFetch, SessionUser } from '@openmrs/esm-framework';
|
|
5
6
|
import { PatientIdentifierType, FetchedPatientIdentifierType } from './patient-registration/patient-registration-types';
|
|
6
7
|
import { mockAutoGenerationOptionsResult } from '../__mocks__/autogenerationoptions.mock';
|
|
7
8
|
import { cacheForOfflineHeaders } from './constants';
|
|
@@ -16,26 +17,20 @@ export interface Resources {
|
|
|
16
17
|
export const ResourcesContext = React.createContext<Resources>(null);
|
|
17
18
|
|
|
18
19
|
export async function fetchCurrentSession(abortController?: AbortController): Promise<FetchResponse<SessionUser>> {
|
|
19
|
-
const { data } = await
|
|
20
|
-
signal: abortController?.signal,
|
|
21
|
-
headers: cacheForOfflineHeaders,
|
|
22
|
-
});
|
|
20
|
+
const { data } = await cacheAndFetch('/ws/rest/v1/session', abortController);
|
|
23
21
|
return data;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
export async function fetchAddressTemplate(abortController?: AbortController) {
|
|
27
|
-
const { data } = await
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
const { data } = await cacheAndFetch(
|
|
26
|
+
'/ws/rest/v1/systemsetting?q=layout.address.format&v=custom:(value)',
|
|
27
|
+
abortController,
|
|
28
|
+
);
|
|
31
29
|
return data;
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
export async function fetchAllRelationshipTypes(abortController?: AbortController) {
|
|
35
|
-
const { data } = await
|
|
36
|
-
signal: abortController?.signal,
|
|
37
|
-
headers: cacheForOfflineHeaders,
|
|
38
|
-
});
|
|
33
|
+
const { data } = await cacheAndFetch('/ws/rest/v1/relationshiptype?v=default', abortController);
|
|
39
34
|
return data;
|
|
40
35
|
}
|
|
41
36
|
|
|
@@ -69,14 +64,14 @@ export async function fetchPatientIdentifierTypesWithSources(
|
|
|
69
64
|
}
|
|
70
65
|
|
|
71
66
|
async function fetchPrimaryIdentifierType(abortController: AbortController): Promise<FetchedPatientIdentifierType> {
|
|
72
|
-
const primaryIdentifierTypeResponse = await
|
|
67
|
+
const primaryIdentifierTypeResponse = await cacheAndFetch(
|
|
73
68
|
'/ws/rest/v1/metadatamapping/termmapping?v=full&code=emr.primaryIdentifierType',
|
|
74
|
-
|
|
69
|
+
abortController,
|
|
75
70
|
);
|
|
76
71
|
|
|
77
|
-
const { data: metadata } = await
|
|
72
|
+
const { data: metadata } = await cacheAndFetch(
|
|
78
73
|
`/ws/rest/v1/patientidentifiertype/${primaryIdentifierTypeResponse.data.results[0].metadataUuid}`,
|
|
79
|
-
|
|
74
|
+
abortController,
|
|
80
75
|
);
|
|
81
76
|
|
|
82
77
|
return {
|
|
@@ -92,25 +87,25 @@ async function fetchPrimaryIdentifierType(abortController: AbortController): Pro
|
|
|
92
87
|
async function fetchSecondaryIdentifierTypes(
|
|
93
88
|
abortController?: AbortController,
|
|
94
89
|
): Promise<Array<FetchedPatientIdentifierType>> {
|
|
95
|
-
const secondaryIdentifierTypeResponse = await
|
|
90
|
+
const secondaryIdentifierTypeResponse = await cacheAndFetch(
|
|
96
91
|
'/ws/rest/v1/metadatamapping/termmapping?v=full&code=emr.extraPatientIdentifierTypes',
|
|
97
|
-
|
|
92
|
+
abortController,
|
|
98
93
|
);
|
|
99
94
|
|
|
100
95
|
if (secondaryIdentifierTypeResponse.data.results) {
|
|
101
96
|
const extraIdentifierTypesSetUuid = secondaryIdentifierTypeResponse.data.results[0].metadataUuid;
|
|
102
|
-
const metadataResponse = await
|
|
97
|
+
const metadataResponse = await cacheAndFetch(
|
|
103
98
|
`/ws/rest/v1/metadatamapping/metadataset/${extraIdentifierTypesSetUuid}/members`,
|
|
104
|
-
|
|
99
|
+
abortController,
|
|
105
100
|
);
|
|
106
101
|
|
|
107
102
|
if (metadataResponse.data.results) {
|
|
108
103
|
return await Promise.all(
|
|
109
104
|
metadataResponse.data.results.map(async (setMember) => {
|
|
110
|
-
const type = await
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
const type = await cacheAndFetch(
|
|
106
|
+
`/ws/rest/v1/patientidentifiertype/${setMember.metadataUuid}`,
|
|
107
|
+
abortController,
|
|
108
|
+
);
|
|
114
109
|
|
|
115
110
|
return {
|
|
116
111
|
name: type.data.name,
|
|
@@ -129,10 +124,10 @@ async function fetchSecondaryIdentifierTypes(
|
|
|
129
124
|
}
|
|
130
125
|
|
|
131
126
|
async function fetchIdentifierSources(identifierType: string, abortController?: AbortController) {
|
|
132
|
-
return await
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
127
|
+
return await cacheAndFetch(
|
|
128
|
+
`/ws/rest/v1/idgen/identifiersource?v=full&identifierType=${identifierType}`,
|
|
129
|
+
abortController,
|
|
130
|
+
);
|
|
136
131
|
}
|
|
137
132
|
|
|
138
133
|
function fetchAutoGenerationOptions(identifierType: string, abortController?: AbortController) {
|
|
@@ -142,3 +137,12 @@ function fetchAutoGenerationOptions(identifierType: string, abortController?: Ab
|
|
|
142
137
|
// });‚
|
|
143
138
|
return Promise.resolve(mockAutoGenerationOptionsResult);
|
|
144
139
|
}
|
|
140
|
+
|
|
141
|
+
async function cacheAndFetch(url: string, abortController?: AbortController) {
|
|
142
|
+
await messageOmrsServiceWorker({
|
|
143
|
+
type: 'registerDynamicRoute',
|
|
144
|
+
pattern: escapeRegExp(url),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
return await openmrsFetch(url, { headers: cacheForOfflineHeaders, signal: abortController?.signal });
|
|
148
|
+
}
|
package/src/offline.ts
CHANGED
|
@@ -41,15 +41,15 @@ export async function syncPatientRegistration(
|
|
|
41
41
|
options: SyncProcessOptions<PatientRegistration>,
|
|
42
42
|
) {
|
|
43
43
|
await FormManager.savePatientFormOnline(
|
|
44
|
-
|
|
45
|
-
queuedPatient.formValues,
|
|
46
|
-
queuedPatient.patientUuidMap,
|
|
47
|
-
queuedPatient.initialAddressFieldValues,
|
|
48
|
-
queuedPatient.identifierTypes,
|
|
49
|
-
queuedPatient.capturePhotoProps,
|
|
50
|
-
queuedPatient.patientPhotoConceptUuid,
|
|
51
|
-
queuedPatient.currentLocation,
|
|
52
|
-
queuedPatient.personAttributeSections,
|
|
44
|
+
queuedPatient._patientRegistrationData.isNewPatient,
|
|
45
|
+
queuedPatient._patientRegistrationData.formValues,
|
|
46
|
+
queuedPatient._patientRegistrationData.patientUuidMap,
|
|
47
|
+
queuedPatient._patientRegistrationData.initialAddressFieldValues,
|
|
48
|
+
queuedPatient._patientRegistrationData.identifierTypes,
|
|
49
|
+
queuedPatient._patientRegistrationData.capturePhotoProps,
|
|
50
|
+
queuedPatient._patientRegistrationData.patientPhotoConceptUuid,
|
|
51
|
+
queuedPatient._patientRegistrationData.currentLocation,
|
|
52
|
+
queuedPatient._patientRegistrationData.personAttributeSections,
|
|
53
53
|
options.abort,
|
|
54
54
|
);
|
|
55
55
|
}
|
|
@@ -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>,
|
|
@@ -90,9 +94,9 @@ export default class FormManager {
|
|
|
90
94
|
abortController,
|
|
91
95
|
);
|
|
92
96
|
|
|
93
|
-
if (
|
|
97
|
+
if (!isNewPatient) {
|
|
94
98
|
await Promise.all(
|
|
95
|
-
FormManager.savePatientIdentifiers(patientUuid, patientIdentifiers, values.identifiers, abortController),
|
|
99
|
+
FormManager.savePatientIdentifiers(values.patientUuid, patientIdentifiers, values.identifiers, abortController),
|
|
96
100
|
);
|
|
97
101
|
}
|
|
98
102
|
|
|
@@ -104,11 +108,15 @@ export default class FormManager {
|
|
|
104
108
|
patientIdentifiers,
|
|
105
109
|
);
|
|
106
110
|
|
|
107
|
-
FormManager.getDeletedNames(patientUuidMap).forEach(async (name) => {
|
|
111
|
+
FormManager.getDeletedNames(values.patientUuid, patientUuidMap).forEach(async (name) => {
|
|
108
112
|
await deletePersonName(name.nameUuid, name.personUuid, abortController);
|
|
109
113
|
});
|
|
110
114
|
|
|
111
|
-
const savePatientResponse = await savePatient(
|
|
115
|
+
const savePatientResponse = await savePatient(
|
|
116
|
+
abortController,
|
|
117
|
+
createdPatient,
|
|
118
|
+
isNewPatient ? undefined : values.patientUuid,
|
|
119
|
+
);
|
|
112
120
|
|
|
113
121
|
if (savePatientResponse.ok) {
|
|
114
122
|
await Promise.all(
|
|
@@ -145,7 +153,7 @@ export default class FormManager {
|
|
|
145
153
|
}
|
|
146
154
|
|
|
147
155
|
static getPatientIdentifiersToCreate(
|
|
148
|
-
patientIdentifiers: PatientIdentifierValue[],
|
|
156
|
+
patientIdentifiers: PatientIdentifierValue[],
|
|
149
157
|
identifierTypes: Array<PatientIdentifierType>,
|
|
150
158
|
location: string,
|
|
151
159
|
abortController: AbortController,
|
|
@@ -192,12 +200,12 @@ export default class FormManager {
|
|
|
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,
|
|
@@ -309,4 +317,45 @@ export default class FormManager {
|
|
|
309
317
|
}
|
|
310
318
|
});
|
|
311
319
|
}
|
|
320
|
+
|
|
321
|
+
static mapPatientToFhirPatient(patient: Partial<Patient>): fhir.Patient {
|
|
322
|
+
// Important:
|
|
323
|
+
// When changing this code, ideally assume that `patient` can be missing any attribute.
|
|
324
|
+
// The `fhir.Patient` provides us with the benefit that all properties are nullable and thus
|
|
325
|
+
// not required (technically, at least). -> Even if we cannot map some props here, we still
|
|
326
|
+
// provide a valid fhir.Patient object. The various patient chart modules should be able to handle
|
|
327
|
+
// such missing props correctly (and should be updated if they don't).
|
|
328
|
+
|
|
329
|
+
// Gender in the original object only uses a single letter. fhir.Patient expects a full string.
|
|
330
|
+
const genderMap = {
|
|
331
|
+
M: 'male',
|
|
332
|
+
F: 'female',
|
|
333
|
+
O: 'other',
|
|
334
|
+
U: 'unknown',
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// Mapping inspired by:
|
|
338
|
+
// https://github.com/openmrs/openmrs-module-fhir/blob/669b3c52220bb9abc622f815f4dc0d8523687a57/api/src/main/java/org/openmrs/module/fhir/api/util/FHIRPatientUtil.java#L36
|
|
339
|
+
// 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
|
|
340
|
+
// Update as required.
|
|
341
|
+
return {
|
|
342
|
+
id: patient.uuid,
|
|
343
|
+
gender: genderMap[patient.person?.gender],
|
|
344
|
+
birthDate: patient.person?.birthdate,
|
|
345
|
+
deceasedBoolean: patient.person.dead,
|
|
346
|
+
deceasedDateTime: patient.person.deathDate,
|
|
347
|
+
name: patient.person?.names?.map((name) => ({
|
|
348
|
+
given: [name.givenName, name.middleName].filter(Boolean),
|
|
349
|
+
family: name.familyName,
|
|
350
|
+
})),
|
|
351
|
+
address: patient.person?.addresses.map((address) => ({
|
|
352
|
+
city: address.cityVillage,
|
|
353
|
+
country: address.country,
|
|
354
|
+
postalCode: address.postalCode,
|
|
355
|
+
state: address.stateProvince,
|
|
356
|
+
use: 'home',
|
|
357
|
+
})),
|
|
358
|
+
telecom: patient.person.attributes?.filter((attribute) => attribute.attributeType === 'Telephone Number'),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
312
361
|
}
|
|
@@ -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,12 +1,8 @@
|
|
|
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,
|
|
@@ -15,57 +11,61 @@ import {
|
|
|
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(
|
|
50
|
+
...getFormValuesFromFhirPatient(patientToEdit),
|
|
51
|
+
...getAddressFieldValuesFromFhirPatient(patientToEdit),
|
|
52
|
+
...getPhonePersonAttributeValueFromFhirPatient(patientToEdit),
|
|
61
53
|
identifiers: await getPatientIdentifiers(patientUuid),
|
|
62
54
|
});
|
|
63
|
-
} else if (!
|
|
55
|
+
} else if (!isLoadingPatientToEdit && patientUuid) {
|
|
64
56
|
const registration = await getPatientRegistration(patientUuid);
|
|
65
|
-
|
|
57
|
+
|
|
58
|
+
if (!registration._patientRegistrationData.formValues) {
|
|
59
|
+
console.error(
|
|
60
|
+
`Found a queued offline patient registration for patient ${patientUuid}, but without form values. Not using these values.`,
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
setInitialFormValues(registration._patientRegistrationData.formValues);
|
|
66
66
|
}
|
|
67
67
|
})();
|
|
68
|
-
}, [
|
|
68
|
+
}, [isLoadingPatientToEdit, patientToEdit, patientUuid]);
|
|
69
69
|
|
|
70
70
|
return [initialFormValues, setInitialFormValues];
|
|
71
71
|
}
|
|
@@ -83,7 +83,7 @@ export function useInitialAddressFieldValues(patientUuid: string, fallback = {})
|
|
|
83
83
|
});
|
|
84
84
|
} else if (!isLoading && patientUuid) {
|
|
85
85
|
const registration = await getPatientRegistration(patientUuid);
|
|
86
|
-
setInitialAddressFieldValues(registration?.initialAddressFieldValues ?? fallback);
|
|
86
|
+
setInitialAddressFieldValues(registration?._patientRegistrationData.initialAddressFieldValues ?? fallback);
|
|
87
87
|
}
|
|
88
88
|
})();
|
|
89
89
|
}, [isLoading, patient, patientUuid]);
|
|
@@ -93,26 +93,25 @@ export function useInitialAddressFieldValues(patientUuid: string, fallback = {})
|
|
|
93
93
|
|
|
94
94
|
export function usePatientUuidMap(
|
|
95
95
|
patientUuid: string,
|
|
96
|
-
fallback = {},
|
|
96
|
+
fallback: PatientUuidMapType = {},
|
|
97
97
|
): [PatientUuidMapType, Dispatch<PatientUuidMapType>] {
|
|
98
|
-
const { isLoading, patient } = usePatient(patientUuid);
|
|
98
|
+
const { isLoading: isLoadingPatientToEdit, patient: patientToEdit } = usePatient(patientUuid);
|
|
99
99
|
const [patientUuidMap, setPatientUuidMap] = useState(fallback);
|
|
100
100
|
|
|
101
101
|
useEffect(() => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}, [isLoading, patient, patientUuid]);
|
|
102
|
+
if (patientToEdit) {
|
|
103
|
+
setPatientUuidMap({ ...patientUuidMap, ...getPatientUuidMapFromFhirPatient(patientToEdit) });
|
|
104
|
+
} else if (!isLoadingPatientToEdit && patientUuid) {
|
|
105
|
+
getPatientRegistration(patientUuid).then((registration) =>
|
|
106
|
+
setPatientUuidMap(registration?._patientRegistrationData.initialAddressFieldValues ?? fallback),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}, [isLoadingPatientToEdit, patientToEdit, patientUuid]);
|
|
111
110
|
|
|
112
111
|
return [patientUuidMap, setPatientUuidMap];
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
async function getPatientRegistration(patientUuid: string) {
|
|
116
115
|
const items = await getSynchronizationItems<PatientRegistration>(patientRegistration);
|
|
117
|
-
return items.find((item) => item.patientUuid === patientUuid);
|
|
116
|
+
return items.find((item) => item._patientRegistrationData.formValues.patientUuid === patientUuid);
|
|
118
117
|
}
|
|
@@ -38,15 +38,25 @@ export interface PatientIdentifierValue {
|
|
|
38
38
|
|
|
39
39
|
export interface PatientRegistration {
|
|
40
40
|
id?: number;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
/**
|
|
42
|
+
* The preliminary patient in the FHIR format.
|
|
43
|
+
*/
|
|
44
|
+
fhirPatient: fhir.Patient;
|
|
45
|
+
/**
|
|
46
|
+
* Internal data collected by patient-registration. Required for later syncing and editing.
|
|
47
|
+
* Not supposed to be used outside of this module.
|
|
48
|
+
*/
|
|
49
|
+
_patientRegistrationData: {
|
|
50
|
+
isNewPatient: boolean;
|
|
51
|
+
formValues: FormValues;
|
|
52
|
+
patientUuidMap: PatientUuidMapType;
|
|
53
|
+
initialAddressFieldValues: Record<string, any>;
|
|
54
|
+
identifierTypes: Array<PatientIdentifierType>;
|
|
55
|
+
capturePhotoProps: CapturePhotoProps;
|
|
56
|
+
patientPhotoConceptUuid: string;
|
|
57
|
+
currentLocation: string;
|
|
58
|
+
personAttributeSections: any;
|
|
59
|
+
};
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
/**
|
|
@@ -100,6 +110,7 @@ export interface IdentifierSource {
|
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
export interface FormValues {
|
|
113
|
+
patientUuid: string;
|
|
103
114
|
givenName: string;
|
|
104
115
|
middleName: string;
|
|
105
116
|
familyName: string;
|
|
@@ -129,7 +140,6 @@ export interface FormValues {
|
|
|
129
140
|
|
|
130
141
|
export interface PatientUuidMapType {
|
|
131
142
|
additionalNameUuid?: string;
|
|
132
|
-
patientUuid?: string;
|
|
133
143
|
preferredNameUuid?: string;
|
|
134
144
|
preferredAddressUuid?: string;
|
|
135
145
|
}
|
|
@@ -73,6 +73,7 @@ export function getFormValuesFromFhirPatient(patient: fhir.Patient) {
|
|
|
73
73
|
const patientName = patient.name[0];
|
|
74
74
|
const additionalPatientName = patient.name[1];
|
|
75
75
|
|
|
76
|
+
result.patientUuid = patient.id;
|
|
76
77
|
result.givenName = patientName?.given[0];
|
|
77
78
|
result.middleName = patientName?.given[1];
|
|
78
79
|
result.familyName = patientName?.family;
|
|
@@ -142,7 +143,6 @@ export function getPatientUuidMapFromFhirPatient(patient: fhir.Patient): Patient
|
|
|
142
143
|
const address = patient.address?.[0];
|
|
143
144
|
|
|
144
145
|
return {
|
|
145
|
-
patientUuid: patient.id,
|
|
146
146
|
preferredNameUuid: patientName?.id,
|
|
147
147
|
additionalNameUuid: additionalPatientName?.id,
|
|
148
148
|
preferredAddressUuid: address?.id,
|
|
@@ -36,21 +36,21 @@ export const PatientRegistration: React.FC<PatientRegistrationProps> = ({ savePa
|
|
|
36
36
|
const { currentSession, addressTemplate, patientIdentifiers } = useContext(ResourcesContext);
|
|
37
37
|
const { search } = useLocation();
|
|
38
38
|
const config = useConfig();
|
|
39
|
-
const { patientUuid } = match.params;
|
|
40
39
|
const [sections, setSections] = useState([]);
|
|
41
40
|
const [target, setTarget] = useState<undefined | string>();
|
|
42
41
|
const [validationSchema, setValidationSchema] = useState(initialSchema);
|
|
43
|
-
const {
|
|
42
|
+
const { patientUuid: uuidOfPatientToEdit } = match.params;
|
|
43
|
+
const { isLoading: isLoadingPatientToEdit, patient: patientToEdit } = usePatient(uuidOfPatientToEdit);
|
|
44
44
|
const { t } = useTranslation();
|
|
45
45
|
const [capturePhotoProps, setCapturePhotoProps] = useState<CapturePhotoProps | null>(null);
|
|
46
46
|
const [fieldConfigs, setFieldConfigs] = useState({});
|
|
47
|
-
const [initialFormValues, setInitialFormValues] = useInitialFormValues(
|
|
48
|
-
const [initialAddressFieldValues] = useInitialAddressFieldValues(
|
|
49
|
-
const [patientUuidMap] = usePatientUuidMap(
|
|
47
|
+
const [initialFormValues, setInitialFormValues] = useInitialFormValues(uuidOfPatientToEdit);
|
|
48
|
+
const [initialAddressFieldValues] = useInitialAddressFieldValues(uuidOfPatientToEdit);
|
|
49
|
+
const [patientUuidMap] = usePatientUuidMap(uuidOfPatientToEdit);
|
|
50
50
|
const location = currentSession.sessionLocation?.uuid;
|
|
51
|
-
const inEditMode =
|
|
51
|
+
const inEditMode = isLoadingPatientToEdit ? undefined : !!(uuidOfPatientToEdit && patientToEdit);
|
|
52
52
|
const showDummyData = useMemo(() => localStorage.getItem('openmrs:devtools') === 'true' && !inEditMode, [inEditMode]);
|
|
53
|
-
const { data: photo } = usePatientPhoto(
|
|
53
|
+
const { data: photo } = usePatientPhoto(patientToEdit?.id);
|
|
54
54
|
|
|
55
55
|
useEffect(() => {
|
|
56
56
|
exportedInitialFormValuesForTesting = initialFormValues;
|
|
@@ -98,8 +98,8 @@ export const PatientRegistration: React.FC<PatientRegistrationProps> = ({ savePa
|
|
|
98
98
|
helpers.setSubmitting(true);
|
|
99
99
|
|
|
100
100
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
await savePatientForm(
|
|
102
|
+
!inEditMode,
|
|
103
103
|
values,
|
|
104
104
|
patientUuidMap,
|
|
105
105
|
initialAddressFieldValues,
|
|
@@ -124,14 +124,12 @@ export const PatientRegistration: React.FC<PatientRegistrationProps> = ({ savePa
|
|
|
124
124
|
kind: 'success',
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
);
|
|
127
|
+
const redirectUrl = interpolateUrl(
|
|
128
|
+
new URLSearchParams(search).get('afterUrl') ||
|
|
129
|
+
interpolateString(config.links.submitButton, { patientUuid: values.patientUuid }),
|
|
130
|
+
);
|
|
132
131
|
|
|
133
|
-
|
|
134
|
-
}
|
|
132
|
+
setTarget(redirectUrl);
|
|
135
133
|
} catch (error) {
|
|
136
134
|
if (error.responseBody?.error?.globalErrors) {
|
|
137
135
|
error.responseBody.error.globalErrors.forEach((error) => {
|
|
@@ -19,8 +19,8 @@ function dataURItoFile(dataURI: string) {
|
|
|
19
19
|
return new File([blob], 'patient-photo.png');
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export function savePatient(abortController: AbortController, patient: Patient,
|
|
23
|
-
return openmrsFetch(`/ws/rest/v1/patient/${
|
|
22
|
+
export function savePatient(abortController: AbortController, patient: Patient, updatePatientUuid?: string) {
|
|
23
|
+
return openmrsFetch(`/ws/rest/v1/patient/${updatePatientUuid || ''}`, {
|
|
24
24
|
headers: {
|
|
25
25
|
'Content-Type': 'application/json',
|
|
26
26
|
},
|