@ampath/esm-patient-registration-app 9.2.0-next.18 → 9.2.0-next.20
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/1453.js +1 -0
- package/dist/1453.js.map +1 -0
- package/dist/4300.js +1 -1
- package/dist/5365.js +2 -0
- package/dist/5365.js.map +1 -0
- package/dist/6168.js +1 -0
- package/dist/6168.js.map +1 -0
- package/dist/6583.js +1 -0
- package/dist/6583.js.map +1 -0
- package/dist/7821.js +1 -1
- package/dist/8414.js +1 -1
- package/dist/8414.js.map +1 -1
- package/dist/8487.js +1 -0
- package/dist/8487.js.map +1 -0
- package/dist/main.js +1 -1
- package/dist/openmrs-esm-patient-registration-app.js +1 -1
- package/dist/openmrs-esm-patient-registration-app.js.buildmanifest.json +129 -129
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/patient-registration/client-registry/client-registry-search.component.tsx +9 -48
- package/src/patient-registration/client-registry/client-registry.resource.ts +8 -29
- package/src/patient-registration/client-registry/constants/civil-status.ts +29 -0
- package/src/patient-registration/client-registry/constants/person-attribute-types.ts +21 -0
- package/src/patient-registration/client-registry/existing-client/client-dependants-comparison/client-dependants-comparison.component.tsx +26 -0
- package/src/patient-registration/client-registry/existing-client/client-dependants-comparison/dependant-comparison-rows.component.tsx +153 -0
- package/src/patient-registration/client-registry/existing-client/client-details-comparison/client-details-comparison.component.tsx +181 -0
- package/src/patient-registration/client-registry/existing-client/client-details-comparison/comparison-table-row.component.tsx +42 -0
- package/src/patient-registration/client-registry/existing-client/client-registry-verification-tag.component.tsx +54 -0
- package/src/patient-registration/client-registry/existing-client/existing-client-tab.component.tsx +85 -0
- package/src/patient-registration/client-registry/existing-client/existing-client.resource.ts +78 -0
- package/src/patient-registration/client-registry/existing-client/mapper-utils.ts +419 -0
- package/src/patient-registration/{client-registry-search/client-registry.types.ts → client-registry/existing-client/types/index.ts} +91 -149
- package/src/patient-registration/client-registry/hie-client-adapter.ts +289 -1
- package/src/patient-registration/client-registry/mock-client.ts +627 -0
- package/src/patient-registration/client-registry/{client-dependants → new-client/client-dependants}/list/client-depandants.component.tsx +1 -1
- package/src/patient-registration/client-registry/{client-details → new-client/client-details}/client-details.tsx +2 -2
- package/src/patient-registration/client-registry/new-client/new-client-registration/new-client-registration.scss +25 -0
- package/src/patient-registration/client-registry/new-client/new-client-registration/new-client-registration.tsx +272 -0
- package/src/patient-registration/client-registry/new-client/new-client-tab.component.tsx +32 -0
- package/src/patient-registration/client-registry/new-client/registration-form-data.ts +251 -0
- package/src/patient-registration/client-registry/types/index.ts +324 -6
- package/src/patient-registration/client-registry-search/client-registry-dependant-details.component.tsx +1 -1
- package/src/patient-registration/client-registry-search/client-registry-details.component.tsx +1 -1
- package/src/patient-registration/client-registry-search/client-registry-patient-details.component.tsx +1 -1
- package/src/patient-registration/client-registry-search/client-registry-search.component.tsx +1 -1
- package/src/patient-registration/client-registry-search/client-registry-verification-tag.component.tsx +1 -1
- package/src/patient-registration/client-registry-search/client-registry.resource.ts +16 -3
- package/src/patient-registration/client-registry-search/map-client-registry-to-form-utils.ts +1 -1
- package/src/patient-registration/patient-registration.component.tsx +1 -0
- package/src/widgets/client-registry-verification.modal.tsx +13 -0
- package/translations/en.json +1 -0
- package/dist/4395.js +0 -1
- package/dist/4395.js.map +0 -1
- package/dist/5239.js +0 -2
- package/dist/5239.js.map +0 -1
- package/dist/6741.js +0 -1
- package/dist/6741.js.map +0 -1
- package/dist/8882.js +0 -1
- package/dist/8882.js.map +0 -1
- package/dist/9898.js +0 -1
- package/dist/9898.js.map +0 -1
- /package/dist/{5239.js.LICENSE.txt → 5365.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const SEPARATED_UUID = 'a899aba0-1350-11df-a1f1-0026b9348838';
|
|
2
|
+
const NEVER_MARRIED_UUID = 'a899ac7c-1350-11df-a1f1-0026b9348838';
|
|
3
|
+
const DIVORCED_UUID = 'a899ad58-1350-11df-a1f1-0026b9348838';
|
|
4
|
+
const WIDOWED_UUID = 'a899ae34-1350-11df-a1f1-0026b9348838';
|
|
5
|
+
const MARRIED_UUID = 'a8aa76b0-1350-11df-a1f1-0026b9348838';
|
|
6
|
+
const LIVING_WITH_PARTNER_UUID = 'a899af10-1350-11df-a1f1-0026b9348838';
|
|
7
|
+
const FRIEND_UUID = 'a8aaf07c-1350-11df-a1f1-0026b9348838';
|
|
8
|
+
const NOT_APPLICABLE_UUID = 'a89ad3a4-1350-11df-a1f1-0026b9348838';
|
|
9
|
+
const POLYGAMOUS_UUID = 'a8b03712-1350-11df-a1f1-0026b9348838';
|
|
10
|
+
const PARTNER_UUID = 'a89ebd3e-1350-11df-a1f1-0026b9348838';
|
|
11
|
+
const CASUAL_SEX_PARTNER_UUID = '7831f002-331d-4f07-bf91-6bb65cd31050';
|
|
12
|
+
const OTHER_UUID = 'a8aaf3e2-1350-11df-a1f1-0026b9348838';
|
|
13
|
+
const SINGLE_UUID = 'a899ac7c-1350-11df-a1f1-0026b9348838';
|
|
14
|
+
|
|
15
|
+
export const CivilStatusUids = {
|
|
16
|
+
SEPARATED_UUID,
|
|
17
|
+
NEVER_MARRIED_UUID,
|
|
18
|
+
DIVORCED_UUID,
|
|
19
|
+
WIDOWED_UUID,
|
|
20
|
+
MARRIED_UUID,
|
|
21
|
+
LIVING_WITH_PARTNER_UUID,
|
|
22
|
+
FRIEND_UUID,
|
|
23
|
+
NOT_APPLICABLE_UUID,
|
|
24
|
+
POLYGAMOUS_UUID,
|
|
25
|
+
PARTNER_UUID,
|
|
26
|
+
CASUAL_SEX_PARTNER_UUID,
|
|
27
|
+
SINGLE_UUID,
|
|
28
|
+
OTHER_UUID,
|
|
29
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const CONTACT_PHONE_NUMBER_UUID = '72a759a8-1359-11df-a1f1-0026b9348838';
|
|
2
|
+
const CITIZENSHIP_UUID = '72a759a8-1359-11df-a1f1-0026b9348838';
|
|
3
|
+
const CONTACT_EMAIL_ADDRESS_UUID = '2f65dbcb-3e58-45a3-8be7-fd1dc9aa0faa';
|
|
4
|
+
const ALTERNATIVE_CONTACT_PHONE_NUMBER_UUID = 'c725f524-c14a-4468-ac19-4a0e6661c930';
|
|
5
|
+
const KRA_PIN_UUID = 'ae683747-b3fc-4e5c-bad3-c3be743b248f';
|
|
6
|
+
const CIVIL_STATUS_UUID = '8d871f2a-c2cc-11de-8d13-0010c6dffd0f';
|
|
7
|
+
const CLIENT_REGISTRY_ID_UUID = 'e068e02b-faac-4baf-bd58-fe6e0c29a81f';
|
|
8
|
+
const PLACE_OF_BIRTH_UUID = '8d8718c2-c2cc-11de-8d13-0010c6dffd0f';
|
|
9
|
+
const EMAIL_UUID = '2f65dbcb-3e58-45a3-8be7-fd1dc9aa0faa';
|
|
10
|
+
|
|
11
|
+
export const PersonAttributeTypeUuids = {
|
|
12
|
+
CONTACT_PHONE_NUMBER_UUID,
|
|
13
|
+
CITIZENSHIP_UUID,
|
|
14
|
+
CONTACT_EMAIL_ADDRESS_UUID,
|
|
15
|
+
ALTERNATIVE_CONTACT_PHONE_NUMBER_UUID,
|
|
16
|
+
KRA_PIN_UUID,
|
|
17
|
+
CIVIL_STATUS_UUID,
|
|
18
|
+
CLIENT_REGISTRY_ID_UUID,
|
|
19
|
+
PLACE_OF_BIRTH_UUID,
|
|
20
|
+
EMAIL_UUID,
|
|
21
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Accordion } from '@carbon/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { type ClientDependantsComparisonProps } from '../types';
|
|
4
|
+
import ClientDependantComparisonRows from './dependant-comparison-rows.component';
|
|
5
|
+
|
|
6
|
+
const ClientDependantsComparison: React.FC<ClientDependantsComparisonProps> = ({
|
|
7
|
+
hieDependants,
|
|
8
|
+
amrsClient,
|
|
9
|
+
patientRelationships,
|
|
10
|
+
}) => {
|
|
11
|
+
return (
|
|
12
|
+
<div>
|
|
13
|
+
<Accordion size="lg">
|
|
14
|
+
{hieDependants.map((dependant) => (
|
|
15
|
+
<ClientDependantComparisonRows
|
|
16
|
+
hieDependant={dependant}
|
|
17
|
+
amrsClient={amrsClient}
|
|
18
|
+
patientRelationships={patientRelationships}
|
|
19
|
+
/>
|
|
20
|
+
))}
|
|
21
|
+
</Accordion>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default ClientDependantsComparison;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { AccordionItem, Row, Column, Select, SelectItem, Button } from '@carbon/react';
|
|
2
|
+
import { showSnackbar } from '@openmrs/esm-framework';
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { createPerson, createRelationship, fetchAmrsPersonData } from '../existing-client.resource';
|
|
6
|
+
import {
|
|
7
|
+
patientObjFields,
|
|
8
|
+
mapFieldValue,
|
|
9
|
+
getPatientAttributes,
|
|
10
|
+
personSyncFields,
|
|
11
|
+
nameFields,
|
|
12
|
+
addressFields,
|
|
13
|
+
getPatientRelationshipPayload,
|
|
14
|
+
} from '../mapper-utils';
|
|
15
|
+
import { type AmrsClient, type ClientDependantComparisonRowsProps } from '../types';
|
|
16
|
+
import { type HieDependant } from '../../types';
|
|
17
|
+
import ClientDetailsComparison from '../client-details-comparison/client-details-comparison.component';
|
|
18
|
+
|
|
19
|
+
const ClientDependantComparisonRows: React.FC<ClientDependantComparisonRowsProps> = ({
|
|
20
|
+
hieDependant,
|
|
21
|
+
patientRelationships,
|
|
22
|
+
amrsClient,
|
|
23
|
+
}) => {
|
|
24
|
+
const { t } = useTranslation();
|
|
25
|
+
const [amrsRelationExists, setAmrsRelationExists] = useState(false);
|
|
26
|
+
const [amrsDependantData, setAmrsDependantData] = useState<AmrsClient>();
|
|
27
|
+
const [selectedRelationship, setSelectedRelationship] = useState('');
|
|
28
|
+
|
|
29
|
+
const handleCreateDependant = async (dependantBody: HieDependant) => {
|
|
30
|
+
try {
|
|
31
|
+
const syncFields = {};
|
|
32
|
+
patientObjFields.forEach((field) => {
|
|
33
|
+
let fieldArr = mapFieldValue(field, dependantBody.result[0], amrsClient);
|
|
34
|
+
const hieFieldValue = fieldArr[1];
|
|
35
|
+
syncFields[field] = hieFieldValue;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Person
|
|
39
|
+
const patientPayload = {};
|
|
40
|
+
const names = {};
|
|
41
|
+
const addresses = {};
|
|
42
|
+
const otherFields = {};
|
|
43
|
+
const attributes = getPatientAttributes(dependantBody.result[0]);
|
|
44
|
+
Object.entries(syncFields).forEach(([k, v]) => {
|
|
45
|
+
if (personSyncFields.includes(k)) {
|
|
46
|
+
// names
|
|
47
|
+
if (nameFields.includes(k)) {
|
|
48
|
+
names[k] = v;
|
|
49
|
+
}
|
|
50
|
+
// addresses
|
|
51
|
+
else if (addressFields.includes(k)) {
|
|
52
|
+
if (v) {
|
|
53
|
+
addresses[k] = v;
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
otherFields[k] = v;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
Object.assign(
|
|
61
|
+
patientPayload,
|
|
62
|
+
otherFields,
|
|
63
|
+
{ addresses: [addresses] },
|
|
64
|
+
{ names: [names] },
|
|
65
|
+
{ attributes: attributes },
|
|
66
|
+
);
|
|
67
|
+
const response = await createPerson(patientPayload);
|
|
68
|
+
if (response && response.data) {
|
|
69
|
+
showSnackbar({
|
|
70
|
+
kind: 'success',
|
|
71
|
+
title: 'Dependant created successfully.',
|
|
72
|
+
});
|
|
73
|
+
const relationshipPayload = getPatientRelationshipPayload(
|
|
74
|
+
amrsClient,
|
|
75
|
+
dependantBody.relationship,
|
|
76
|
+
response.data.uuid,
|
|
77
|
+
);
|
|
78
|
+
await createRelationship(relationshipPayload);
|
|
79
|
+
showSnackbar({
|
|
80
|
+
kind: 'success',
|
|
81
|
+
title: 'Dependant relationship created successfully.',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
} catch (err) {
|
|
85
|
+
showSnackbar({
|
|
86
|
+
kind: 'error',
|
|
87
|
+
title: 'Error syncing patient data.',
|
|
88
|
+
subtitle: JSON.stringify(err),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const handleSelectAmrsDependant = async (e: any) => {
|
|
94
|
+
const uuid = e.target.value;
|
|
95
|
+
if (!uuid) {
|
|
96
|
+
setAmrsRelationExists(false);
|
|
97
|
+
setAmrsDependantData(null);
|
|
98
|
+
}
|
|
99
|
+
const response = await fetchAmrsPersonData(uuid);
|
|
100
|
+
if (response && response.data) {
|
|
101
|
+
setAmrsRelationExists(true);
|
|
102
|
+
setAmrsDependantData((prev) => ({ ...prev, person: response.data }));
|
|
103
|
+
} else {
|
|
104
|
+
setAmrsRelationExists(false);
|
|
105
|
+
setAmrsDependantData(null);
|
|
106
|
+
const relationshipUuid = patientRelationships.find((v) => v.relatedPersonUuid === uuid);
|
|
107
|
+
if (relationshipUuid && relationshipUuid.relationshipType) {
|
|
108
|
+
setSelectedRelationship(relationshipUuid.relationshipType);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const getDependantName = () => {
|
|
114
|
+
const name = hieDependant.result[0];
|
|
115
|
+
return `${name.first_name} ${name.middle_name} ${name.last_name} (${hieDependant.relationship})`;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<>
|
|
120
|
+
<AccordionItem title={getDependantName()}>
|
|
121
|
+
<Row>
|
|
122
|
+
<Column>
|
|
123
|
+
<Select labelText={t('amrsDependants', 'AMRS dependants')} onChange={handleSelectAmrsDependant}>
|
|
124
|
+
<SelectItem text={t('selectAmrsRelation', 'Select AMRS relation')} value="" />
|
|
125
|
+
{patientRelationships.map((relationship) => (
|
|
126
|
+
<SelectItem
|
|
127
|
+
text={`${relationship.display} (${relationship.relationshipType})`}
|
|
128
|
+
value={relationship.relatedPerson.uuid}
|
|
129
|
+
/>
|
|
130
|
+
))}
|
|
131
|
+
</Select>
|
|
132
|
+
</Column>
|
|
133
|
+
{!amrsRelationExists ? (
|
|
134
|
+
<Column>
|
|
135
|
+
<Button onClick={() => handleCreateDependant(hieDependant)}>
|
|
136
|
+
{t('createDependant', 'Create dependant in AMRS')}
|
|
137
|
+
</Button>
|
|
138
|
+
</Column>
|
|
139
|
+
) : null}
|
|
140
|
+
</Row>
|
|
141
|
+
<Row>
|
|
142
|
+
<ClientDetailsComparison
|
|
143
|
+
hieClient={hieDependant.result[0]}
|
|
144
|
+
amrsClient={amrsDependantData}
|
|
145
|
+
fromDependant={true}
|
|
146
|
+
/>
|
|
147
|
+
</Row>
|
|
148
|
+
</AccordionItem>
|
|
149
|
+
</>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export default ClientDependantComparisonRows;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { type ClientDetailsComparisonProps } from '../types';
|
|
3
|
+
import {
|
|
4
|
+
Row,
|
|
5
|
+
Button,
|
|
6
|
+
InlineLoading,
|
|
7
|
+
Table,
|
|
8
|
+
TableHead,
|
|
9
|
+
TableRow,
|
|
10
|
+
TableHeader,
|
|
11
|
+
Checkbox,
|
|
12
|
+
TableBody,
|
|
13
|
+
} from '@carbon/react';
|
|
14
|
+
import { showSnackbar } from '@openmrs/esm-framework';
|
|
15
|
+
import { HieIdentificationType } from '../../types';
|
|
16
|
+
import {
|
|
17
|
+
personSyncFields,
|
|
18
|
+
nameFields,
|
|
19
|
+
addressFields,
|
|
20
|
+
identifiersSyncFields,
|
|
21
|
+
getIdentifierUuid,
|
|
22
|
+
patientObjFields,
|
|
23
|
+
mapFieldValue,
|
|
24
|
+
} from '../mapper-utils';
|
|
25
|
+
import ComparisonTableRow from './comparison-table-row.component';
|
|
26
|
+
import { updateAmrsPersonIdentifiers, updatePerson } from '../existing-client.resource';
|
|
27
|
+
|
|
28
|
+
const ClientDetailsComparison: React.FC<ClientDetailsComparisonProps> = ({ hieClient, amrsClient, fromDependant }) => {
|
|
29
|
+
const [syncFields, setSyncFields] = useState<Array<Record<string, string>>>([]);
|
|
30
|
+
const [allChecked, setAllChecked] = useState(false);
|
|
31
|
+
const [loading, setLoading] = useState(false);
|
|
32
|
+
const locationUuid = '18c343eb-b353-462a-9139-b16606e6b6c2';
|
|
33
|
+
const randomString = Math.random().toString(10).substring(2, 6).toUpperCase();
|
|
34
|
+
|
|
35
|
+
const handleFieldChange = (checked: boolean, field: string, value: string, multiple: boolean) => {
|
|
36
|
+
if (multiple) {
|
|
37
|
+
if (checked) {
|
|
38
|
+
setSyncFields((prev) => [...prev, { [field]: value }]);
|
|
39
|
+
} else {
|
|
40
|
+
setSyncFields([]);
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
if (checked) {
|
|
44
|
+
setSyncFields([...syncFields, { [field]: value }]);
|
|
45
|
+
} else {
|
|
46
|
+
setSyncFields((prev) => prev.filter((p) => !Object.keys(p).includes(field)));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const handleCheckAll = (e) => {
|
|
52
|
+
setAllChecked(e.target.checked);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const handleSync = async () => {
|
|
56
|
+
try {
|
|
57
|
+
const payload = {};
|
|
58
|
+
syncFields.forEach((field) => {
|
|
59
|
+
let key = Object.keys(field)[0];
|
|
60
|
+
payload[key] = field[key];
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Person
|
|
64
|
+
const patientPayload = {};
|
|
65
|
+
const names = {};
|
|
66
|
+
const addresses = {};
|
|
67
|
+
const otherFields = {};
|
|
68
|
+
Object.entries(payload).forEach(([k, v]) => {
|
|
69
|
+
if (personSyncFields.includes(k)) {
|
|
70
|
+
// names
|
|
71
|
+
if (nameFields.includes(k)) {
|
|
72
|
+
names[k] = v;
|
|
73
|
+
}
|
|
74
|
+
// addresses
|
|
75
|
+
else if (addressFields.includes(k)) {
|
|
76
|
+
if (v) {
|
|
77
|
+
addresses[k] = v;
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
otherFields[k] = v;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
Object.assign(patientPayload, otherFields, { addresses: [addresses] }, { names: [names] });
|
|
85
|
+
await updatePerson(amrsClient.person.uuid, patientPayload);
|
|
86
|
+
showSnackbar({
|
|
87
|
+
kind: 'success',
|
|
88
|
+
title: 'Patient successfully synced.',
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Identifiers
|
|
92
|
+
Object.entries(payload).forEach(async ([k, v]) => {
|
|
93
|
+
if (identifiersSyncFields().includes(k)) {
|
|
94
|
+
if (v) {
|
|
95
|
+
const identifierUuid = getIdentifierUuid(HieIdentificationType[k]);
|
|
96
|
+
const identifierPayload = {
|
|
97
|
+
identifier: v,
|
|
98
|
+
location: locationUuid,
|
|
99
|
+
identifierType: identifierUuid,
|
|
100
|
+
};
|
|
101
|
+
try {
|
|
102
|
+
// Check if the identifier exists
|
|
103
|
+
if (amrsClient?.person?.identifiers?.find((i) => i.identifierType.uuid === identifierUuid)) {
|
|
104
|
+
// update to have the selected identifier
|
|
105
|
+
await updateAmrsPersonIdentifiers(
|
|
106
|
+
amrsClient.person.uuid,
|
|
107
|
+
identifierUuid + '',
|
|
108
|
+
identifierPayload,
|
|
109
|
+
fromDependant,
|
|
110
|
+
);
|
|
111
|
+
} else {
|
|
112
|
+
// create to have the blank identifier
|
|
113
|
+
await updateAmrsPersonIdentifiers(amrsClient.person.uuid, '', identifierPayload, fromDependant);
|
|
114
|
+
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
showSnackbar({
|
|
117
|
+
kind: 'error',
|
|
118
|
+
title: 'Error syncing patient identifiers.',
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
showSnackbar({
|
|
125
|
+
kind: 'success',
|
|
126
|
+
title: 'Patient identifiers successfully synced.',
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
setSyncFields([]);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
showSnackbar({
|
|
132
|
+
kind: 'error',
|
|
133
|
+
title: 'Error syncing patient data.',
|
|
134
|
+
subtitle: JSON.stringify(err?.error?.message),
|
|
135
|
+
});
|
|
136
|
+
} finally {
|
|
137
|
+
setLoading(false);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<>
|
|
143
|
+
<Table>
|
|
144
|
+
<TableHead>
|
|
145
|
+
<TableRow>
|
|
146
|
+
<TableHeader>Field</TableHeader>
|
|
147
|
+
<TableHeader>AMRS Person</TableHeader>
|
|
148
|
+
<TableHeader>HIE Patient</TableHeader>
|
|
149
|
+
<TableHeader>
|
|
150
|
+
<Checkbox id={`cbox-multiple-${randomString}`} onChange={(e) => handleCheckAll(e)} />
|
|
151
|
+
</TableHeader>
|
|
152
|
+
</TableRow>
|
|
153
|
+
</TableHead>
|
|
154
|
+
<TableBody>
|
|
155
|
+
{patientObjFields.map((field) => {
|
|
156
|
+
const fieldValue = mapFieldValue(field, hieClient, amrsClient);
|
|
157
|
+
const amrsField = fieldValue[0];
|
|
158
|
+
const hieField = fieldValue[1];
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<ComparisonTableRow
|
|
162
|
+
label={field}
|
|
163
|
+
field={field}
|
|
164
|
+
amrsValue={amrsField}
|
|
165
|
+
hieValue={hieField}
|
|
166
|
+
onChange={handleFieldChange}
|
|
167
|
+
allChecked={allChecked}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
})}
|
|
171
|
+
</TableBody>
|
|
172
|
+
</Table>
|
|
173
|
+
<Row>
|
|
174
|
+
{syncFields.length ? <Button onClick={handleSync}>Sync data</Button> : null}
|
|
175
|
+
{loading ? <InlineLoading description="Syncing patient details..." /> : null}
|
|
176
|
+
</Row>
|
|
177
|
+
</>
|
|
178
|
+
);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export default ClientDetailsComparison;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { TableRow, TableCell, Checkbox } from '@carbon/react';
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import { type ComparisonTableRowProps } from '../types';
|
|
4
|
+
|
|
5
|
+
const ComparisonTableRow: React.FC<ComparisonTableRowProps> = ({
|
|
6
|
+
field,
|
|
7
|
+
label,
|
|
8
|
+
amrsValue,
|
|
9
|
+
hieValue,
|
|
10
|
+
onChange,
|
|
11
|
+
allChecked,
|
|
12
|
+
}) => {
|
|
13
|
+
const [checked, setChecked] = useState(false);
|
|
14
|
+
const randomString = Math.random().toString(10).substring(2, 6).toUpperCase();
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
onChange?.(allChecked, field, hieValue, true);
|
|
17
|
+
setChecked(allChecked);
|
|
18
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
19
|
+
}, [allChecked]);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<TableRow>
|
|
23
|
+
<TableCell>
|
|
24
|
+
<p style={{ color: amrsValue!.trim().toUpperCase() == hieValue!.trim().toUpperCase() ? '' : 'red' }}>{label}</p>
|
|
25
|
+
</TableCell>
|
|
26
|
+
<TableCell>{amrsValue}</TableCell>
|
|
27
|
+
<TableCell>{hieValue}</TableCell>
|
|
28
|
+
<TableCell>
|
|
29
|
+
<Checkbox
|
|
30
|
+
id={`cbox-${randomString}`}
|
|
31
|
+
onChange={(e) => {
|
|
32
|
+
onChange(e.target.checked, field, hieValue, false);
|
|
33
|
+
setChecked(e.target.checked);
|
|
34
|
+
}}
|
|
35
|
+
checked={checked}
|
|
36
|
+
/>
|
|
37
|
+
</TableCell>
|
|
38
|
+
</TableRow>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default ComparisonTableRow;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Button } from '@carbon/react';
|
|
3
|
+
import { age, usePatient } from '@openmrs/esm-framework';
|
|
4
|
+
import { Formik } from 'formik';
|
|
5
|
+
import ClientRegistryLookupSection from '../client-registry-search.component';
|
|
6
|
+
|
|
7
|
+
const ClientRegistryVerificationTag = () => {
|
|
8
|
+
const { patient } = usePatient();
|
|
9
|
+
const [showCrBtn, setShowCrBtn] = useState(false);
|
|
10
|
+
const [showVerifyModal, setShowVerifyModal] = useState(false);
|
|
11
|
+
const [isClientVerified, setIsClientVerified] = useState(false);
|
|
12
|
+
const initialFormValues = {};
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (patient && patient.birthDate) {
|
|
16
|
+
const ageArr = age(patient.birthDate).split(' ');
|
|
17
|
+
if (ageArr.includes('yrs')) {
|
|
18
|
+
const yrs = Number(ageArr[0]);
|
|
19
|
+
setShowCrBtn(yrs > 17);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}, [patient]);
|
|
23
|
+
|
|
24
|
+
const openVerifyModal = () => {
|
|
25
|
+
setShowVerifyModal(true);
|
|
26
|
+
};
|
|
27
|
+
const closeVerifyModal = () => {
|
|
28
|
+
setShowVerifyModal(false);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return showCrBtn ? (
|
|
32
|
+
<>
|
|
33
|
+
<Button kind="ghost" style={{ backgroundColor: 'purple', color: 'white' }} onClick={openVerifyModal}>
|
|
34
|
+
Verify CR
|
|
35
|
+
</Button>
|
|
36
|
+
{showVerifyModal ? (
|
|
37
|
+
<Formik enableReinitialize initialValues={initialFormValues} onSubmit={null}>
|
|
38
|
+
<ClientRegistryLookupSection
|
|
39
|
+
onClientVerified={() => setIsClientVerified(true)}
|
|
40
|
+
onModalClose={closeVerifyModal}
|
|
41
|
+
open={showVerifyModal}
|
|
42
|
+
isNewClient={false}
|
|
43
|
+
/>
|
|
44
|
+
</Formik>
|
|
45
|
+
) : (
|
|
46
|
+
<></>
|
|
47
|
+
)}
|
|
48
|
+
</>
|
|
49
|
+
) : (
|
|
50
|
+
<></>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default ClientRegistryVerificationTag;
|
package/src/patient-registration/client-registry/existing-client/existing-client-tab.component.tsx
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { Tabs, TabList, Tab, TabPanels, TabPanel, InlineLoading } from '@carbon/react';
|
|
3
|
+
import { type HieClient } from '../types';
|
|
4
|
+
import ClientDetailsComparison from './client-details-comparison/client-details-comparison.component';
|
|
5
|
+
import { type CustomRelationship, type AmrsClient } from './types';
|
|
6
|
+
import ClientDependantsComparison from './client-dependants-comparison/client-dependants-comparison.component';
|
|
7
|
+
import { showSnackbar, usePatient } from '@openmrs/esm-framework';
|
|
8
|
+
import { fetchAmrsPatientData, getRelationships } from './existing-client.resource';
|
|
9
|
+
|
|
10
|
+
interface ExistingClientTabProps {
|
|
11
|
+
hieClient: HieClient;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ExistingClientTab: React.FC<ExistingClientTabProps> = ({ hieClient }) => {
|
|
15
|
+
const [amrsClient, setAmrsClient] = useState<AmrsClient>();
|
|
16
|
+
const [loading, setLoading] = useState<boolean>(false);
|
|
17
|
+
const { patientUuid } = usePatient();
|
|
18
|
+
const [relationships, setRelationships] = useState<Array<CustomRelationship>>([]);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (patientUuid) {
|
|
22
|
+
handleAmrsPersonDetails();
|
|
23
|
+
handleFetchPatientRelationships();
|
|
24
|
+
}
|
|
25
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
|
+
}, [patientUuid]);
|
|
27
|
+
|
|
28
|
+
const handleFetchPatientRelationships = async () => {
|
|
29
|
+
const resp = await getRelationships(patientUuid);
|
|
30
|
+
if (resp) {
|
|
31
|
+
setRelationships(resp);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const handleAmrsPersonDetails = async () => {
|
|
36
|
+
try {
|
|
37
|
+
setLoading(true);
|
|
38
|
+
const response = await fetchAmrsPatientData(patientUuid);
|
|
39
|
+
if (response) {
|
|
40
|
+
setAmrsClient(response.data);
|
|
41
|
+
}
|
|
42
|
+
showSnackbar({
|
|
43
|
+
kind: 'success',
|
|
44
|
+
title: 'AMRS person data fetched successfully.',
|
|
45
|
+
});
|
|
46
|
+
} catch (er) {
|
|
47
|
+
showSnackbar({
|
|
48
|
+
kind: 'error',
|
|
49
|
+
title: 'Error fetching AMRS person data.',
|
|
50
|
+
subtitle: JSON.stringify(er),
|
|
51
|
+
});
|
|
52
|
+
} finally {
|
|
53
|
+
setLoading(false);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return loading ? (
|
|
58
|
+
<InlineLoading description="Fetching existing client details..." />
|
|
59
|
+
) : (
|
|
60
|
+
<Tabs>
|
|
61
|
+
<TabList contained>
|
|
62
|
+
<Tab>Patient</Tab>
|
|
63
|
+
<Tab>Dependants</Tab>
|
|
64
|
+
</TabList>
|
|
65
|
+
<TabPanels>
|
|
66
|
+
<TabPanel>
|
|
67
|
+
{hieClient && <ClientDetailsComparison hieClient={hieClient} amrsClient={amrsClient} fromDependant={false} />}
|
|
68
|
+
</TabPanel>
|
|
69
|
+
<TabPanel>
|
|
70
|
+
{hieClient && hieClient.dependants ? (
|
|
71
|
+
<ClientDependantsComparison
|
|
72
|
+
hieDependants={hieClient.dependants}
|
|
73
|
+
amrsClient={amrsClient}
|
|
74
|
+
patientRelationships={relationships}
|
|
75
|
+
/>
|
|
76
|
+
) : (
|
|
77
|
+
<div>Dependants not found.</div>
|
|
78
|
+
)}
|
|
79
|
+
</TabPanel>
|
|
80
|
+
</TabPanels>
|
|
81
|
+
</Tabs>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export default ExistingClientTab;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
+
import { type AmrsClient } from './types';
|
|
3
|
+
import { mapAmrsPatientRelationship } from './mapper-utils';
|
|
4
|
+
|
|
5
|
+
export async function fetchAmrsPatientData(patientUuid: string) {
|
|
6
|
+
return await openmrsFetch<AmrsClient>(`${restBaseUrl}/patient/${patientUuid}?v=full`, {
|
|
7
|
+
method: 'GET',
|
|
8
|
+
}).catch((err) => {
|
|
9
|
+
console.error(err);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function updateAmrsPersonIdentifiers(
|
|
14
|
+
patientUuid: string,
|
|
15
|
+
identifierUuid: string,
|
|
16
|
+
payload: unknown,
|
|
17
|
+
fromDependant = false,
|
|
18
|
+
) {
|
|
19
|
+
const resource = fromDependant ? 'person' : 'patient';
|
|
20
|
+
return await openmrsFetch(`${restBaseUrl}/${resource}/${patientUuid}/identifier/${identifierUuid}`, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json',
|
|
24
|
+
},
|
|
25
|
+
body: payload,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function fetchAmrsPersonData(personUuid: string) {
|
|
30
|
+
return await openmrsFetch(`${restBaseUrl}/person/${personUuid}?v=full`, {
|
|
31
|
+
method: 'GET',
|
|
32
|
+
}).catch((err) => {
|
|
33
|
+
console.error(err);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function updatePerson(patientUuid: string, payload: unknown) {
|
|
38
|
+
return await openmrsFetch<AmrsClient>(`${restBaseUrl}/person/${patientUuid}`, {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: {
|
|
41
|
+
'Content-Type': 'application/json',
|
|
42
|
+
},
|
|
43
|
+
body: payload,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function createPerson(payload: unknown) {
|
|
48
|
+
return await openmrsFetch<AmrsClient>(`${restBaseUrl}/person`, {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
},
|
|
53
|
+
body: payload,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function createRelationship(payload: unknown) {
|
|
58
|
+
return await openmrsFetch(`${restBaseUrl}/relationship`, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: {
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
},
|
|
63
|
+
body: payload,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function getRelationships(patientUuid: string) {
|
|
68
|
+
const response = await openmrsFetch(`${restBaseUrl}/relationship?person=${patientUuid}&v=full`, {
|
|
69
|
+
method: 'GET',
|
|
70
|
+
headers: {
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
if (response && response.data) {
|
|
75
|
+
return mapAmrsPatientRelationship(patientUuid, response.data.results);
|
|
76
|
+
}
|
|
77
|
+
return [];
|
|
78
|
+
}
|