@kenyaemr/esm-patient-registration-app 8.0.3-pre.131 → 8.0.3-pre.138
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +13 -13
- package/dist/574.js +1 -1
- package/dist/652.js +1 -0
- package/dist/652.js.map +1 -0
- package/dist/kenyaemr-esm-patient-registration-app.js +1 -1
- package/dist/kenyaemr-esm-patient-registration-app.js.buildmanifest.json +34 -34
- package/dist/kenyaemr-esm-patient-registration-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/client-registry/hie-client-registry/dependants/dependants.component.tsx +48 -0
- package/src/client-registry/hie-client-registry/hie-resource.ts +26 -4
- package/src/client-registry/hie-client-registry/modal/confirm-hie.modal.tsx +29 -18
- package/src/client-registry/hie-client-registry/modal/confirm-hie.scss +43 -3
- package/src/client-registry/hie-client-registry/patient-info/patient-info.component.tsx +17 -0
- package/translations/en.json +5 -0
- package/dist/66.js +0 -1
- package/dist/66.js.map +0 -1
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.24.0"},"pages":[{"component":"root","route":"patient-registration","online":true,"offline":true},{"component":"editPatient","routeRegex":"patient\\/([a-zA-Z0-9\\-]+)\\/edit","online":true,"offline":true}],"extensions":[{"component":"addPatientLink","name":"add-patient-action","slot":"top-nav-actions-slot","online":true,"offline":true},{"component":"patientPhotoExtension","name":"patient-photo-widget","slot":"patient-photo-slot","online":true,"offline":true},{"component":"editPatientDetailsButton","name":"edit-patient-details-button","slot":"patient-actions-slot","online":true,"offline":true},{"component":"editPatientDetailsButton","name":"edit-patient-details-button","slot":"patient-search-actions-slot","online":true,"offline":true}],"modals":[{"name":"cancel-patient-edit-modal","component":"cancelPatientEditModal"},{"name":"delete-identifier-confirmation-modal","component":"deleteIdentifierConfirmationModal"},{"component":"emptyClientRegistryModal","name":"empty-client-registry-modal"},{"component":"confirmClientRegistryModal","name":"confirm-client-registry-modal"},{"component":"hieConfirmationModal","name":"hie-confirmation-modal"}],"version":"8.0.3-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.24.0"},"pages":[{"component":"root","route":"patient-registration","online":true,"offline":true},{"component":"editPatient","routeRegex":"patient\\/([a-zA-Z0-9\\-]+)\\/edit","online":true,"offline":true}],"extensions":[{"component":"addPatientLink","name":"add-patient-action","slot":"top-nav-actions-slot","online":true,"offline":true},{"component":"patientPhotoExtension","name":"patient-photo-widget","slot":"patient-photo-slot","online":true,"offline":true},{"component":"editPatientDetailsButton","name":"edit-patient-details-button","slot":"patient-actions-slot","online":true,"offline":true},{"component":"editPatientDetailsButton","name":"edit-patient-details-button","slot":"patient-search-actions-slot","online":true,"offline":true}],"modals":[{"name":"cancel-patient-edit-modal","component":"cancelPatientEditModal"},{"name":"delete-identifier-confirmation-modal","component":"deleteIdentifierConfirmationModal"},{"component":"emptyClientRegistryModal","name":"empty-client-registry-modal"},{"component":"confirmClientRegistryModal","name":"confirm-client-registry-modal"},{"component":"hieConfirmationModal","name":"hie-confirmation-modal"}],"version":"8.0.3-pre.138"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenyaemr/esm-patient-registration-app",
|
|
3
|
-
"version": "8.0.3-pre.
|
|
3
|
+
"version": "8.0.3-pre.138",
|
|
4
4
|
"description": "Patient registration microfrontend for the OpenMRS SPA",
|
|
5
5
|
"browser": "dist/kenyaemr-esm-patient-registration-app.js",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import styles from '../modal/confirm-hie.scss';
|
|
4
|
+
import PatientInfo from '../patient-info/patient-info.component';
|
|
5
|
+
|
|
6
|
+
const DependentInfo: React.FC<{ dependents: any[] }> = ({ dependents }) => {
|
|
7
|
+
const { t } = useTranslation();
|
|
8
|
+
|
|
9
|
+
if (dependents && dependents.length > 0) {
|
|
10
|
+
return (
|
|
11
|
+
<div>
|
|
12
|
+
<span className={styles.header}>{t('dependants', 'Dependants')}</span>
|
|
13
|
+
{dependents.map((dependent, index) => {
|
|
14
|
+
const name = dependent?.name?.text;
|
|
15
|
+
const relationship =
|
|
16
|
+
dependent?.relationship?.[0]?.coding?.[0]?.display || t('unknownRelationship', 'Unknown');
|
|
17
|
+
const nationalID = dependent?.extension?.find(
|
|
18
|
+
(ext) =>
|
|
19
|
+
ext.url === 'http://cr.tiberbu.app/fhir/StructureDefinition/dependants-id-number' &&
|
|
20
|
+
ext.valueIdentifier?.type?.coding?.[0]?.code === 'national-id',
|
|
21
|
+
)?.valueIdentifier?.value;
|
|
22
|
+
const birthCertificate = dependent?.extension?.find(
|
|
23
|
+
(ext) =>
|
|
24
|
+
ext.url === 'http://cr.tiberbu.app/fhir/StructureDefinition/dependants-id-number' &&
|
|
25
|
+
ext.valueIdentifier?.type?.coding?.[0]?.code === 'birth-certificate-number',
|
|
26
|
+
)?.valueIdentifier?.value;
|
|
27
|
+
|
|
28
|
+
const primaryIdentifier = nationalID || birthCertificate;
|
|
29
|
+
const identifierLabel = nationalID
|
|
30
|
+
? t('nationalID', 'National ID')
|
|
31
|
+
: t('birthCertificate', 'Birth Certificate');
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div key={index} className={styles.dependentInfo}>
|
|
35
|
+
<PatientInfo label={t('name', 'Name')} value={name} />
|
|
36
|
+
<PatientInfo label={t('relationship', 'Relationship')} value={relationship} />
|
|
37
|
+
<PatientInfo label={identifierLabel} value={primaryIdentifier} />
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
})}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default DependentInfo;
|
|
@@ -35,7 +35,7 @@ class Mapper<T, U> {
|
|
|
35
35
|
*/
|
|
36
36
|
class PatientMapper extends Mapper<HIEPatient, FormValues> {
|
|
37
37
|
mapHIEPatientToFormValues(hiePatient: HIEPatient, currentFormValues: FormValues): FormValues {
|
|
38
|
-
const
|
|
38
|
+
const { familyName, givenName, middleName } = getPatientName(hiePatient);
|
|
39
39
|
const telecom = hiePatient.telecom || [];
|
|
40
40
|
|
|
41
41
|
const telecomAttributes = this.mapTelecomToAttributes(telecom);
|
|
@@ -46,10 +46,10 @@ class PatientMapper extends Mapper<HIEPatient, FormValues> {
|
|
|
46
46
|
isDead: hiePatient.deceasedBoolean || false,
|
|
47
47
|
gender: hiePatient.gender || '',
|
|
48
48
|
birthdate: hiePatient.birthDate || '',
|
|
49
|
-
givenName
|
|
50
|
-
familyName
|
|
49
|
+
givenName,
|
|
50
|
+
familyName,
|
|
51
51
|
telephoneNumber: telecom.find((t) => t.system === 'phone')?.value || '',
|
|
52
|
-
middleName
|
|
52
|
+
middleName,
|
|
53
53
|
address: extensionAddressEntries,
|
|
54
54
|
identifiers: updatedIdentifiers,
|
|
55
55
|
attributes: telecomAttributes,
|
|
@@ -160,3 +160,25 @@ export const fetchPatientFromHIE = async (
|
|
|
160
160
|
export const mapHIEPatientToFormValues = (hiePatient: HIEPatient, currentFormValues: FormValues): FormValues => {
|
|
161
161
|
return patientMapper.mapHIEPatientToFormValues(hiePatient, currentFormValues);
|
|
162
162
|
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Mask sensitive data by replacing end digits starting from the 2nd to last with '*'
|
|
166
|
+
* @param data {string} - The data to mask
|
|
167
|
+
* @returns {string} - The masked data
|
|
168
|
+
*/
|
|
169
|
+
export const maskData = (data: string): string => {
|
|
170
|
+
const maskedData = data.slice(0, 2) + '*'.repeat(data.length - 2);
|
|
171
|
+
return maskedData;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get patient name from FHIR Patient resource
|
|
176
|
+
* @param patient {fhir.Patient} - The FHIR Patient resource
|
|
177
|
+
* @returns {object} - The patient name
|
|
178
|
+
*/
|
|
179
|
+
export const getPatientName = (patient: fhir.Patient) => {
|
|
180
|
+
const familyName = patient?.name[0]?.['family'] ?? '';
|
|
181
|
+
const givenName = patient.name[0]?.['given']?.[0]?.split(' ')?.[0] ?? '';
|
|
182
|
+
const middleName = patient.name[0]?.['given']?.[0]?.replace(givenName, '')?.trim() ?? '';
|
|
183
|
+
return { familyName, givenName, middleName };
|
|
184
|
+
};
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { Button, ModalBody, ModalHeader, ModalFooter, Accordion, AccordionItem, CodeSnippet } from '@carbon/react';
|
|
4
|
-
import styles from './confirm-hie.scss';
|
|
5
4
|
import { age, ExtensionSlot, formatDate } from '@openmrs/esm-framework';
|
|
6
5
|
import { type HIEPatient } from '../hie-types';
|
|
7
6
|
import capitalize from 'lodash-es/capitalize';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<span style={{ minWidth: '5rem', fontWeight: 'bold' }}>{label}</span>
|
|
13
|
-
<span>{value}</span>
|
|
14
|
-
</div>
|
|
15
|
-
);
|
|
16
|
-
};
|
|
7
|
+
import styles from './confirm-hie.scss';
|
|
8
|
+
import PatientInfo from '../patient-info/patient-info.component';
|
|
9
|
+
import DependentInfo from '../dependants/dependants.component';
|
|
10
|
+
import { getPatientName, maskData } from '../hie-resource';
|
|
17
11
|
|
|
18
12
|
interface HIEConfirmationModalProps {
|
|
19
13
|
closeModal: () => void;
|
|
@@ -23,8 +17,7 @@ interface HIEConfirmationModalProps {
|
|
|
23
17
|
|
|
24
18
|
const HIEConfirmationModal: React.FC<HIEConfirmationModalProps> = ({ closeModal, patient, onUseValues }) => {
|
|
25
19
|
const { t } = useTranslation();
|
|
26
|
-
const
|
|
27
|
-
const lastName = patient?.name[0]['family'];
|
|
20
|
+
const { familyName, givenName, middleName } = getPatientName(patient);
|
|
28
21
|
|
|
29
22
|
const handleUseValues = () => {
|
|
30
23
|
onUseValues();
|
|
@@ -37,15 +30,27 @@ const HIEConfirmationModal: React.FC<HIEConfirmationModalProps> = ({ closeModal,
|
|
|
37
30
|
<span className={styles.header}>{t('hieModal', 'HIE Patient Record Found')}</span>
|
|
38
31
|
</ModalHeader>
|
|
39
32
|
<ModalBody>
|
|
40
|
-
<div
|
|
33
|
+
<div className={styles.patientDetails}>
|
|
41
34
|
<ExtensionSlot
|
|
42
|
-
|
|
35
|
+
className={styles.patientPhotoContainer}
|
|
43
36
|
name="patient-photo-slot"
|
|
44
|
-
state={{ patientName: `${
|
|
37
|
+
state={{ patientName: `${maskData(givenName)} . ${maskData(middleName)} . ${maskData(familyName)}` }}
|
|
45
38
|
/>
|
|
46
|
-
<div
|
|
39
|
+
<div className={styles.patientInfoContainer}>
|
|
47
40
|
<PatientInfo label={t('healthID', 'HealthID')} value={patient?.id} />
|
|
48
|
-
<PatientInfo
|
|
41
|
+
<PatientInfo
|
|
42
|
+
label={t('patientName', 'Patient name')}
|
|
43
|
+
customValue={
|
|
44
|
+
<span className={styles.patientNameValue}>
|
|
45
|
+
<p>{maskData(givenName)}</p>
|
|
46
|
+
<span>•</span>
|
|
47
|
+
<p>{maskData(middleName)}</p>
|
|
48
|
+
<span>•</span>
|
|
49
|
+
<p>{maskData(familyName)}</p>
|
|
50
|
+
</span>
|
|
51
|
+
}
|
|
52
|
+
/>
|
|
53
|
+
|
|
49
54
|
<PatientInfo label={t('age', 'Age')} value={age(patient?.birthDate)} />
|
|
50
55
|
<PatientInfo label={t('dateOfBirth', 'Date of birth')} value={formatDate(new Date(patient?.birthDate))} />
|
|
51
56
|
<PatientInfo label={t('gender', 'Gender')} value={capitalize(patient?.gender)} />
|
|
@@ -53,9 +58,15 @@ const HIEConfirmationModal: React.FC<HIEConfirmationModalProps> = ({ closeModal,
|
|
|
53
58
|
label={t('maritalStatus', 'Marital status')}
|
|
54
59
|
value={patient?.maritalStatus?.coding?.map((m) => m.code).join('')}
|
|
55
60
|
/>
|
|
56
|
-
|
|
61
|
+
|
|
62
|
+
{(!patient?.contact || patient?.contact.length === 0) && (
|
|
63
|
+
<PatientInfo label={t('dependents', 'Dependents')} value="--" />
|
|
64
|
+
)}
|
|
57
65
|
</div>
|
|
58
66
|
</div>
|
|
67
|
+
|
|
68
|
+
<DependentInfo dependents={patient?.contact} />
|
|
69
|
+
|
|
59
70
|
<div>
|
|
60
71
|
<Accordion>
|
|
61
72
|
<AccordionItem title={t('viewFullResponse', 'View full response')}>
|
|
@@ -1,10 +1,50 @@
|
|
|
1
1
|
@use '@carbon/type';
|
|
2
|
-
@use '@
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/colors';
|
|
3
4
|
|
|
4
5
|
.header {
|
|
5
6
|
@include type.type-style('heading-03');
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
.
|
|
9
|
-
|
|
9
|
+
.patientInfo {
|
|
10
|
+
display: grid;
|
|
11
|
+
grid-template-columns: 0.25fr 0.75fr;
|
|
12
|
+
margin: 0.25rem;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.patientInfoLabel {
|
|
16
|
+
min-width: 5rem;
|
|
17
|
+
font-weight: bold;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.dependentInfo {
|
|
21
|
+
margin-bottom: 1rem;
|
|
22
|
+
padding: 0.5rem;
|
|
23
|
+
border: 1px solid #ddd;
|
|
24
|
+
border-radius: 5px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.patientDetails {
|
|
28
|
+
display: flex;
|
|
29
|
+
margin: 1rem;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.patientPhotoContainer {
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.patientInfoContainer {
|
|
38
|
+
width: 100%;
|
|
39
|
+
margin-left: 0.625rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.patientNameValue {
|
|
43
|
+
display: flex;
|
|
44
|
+
gap: layout.$spacing-03;
|
|
45
|
+
align-items: center;
|
|
46
|
+
|
|
47
|
+
& > span {
|
|
48
|
+
color: colors.$gray-40;
|
|
49
|
+
}
|
|
10
50
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from '../modal/confirm-hie.scss';
|
|
3
|
+
|
|
4
|
+
const PatientInfo: React.FC<{ label: string; value?: string; customValue?: JSX.Element }> = ({
|
|
5
|
+
label,
|
|
6
|
+
value,
|
|
7
|
+
customValue,
|
|
8
|
+
}) => {
|
|
9
|
+
return (
|
|
10
|
+
<div className={styles.patientInfo}>
|
|
11
|
+
<span className={styles.patientInfoLabel}>{label}</span>
|
|
12
|
+
<span>{value || customValue || '--'}</span>
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default PatientInfo;
|
package/translations/en.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"age": "Age",
|
|
5
5
|
"allFieldsRequiredText": "All fields are required unless marked optional",
|
|
6
6
|
"autoGeneratedPlaceholderText": "Auto-generated",
|
|
7
|
+
"birthCertificate": "Birth Certificate",
|
|
7
8
|
"birthdayNotInTheFuture": "Birthday cannot be in future",
|
|
8
9
|
"birthdayNotOver140YearsAgo": "Birthday cannot be more than 140 years ago",
|
|
9
10
|
"birthdayRequired": "Birthday is required",
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
"deleteIdentifierTooltip": "Delete",
|
|
46
47
|
"deleteRelationshipTooltipText": "Delete",
|
|
47
48
|
"demographicsSection": "Basic Info",
|
|
49
|
+
"dependants": "Dependants",
|
|
48
50
|
"dependents": "Dependents",
|
|
49
51
|
"discard": "Discard",
|
|
50
52
|
"dobToggleLabelText": "Date of Birth Known?",
|
|
@@ -84,7 +86,9 @@
|
|
|
84
86
|
"male": "Male",
|
|
85
87
|
"maritalStatus": "Marital status",
|
|
86
88
|
"middleNameLabelText": "Middle Name",
|
|
89
|
+
"name": "Name",
|
|
87
90
|
"nationalId": "National ID",
|
|
91
|
+
"nationalID": "National ID",
|
|
88
92
|
"negativeMonths": "Estimated months cannot be negative",
|
|
89
93
|
"negativeYears": "Estimated years cannot be negative",
|
|
90
94
|
"no": "No",
|
|
@@ -138,6 +142,7 @@
|
|
|
138
142
|
"unableToFetch": "Unable to fetch person attribute type - {{personattributetype}}",
|
|
139
143
|
"unknown": "Unknown",
|
|
140
144
|
"unknownPatientAttributeType": "Patient attribute type has unknown format {{personAttributeTypeFormat}}",
|
|
145
|
+
"unknownRelationship": "Unknown",
|
|
141
146
|
"updatePatient": "Update patient",
|
|
142
147
|
"updatePatientErrorSnackbarTitle": "Patient Details Update Failed",
|
|
143
148
|
"updatePatientSuccessSnackbarSubtitle": "The patient's information has been successfully updated",
|