@kenyaemr/esm-patient-registration-app 4.3.0 → 4.4.0
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/574.js +1 -1
- package/dist/68.js +1 -1
- package/dist/68.js.map +1 -1
- package/dist/822.js +1 -1
- package/dist/822.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-patient-registration-app.js.buildmanifest.json +12 -12
- package/package.json +2 -2
- package/src/index.ts +0 -18
- package/src/offline.resources.ts +8 -1
- package/src/patient-registration/field/address/address-field.component.tsx +0 -1
- package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +13 -11
- package/src/patient-registration/form-manager.ts +27 -10
- package/src/patient-registration/input/basic-input/input/input.test.tsx +47 -10
- package/src/patient-registration/input/basic-input/select/select-input.test.tsx +16 -3
- package/src/patient-registration/input/custom-input/autosuggest/autosuggest.test.tsx +25 -14
- package/src/patient-registration/patient-registration-hooks.ts +21 -75
- package/src/patient-registration/patient-registration-types.tsx +2 -8
- package/src/patient-registration/patient-registration.component.tsx +3 -26
- package/src/patient-registration/section/section-wrapper.component.tsx +1 -1
- package/src/root.component.tsx +1 -5
- package/translations/en.json +0 -15
- package/src/patient-registration/input/custom-input/estimated-age/estimated-age-input.component.tsx +0 -32
- package/src/patient-registration/input/custom-input/estimated-age/estimated-age-input.test.tsx +0 -36
- package/src/patient-registration/input/custom-input/unidentified-patient/unidentified-patient-input.component.tsx +0 -24
- package/src/patient-registration/input/custom-input/unidentified-patient/unidentified-patient-input.test.tsx +0 -39
- package/src/patient-verification/assets/counties.json +0 -236
- package/src/patient-verification/assets/verification-assets.ts +0 -11
- package/src/patient-verification/patient-verification-hook.tsx +0 -156
- package/src/patient-verification/patient-verification-utils.ts +0 -173
- package/src/patient-verification/patient-verification.component.tsx +0 -118
- package/src/patient-verification/patient-verification.scss +0 -30
- package/src/patient-verification/verification-modal/confirm-prompt.component.tsx +0 -69
- package/src/patient-verification/verification-modal/empty-prompt.component.tsx +0 -35
- package/src/patient-verification/verification-types.ts +0 -50
|
@@ -23,7 +23,7 @@ export const SectionWrapper = ({ sectionDefinition, index }: SectionWrapperProps
|
|
|
23
23
|
* t('relationshipsSection', 'Relationships')
|
|
24
24
|
*/
|
|
25
25
|
return (
|
|
26
|
-
<div id={sectionDefinition.id}>
|
|
26
|
+
<div id={sectionDefinition.id} style={{ scrollMarginTop: '4rem' }}>
|
|
27
27
|
<h3 className={styles.productiveHeading02} style={{ color: '#161616' }}>
|
|
28
28
|
{index + 1}. {t(`${sectionDefinition.id}Section`, sectionDefinition.name)}
|
|
29
29
|
</h3>
|
package/src/root.component.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
|
3
3
|
import { Grid, Row } from '@carbon/react';
|
|
4
|
-
import { ExtensionSlot,
|
|
4
|
+
import { ExtensionSlot, useSession } from '@openmrs/esm-framework';
|
|
5
5
|
import {
|
|
6
6
|
Resources,
|
|
7
7
|
ResourcesContext,
|
|
@@ -30,10 +30,6 @@ export default function Root({ savePatientForm, isOffline }: RootProps) {
|
|
|
30
30
|
fetchPatientIdentifierTypesWithSources,
|
|
31
31
|
);
|
|
32
32
|
|
|
33
|
-
if (currentSession.sessionLocation === null) {
|
|
34
|
-
navigate({ to: `\${openmrsSpaBase}/login/location?returnToUrl=\${openmrsSpaBase}/patient-registration` });
|
|
35
|
-
}
|
|
36
|
-
|
|
37
33
|
return (
|
|
38
34
|
<main className={`omrs-main-content ${styles.root}`}>
|
|
39
35
|
<Grid className={styles.grid}>
|
package/translations/en.json
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
"address1": "Address line 1",
|
|
4
4
|
"address2": "Address line 2",
|
|
5
5
|
"addressHeader": "Address",
|
|
6
|
-
"age": "Age",
|
|
7
6
|
"allFieldsRequiredText": "All fields are required unless marked optional",
|
|
8
7
|
"autoGeneratedPlaceholderText": "Auto-generated",
|
|
9
8
|
"birthdayNotInTheFuture": "Birthday cannot be in the future",
|
|
@@ -12,15 +11,11 @@
|
|
|
12
11
|
"cancel": "Cancel",
|
|
13
12
|
"causeOfDeathInputLabel": "Cause of Death",
|
|
14
13
|
"cityVillage": "City",
|
|
15
|
-
"clientRegistryEmpty": "Create & Post Patient",
|
|
16
|
-
"clientVerificationWithClientRegistry": "Client verification with client registry",
|
|
17
14
|
"configure": "Configure",
|
|
18
15
|
"contactSection": "Contact Details",
|
|
19
|
-
"continue": "Continue",
|
|
20
16
|
"country": "Country",
|
|
21
17
|
"countyDistrict": "District",
|
|
22
18
|
"createNew": "Create New",
|
|
23
|
-
"dateOfBirth": "Date of birth",
|
|
24
19
|
"dateOfBirthLabelText": "Date of Birth",
|
|
25
20
|
"deathDateInputLabel": "Date of Death",
|
|
26
21
|
"deathdayNotInTheFuture": "Death day cannot be in the future",
|
|
@@ -43,7 +38,6 @@
|
|
|
43
38
|
"female": "Female",
|
|
44
39
|
"fieldErrorTitleMessage": "The following fields have errors:",
|
|
45
40
|
"fullNameLabelText": "Full Name",
|
|
46
|
-
"gender": "Gender",
|
|
47
41
|
"genderLabelText": "Sex",
|
|
48
42
|
"genderRequired": "Gender is required",
|
|
49
43
|
"genderUnspecified": "Gender is not specified",
|
|
@@ -60,7 +54,6 @@
|
|
|
60
54
|
"male": "Male",
|
|
61
55
|
"middleNameLabelText": "Middle Name",
|
|
62
56
|
"months": "Months",
|
|
63
|
-
"nationalId": "National ID",
|
|
64
57
|
"negativeMonths": "Negative months",
|
|
65
58
|
"negativeYears": "Negative years",
|
|
66
59
|
"no": "No",
|
|
@@ -69,12 +62,8 @@
|
|
|
69
62
|
"optional": "optional",
|
|
70
63
|
"other": "Other",
|
|
71
64
|
"patient": "Patient",
|
|
72
|
-
"patientDetailsFound": "Patient information found in the registry, do you want to use the information to continue with registration?",
|
|
73
|
-
"patientName": "Patient name",
|
|
74
65
|
"patientNameKnown": "Patient's Name is Known?",
|
|
75
|
-
"patientNotFound": "The patient records could not be found in Client registry, do you want to continue to create and post patient to registry",
|
|
76
66
|
"postalCode": "Postcode",
|
|
77
|
-
"postToRegistry": "Post to registry",
|
|
78
67
|
"registerPatient": "Register Patient",
|
|
79
68
|
"registrationSuccessToastDescription": "The patient can now be found by searching for them using their name or ID number",
|
|
80
69
|
"registrationSuccessToastTitle": "New Patient Created",
|
|
@@ -89,8 +78,6 @@
|
|
|
89
78
|
"restoreRelationshipActionButton": "Undo",
|
|
90
79
|
"searchAddress": "Search address",
|
|
91
80
|
"selectAnOption": "Select an option",
|
|
92
|
-
"selectCountry": "Select country",
|
|
93
|
-
"selectIdentifierType": "Select identifier type",
|
|
94
81
|
"sexFieldLabelText": "Sex",
|
|
95
82
|
"stateProvince": "State",
|
|
96
83
|
"stroke": "Stroke",
|
|
@@ -100,8 +87,6 @@
|
|
|
100
87
|
"updatePatient": "Update Patient",
|
|
101
88
|
"updationSuccessToastDescription": "The patient's information has been successfully updated",
|
|
102
89
|
"updationSuccessToastTitle": "Patient Details Updated",
|
|
103
|
-
"useValues": "Use values",
|
|
104
|
-
"validate": "Validate",
|
|
105
90
|
"years": "Years",
|
|
106
91
|
"yearsEstimateRequired": "Years estimate required",
|
|
107
92
|
"yes": "Yes"
|
package/src/patient-registration/input/custom-input/estimated-age/estimated-age-input.component.tsx
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
2
|
-
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import { useField } from 'formik';
|
|
4
|
-
import dayjs from 'dayjs';
|
|
5
|
-
import { Input } from '../../basic-input/input/input.component';
|
|
6
|
-
import styles from './../../input.scss';
|
|
7
|
-
|
|
8
|
-
interface EstimatedAgeInputProps {
|
|
9
|
-
yearsName: string;
|
|
10
|
-
monthsName: string;
|
|
11
|
-
setBirthdate(field: string, value: any, shouldValidate?: boolean): void;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const EstimatedAgeInput: React.FC<EstimatedAgeInputProps> = ({ yearsName, monthsName, setBirthdate }) => {
|
|
15
|
-
const [yearsField] = useField(yearsName);
|
|
16
|
-
const [monthsField] = useField(monthsName);
|
|
17
|
-
const { t } = useTranslation();
|
|
18
|
-
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
setBirthdate(
|
|
21
|
-
'birthdate',
|
|
22
|
-
dayjs().subtract(yearsField.value, 'year').subtract(monthsField.value, 'month').toISOString().split('T')[0],
|
|
23
|
-
);
|
|
24
|
-
}, [yearsField.value, monthsField.value, setBirthdate]);
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<main className={styles.fieldRow}>
|
|
28
|
-
<Input id="number" labelText={t('years', 'Years')} name={yearsName} />
|
|
29
|
-
<Input id="number" labelText={t('months', 'Months')} name={monthsName} />
|
|
30
|
-
</main>
|
|
31
|
-
);
|
|
32
|
-
};
|
package/src/patient-registration/input/custom-input/estimated-age/estimated-age-input.test.tsx
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { Formik, Form } from 'formik';
|
|
4
|
-
import { EstimatedAgeInput } from './estimated-age-input.component';
|
|
5
|
-
|
|
6
|
-
describe.skip('estimated age input', () => {
|
|
7
|
-
const mockSetBirthdate = jest.fn();
|
|
8
|
-
|
|
9
|
-
const setupInput = async () => {
|
|
10
|
-
render(
|
|
11
|
-
<Formik initialValues={{ years: 0, months: 0 }} onSubmit={null}>
|
|
12
|
-
<Form>
|
|
13
|
-
<EstimatedAgeInput yearsName="years" monthsName="months" setBirthdate={mockSetBirthdate} />
|
|
14
|
-
</Form>
|
|
15
|
-
</Formik>,
|
|
16
|
-
);
|
|
17
|
-
const years = screen.getByLabelText('years') as HTMLInputElement;
|
|
18
|
-
const months = screen.getByLabelText('months') as HTMLInputElement;
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
years,
|
|
22
|
-
months,
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
it('exists', async () => {
|
|
27
|
-
const inputs = await setupInput();
|
|
28
|
-
expect(inputs.years.type).toEqual('number');
|
|
29
|
-
expect(inputs.months.type).toEqual('number');
|
|
30
|
-
});
|
|
31
|
-
it('calls setBirthdate', async () => {
|
|
32
|
-
mockSetBirthdate.mockReset();
|
|
33
|
-
await setupInput();
|
|
34
|
-
expect(mockSetBirthdate.mock.calls.length).toBe(1);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
2
|
-
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import { useField } from 'formik';
|
|
4
|
-
import { Input } from '../../basic-input/input/input.component';
|
|
5
|
-
|
|
6
|
-
interface UnidentifiedPatientInputProps {
|
|
7
|
-
name: string;
|
|
8
|
-
setName(field: string, value: any, shouldValidate?: boolean): void;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const UnidentifiedPatientInput: React.FC<UnidentifiedPatientInputProps> = ({ setName, name }) => {
|
|
12
|
-
const [field] = useField({ name });
|
|
13
|
-
const { t } = useTranslation();
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
if (field.value) {
|
|
17
|
-
setName('givenName', 'UNKNOWN');
|
|
18
|
-
setName('middleName', 'UNKNOWN');
|
|
19
|
-
setName('familyName', 'UNKNOWN');
|
|
20
|
-
}
|
|
21
|
-
}, [field.value, setName]);
|
|
22
|
-
|
|
23
|
-
return <Input id="checkbox" labelText={t('unidentifiedPatient', 'Unidentified Patient')} name={name} />;
|
|
24
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { Formik, Form } from 'formik';
|
|
4
|
-
import { UnidentifiedPatientInput } from './unidentified-patient-input.component';
|
|
5
|
-
|
|
6
|
-
describe.skip('unidentified patient input', () => {
|
|
7
|
-
const mockSetName = jest.fn();
|
|
8
|
-
|
|
9
|
-
const setupInput = async (unidentifiedPatient) => {
|
|
10
|
-
render(
|
|
11
|
-
<Formik initialValues={{ unidentifiedPatient: unidentifiedPatient }} onSubmit={null}>
|
|
12
|
-
<Form>
|
|
13
|
-
<UnidentifiedPatientInput name="unidentifiedPatient" setName={mockSetName} />
|
|
14
|
-
</Form>
|
|
15
|
-
</Formik>,
|
|
16
|
-
);
|
|
17
|
-
return screen.getByLabelText('Unidentified Patient') as HTMLInputElement;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
it('exists', async () => {
|
|
21
|
-
const input = await setupInput(false);
|
|
22
|
-
expect(input.type).toEqual('checkbox');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('sets givenName, middleName and familyName to "UNKNOWN" if patient is marked as unidentified', async () => {
|
|
26
|
-
mockSetName.mockReset();
|
|
27
|
-
await setupInput(true);
|
|
28
|
-
expect(mockSetName.mock.calls.length).toBe(3);
|
|
29
|
-
expect(mockSetName).toHaveBeenCalledWith('givenName', 'UNKNOWN');
|
|
30
|
-
expect(mockSetName).toHaveBeenCalledWith('middleName', 'UNKNOWN');
|
|
31
|
-
expect(mockSetName).toHaveBeenCalledWith('familyName', 'UNKNOWN');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('does not override givenName, middleName and familyName if patient is identified', async () => {
|
|
35
|
-
mockSetName.mockReset();
|
|
36
|
-
await setupInput(false);
|
|
37
|
-
expect(mockSetName.mock.calls.length).toBe(0);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"name": "Mombasa",
|
|
4
|
-
"code": 1,
|
|
5
|
-
"capital": "Mombasa City"
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"name": "Kwale",
|
|
9
|
-
"code": 2,
|
|
10
|
-
"capital": "Kwale"
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"name": "Kilifi",
|
|
14
|
-
"code": 3,
|
|
15
|
-
"capital": "Kilifi"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"name": "Tana River",
|
|
19
|
-
"code": 4,
|
|
20
|
-
"capital": "Hola"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"name": "Lamu",
|
|
24
|
-
"code": 5,
|
|
25
|
-
"capital": "Lamu"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"name": "Taita taveta",
|
|
29
|
-
"code": 6,
|
|
30
|
-
"capital": "Voi"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"name": "Garissa",
|
|
34
|
-
"code": 7,
|
|
35
|
-
"capital": "Garissa"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"name": "Wajir",
|
|
39
|
-
"code": 8,
|
|
40
|
-
"capital": "Wajir"
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"name": "Mandera",
|
|
44
|
-
"code": 9,
|
|
45
|
-
"capital": "Mandera"
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
"name": "Marsabit",
|
|
49
|
-
"code": 10,
|
|
50
|
-
"capital": "Marsabit"
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
"name": "Isiolo",
|
|
54
|
-
"code": 11,
|
|
55
|
-
"capital": "Isiolo"
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"name": "Meru",
|
|
59
|
-
"code": 12,
|
|
60
|
-
"capital": "Meru"
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
"name": "Tharaka nithi",
|
|
64
|
-
"code": 13,
|
|
65
|
-
"capital": "Chuka"
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
"name": "Embu",
|
|
69
|
-
"code": 14,
|
|
70
|
-
"capital": "Embu"
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
"name": "Kitui",
|
|
74
|
-
"code": 15,
|
|
75
|
-
"capital": "Kitui"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
"name": "Machakos",
|
|
79
|
-
"code": 16,
|
|
80
|
-
"capital": "Machakos"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"name": "Makueni",
|
|
84
|
-
"code": 17,
|
|
85
|
-
"capital": "Wote"
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
"name": "Nyandarua",
|
|
89
|
-
"code": 18,
|
|
90
|
-
"capital": "Ol Kalou"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"name": "Nyeri",
|
|
94
|
-
"code": 19,
|
|
95
|
-
"capital": "Nyeri"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"name": "Kirinyaga",
|
|
99
|
-
"code": 20,
|
|
100
|
-
"capital": "Kerugoya/Kutus"
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"name": "Murang'a",
|
|
104
|
-
"code": 21,
|
|
105
|
-
"capital": "Murang'a"
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
"name": "Kiambu",
|
|
109
|
-
"code": 22,
|
|
110
|
-
"capital": "Kiambu"
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
"name": "Turkana",
|
|
114
|
-
"code": 23,
|
|
115
|
-
"capital": "Lodwar"
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
"name": "West pokot",
|
|
119
|
-
"code": 24,
|
|
120
|
-
"capital": "Kapenguria"
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
"name": "Samburu",
|
|
124
|
-
"code": 25,
|
|
125
|
-
"capital": "Maralal"
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
"name": "Trans nzoia",
|
|
129
|
-
"code": 26,
|
|
130
|
-
"capital": "Kitale"
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
"name": "Uasin gishu",
|
|
134
|
-
"code": 27,
|
|
135
|
-
"capital": "Eldoret"
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
"name": "Elgeyo marakwet",
|
|
139
|
-
"code": 28,
|
|
140
|
-
"capital": "Iten"
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
"name": "Nandi",
|
|
144
|
-
"code": 29,
|
|
145
|
-
"capital": "Kapsabet"
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
"name": "Baringo",
|
|
149
|
-
"code": 30,
|
|
150
|
-
"capital": "Kabarnet"
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
"name": "Laikipia",
|
|
154
|
-
"code": 31,
|
|
155
|
-
"capital": "Rumuruti"
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"name": "Nakuru",
|
|
159
|
-
"code": 32,
|
|
160
|
-
"capital": "Nakuru"
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
"name": "Narok",
|
|
164
|
-
"code": 33,
|
|
165
|
-
"capital": "Narok"
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
"name": "Kajiado",
|
|
169
|
-
"code": 34
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
"name": "Kericho",
|
|
173
|
-
"code": 35,
|
|
174
|
-
"capital": "Kericho"
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"name": "Bomet",
|
|
178
|
-
"code": 36,
|
|
179
|
-
"capital": "Bomet"
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
"name": "Kakamega",
|
|
183
|
-
"code": 37,
|
|
184
|
-
"capital": "Kakamega"
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
"name": "Vihiga",
|
|
188
|
-
"code": 38,
|
|
189
|
-
"capital": "Vihiga"
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
"name": "Bungoma",
|
|
193
|
-
"code": 39,
|
|
194
|
-
"capital": "Bungoma"
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
"name": "Busia",
|
|
198
|
-
"code": 40,
|
|
199
|
-
"capital": "Busia"
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
"name": "Siaya",
|
|
203
|
-
"code": 41,
|
|
204
|
-
"capital": "Siaya"
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
"name": "Kisumu",
|
|
208
|
-
"code": 42,
|
|
209
|
-
"capital": "Kisumu"
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
"name": "Homa bay",
|
|
213
|
-
"code": 43,
|
|
214
|
-
"capital": "Homa Bay"
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
"name": "Migori",
|
|
218
|
-
"code": 44,
|
|
219
|
-
"capital": "Migori"
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
"name": "Kisii",
|
|
223
|
-
"code": 45,
|
|
224
|
-
"capital": "Kisii"
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
"name": "Nyamira",
|
|
228
|
-
"code": 46,
|
|
229
|
-
"capital": "Nyamira"
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
"name": "Nairobi",
|
|
233
|
-
"code": 47,
|
|
234
|
-
"capital": "Nairobi City"
|
|
235
|
-
}
|
|
236
|
-
]
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export const countries = [
|
|
2
|
-
{ name: 'Kenya', initials: 'KE' },
|
|
3
|
-
{ name: 'Uganda', initials: 'UG' },
|
|
4
|
-
{ name: 'Tanzania', initials: 'TZ' },
|
|
5
|
-
];
|
|
6
|
-
|
|
7
|
-
export const verificationIdentifierTypes = [
|
|
8
|
-
{ name: 'National ID', value: 'national-id' },
|
|
9
|
-
{ name: 'Passport', value: 'passport' },
|
|
10
|
-
{ name: 'Birth certificate number', value: 'birth-certificate-number' },
|
|
11
|
-
];
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { FetchResponse, openmrsFetch, showNotification, showToast } from '@openmrs/esm-framework';
|
|
2
|
-
import { ConceptAnswers, ConceptResponse, FormValues } from '../patient-registration/patient-registration-types';
|
|
3
|
-
import { generateNUPIPayload, handleClientRegistryResponse } from './patient-verification-utils';
|
|
4
|
-
import useSWR from 'swr';
|
|
5
|
-
import useSWRImmutable from 'swr/immutable';
|
|
6
|
-
|
|
7
|
-
export function searchClientRegistry(identifierType: string, searchTerm: string, token: string) {
|
|
8
|
-
const url = `https://afyakenyaapi.health.go.ke/partners/registry/search/KE/${identifierType}/${searchTerm}`;
|
|
9
|
-
return fetch(url, { headers: { Authorization: `Bearer ${token}` } }).then((r) => r.json());
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function savePatientToClientRegistry(formValues: FormValues) {
|
|
13
|
-
const createdRegistryPatient = generateNUPIPayload(formValues);
|
|
14
|
-
return fetch(`https://afyakenyaapi.health.go.ke/partners/registry`, {
|
|
15
|
-
headers: { Authorization: `Bearer ${formValues.token}`, 'Content-Type': 'application/json' },
|
|
16
|
-
method: 'POST',
|
|
17
|
-
body: JSON.stringify(createdRegistryPatient),
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export async function handleSavePatientToClientRegistry(
|
|
22
|
-
formValues: FormValues,
|
|
23
|
-
setValues: (values: FormValues, shouldValidate?: boolean) => void,
|
|
24
|
-
inEditMode: boolean,
|
|
25
|
-
) {
|
|
26
|
-
const mode = inEditMode ? 'edit' : 'new';
|
|
27
|
-
switch (mode) {
|
|
28
|
-
case 'edit': {
|
|
29
|
-
try {
|
|
30
|
-
const searchResponse = await searchClientRegistry(
|
|
31
|
-
'national-id',
|
|
32
|
-
formValues.identifiers['nationalId'].identifierValue,
|
|
33
|
-
formValues.token,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
// if client does not exists post client to registry
|
|
37
|
-
if (searchResponse?.clientExists === false) {
|
|
38
|
-
postToRegistry(formValues, setValues);
|
|
39
|
-
}
|
|
40
|
-
} catch (error) {
|
|
41
|
-
showToast({
|
|
42
|
-
title: 'Client registry error',
|
|
43
|
-
description: `${error}`,
|
|
44
|
-
millis: 10000,
|
|
45
|
-
kind: 'error',
|
|
46
|
-
critical: true,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
case 'new': {
|
|
52
|
-
postToRegistry(formValues, setValues);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function useConceptAnswers(conceptUuid: string): { data: Array<ConceptAnswers>; isLoading: boolean } {
|
|
58
|
-
const { data, error, isLoading } = useSWR<FetchResponse<ConceptResponse>, Error>(
|
|
59
|
-
`/ws/rest/v1/concept/${conceptUuid}`,
|
|
60
|
-
openmrsFetch,
|
|
61
|
-
);
|
|
62
|
-
if (error) {
|
|
63
|
-
showToast({
|
|
64
|
-
title: error.name,
|
|
65
|
-
description: error.message,
|
|
66
|
-
kind: 'error',
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
return { data: data?.data?.answers ?? [], isLoading };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const urlencoded = new URLSearchParams();
|
|
73
|
-
urlencoded.append('client_id', 'palladium.partner.client');
|
|
74
|
-
urlencoded.append('client_secret', '28f95b2a');
|
|
75
|
-
urlencoded.append('grant_type', 'client_credentials');
|
|
76
|
-
urlencoded.append('scope', 'DHP.Gateway DHP.Partners');
|
|
77
|
-
|
|
78
|
-
const swrFetcher = async (url) => {
|
|
79
|
-
const res = await fetch(url, {
|
|
80
|
-
method: 'POST',
|
|
81
|
-
body: urlencoded,
|
|
82
|
-
redirect: 'follow',
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// If the status code is not in the range 200-299,
|
|
86
|
-
// we still try to parse and throw it.
|
|
87
|
-
if (!res.ok) {
|
|
88
|
-
const error = new Error('An error occurred while fetching the data.') as any;
|
|
89
|
-
// Attach extra info to the error object.
|
|
90
|
-
error.info = await res.json();
|
|
91
|
-
error.status = res.status;
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return res.json();
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export function useGlobalProperties() {
|
|
99
|
-
const { data, isLoading, error } = useSWRImmutable(
|
|
100
|
-
`https://afyakenyaidentityapi.health.go.ke/connect/token`,
|
|
101
|
-
swrFetcher,
|
|
102
|
-
{ refreshInterval: 864000 },
|
|
103
|
-
);
|
|
104
|
-
return { data: data, isLoading, error };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function postToRegistry(
|
|
108
|
-
formValues: FormValues,
|
|
109
|
-
setValues: (values: FormValues, shouldValidate?: boolean) => void,
|
|
110
|
-
) {
|
|
111
|
-
try {
|
|
112
|
-
const clientRegistryResponse = await savePatientToClientRegistry(formValues);
|
|
113
|
-
if (clientRegistryResponse.ok) {
|
|
114
|
-
const savedValues = await clientRegistryResponse.json();
|
|
115
|
-
const nupiIdentifier = {
|
|
116
|
-
['nationalUniquePatientIdentifier']: {
|
|
117
|
-
identifierTypeUuid: 'f85081e2-b4be-4e48-b3a4-7994b69bb101',
|
|
118
|
-
identifierName: 'National Unique patient identifier',
|
|
119
|
-
identifierValue: savedValues['clientNumber'],
|
|
120
|
-
initialValue: savedValues['clientNumber'],
|
|
121
|
-
identifierUuid: undefined,
|
|
122
|
-
selectedSource: { uuid: '', name: '' },
|
|
123
|
-
preferred: false,
|
|
124
|
-
required: false,
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
setValues({ ...formValues, identifiers: { ...formValues.identifiers, ...nupiIdentifier } });
|
|
128
|
-
showToast({
|
|
129
|
-
title: 'Posted patient to client registry successfully',
|
|
130
|
-
description: `The patient has been saved to client registry`,
|
|
131
|
-
kind: 'success',
|
|
132
|
-
});
|
|
133
|
-
} else {
|
|
134
|
-
const responseError = await clientRegistryResponse.json();
|
|
135
|
-
const errorMessage = Object.values(responseError.errors ?? {})
|
|
136
|
-
.map((error: any) => error.join())
|
|
137
|
-
.toString();
|
|
138
|
-
setValues({
|
|
139
|
-
...formValues,
|
|
140
|
-
attributes: {
|
|
141
|
-
...formValues.attributes,
|
|
142
|
-
['869f623a-f78e-4ace-9202-0bed481822f5']: 'Failed validation',
|
|
143
|
-
['752a0331-5293-4aa5-bf46-4d51aaf2cdc5']: 'Failed',
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
showNotification({
|
|
147
|
-
title: responseError.title,
|
|
148
|
-
description: errorMessage,
|
|
149
|
-
kind: 'warning',
|
|
150
|
-
millis: 150000,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
} catch (error) {
|
|
154
|
-
showNotification({ kind: 'error', title: 'NUPI Post failed', description: JSON.stringify(error) });
|
|
155
|
-
}
|
|
156
|
-
}
|