@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.
Files changed (63) hide show
  1. package/dist/1453.js +1 -0
  2. package/dist/1453.js.map +1 -0
  3. package/dist/4300.js +1 -1
  4. package/dist/5365.js +2 -0
  5. package/dist/5365.js.map +1 -0
  6. package/dist/6168.js +1 -0
  7. package/dist/6168.js.map +1 -0
  8. package/dist/6583.js +1 -0
  9. package/dist/6583.js.map +1 -0
  10. package/dist/7821.js +1 -1
  11. package/dist/8414.js +1 -1
  12. package/dist/8414.js.map +1 -1
  13. package/dist/8487.js +1 -0
  14. package/dist/8487.js.map +1 -0
  15. package/dist/main.js +1 -1
  16. package/dist/openmrs-esm-patient-registration-app.js +1 -1
  17. package/dist/openmrs-esm-patient-registration-app.js.buildmanifest.json +129 -129
  18. package/dist/routes.json +1 -1
  19. package/package.json +1 -1
  20. package/src/index.ts +1 -1
  21. package/src/patient-registration/client-registry/client-registry-search.component.tsx +9 -48
  22. package/src/patient-registration/client-registry/client-registry.resource.ts +8 -29
  23. package/src/patient-registration/client-registry/constants/civil-status.ts +29 -0
  24. package/src/patient-registration/client-registry/constants/person-attribute-types.ts +21 -0
  25. package/src/patient-registration/client-registry/existing-client/client-dependants-comparison/client-dependants-comparison.component.tsx +26 -0
  26. package/src/patient-registration/client-registry/existing-client/client-dependants-comparison/dependant-comparison-rows.component.tsx +153 -0
  27. package/src/patient-registration/client-registry/existing-client/client-details-comparison/client-details-comparison.component.tsx +181 -0
  28. package/src/patient-registration/client-registry/existing-client/client-details-comparison/comparison-table-row.component.tsx +42 -0
  29. package/src/patient-registration/client-registry/existing-client/client-registry-verification-tag.component.tsx +54 -0
  30. package/src/patient-registration/client-registry/existing-client/existing-client-tab.component.tsx +85 -0
  31. package/src/patient-registration/client-registry/existing-client/existing-client.resource.ts +78 -0
  32. package/src/patient-registration/client-registry/existing-client/mapper-utils.ts +419 -0
  33. package/src/patient-registration/{client-registry-search/client-registry.types.ts → client-registry/existing-client/types/index.ts} +91 -149
  34. package/src/patient-registration/client-registry/hie-client-adapter.ts +289 -1
  35. package/src/patient-registration/client-registry/mock-client.ts +627 -0
  36. package/src/patient-registration/client-registry/{client-dependants → new-client/client-dependants}/list/client-depandants.component.tsx +1 -1
  37. package/src/patient-registration/client-registry/{client-details → new-client/client-details}/client-details.tsx +2 -2
  38. package/src/patient-registration/client-registry/new-client/new-client-registration/new-client-registration.scss +25 -0
  39. package/src/patient-registration/client-registry/new-client/new-client-registration/new-client-registration.tsx +272 -0
  40. package/src/patient-registration/client-registry/new-client/new-client-tab.component.tsx +32 -0
  41. package/src/patient-registration/client-registry/new-client/registration-form-data.ts +251 -0
  42. package/src/patient-registration/client-registry/types/index.ts +324 -6
  43. package/src/patient-registration/client-registry-search/client-registry-dependant-details.component.tsx +1 -1
  44. package/src/patient-registration/client-registry-search/client-registry-details.component.tsx +1 -1
  45. package/src/patient-registration/client-registry-search/client-registry-patient-details.component.tsx +1 -1
  46. package/src/patient-registration/client-registry-search/client-registry-search.component.tsx +1 -1
  47. package/src/patient-registration/client-registry-search/client-registry-verification-tag.component.tsx +1 -1
  48. package/src/patient-registration/client-registry-search/client-registry.resource.ts +16 -3
  49. package/src/patient-registration/client-registry-search/map-client-registry-to-form-utils.ts +1 -1
  50. package/src/patient-registration/patient-registration.component.tsx +1 -0
  51. package/src/widgets/client-registry-verification.modal.tsx +13 -0
  52. package/translations/en.json +1 -0
  53. package/dist/4395.js +0 -1
  54. package/dist/4395.js.map +0 -1
  55. package/dist/5239.js +0 -2
  56. package/dist/5239.js.map +0 -1
  57. package/dist/6741.js +0 -1
  58. package/dist/6741.js.map +0 -1
  59. package/dist/8882.js +0 -1
  60. package/dist/8882.js.map +0 -1
  61. package/dist/9898.js +0 -1
  62. package/dist/9898.js.map +0 -1
  63. /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;
@@ -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
+ }