@kenyaemr/esm-admin-app 5.4.1-pre.1908 → 5.4.1-pre.1912
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 +31 -24
- package/dist/102.js +2 -0
- package/dist/102.js.map +1 -0
- package/dist/{325.js → 137.js} +2 -2
- package/dist/{325.js.map → 137.js.map} +1 -1
- package/dist/294.js +2 -0
- package/dist/294.js.LICENSE.txt +32 -0
- package/dist/294.js.map +1 -0
- package/dist/300.js +1 -1
- package/dist/654.js +1 -0
- package/dist/654.js.map +1 -0
- package/dist/675.js +2 -0
- package/dist/{485.js.map → 675.js.map} +1 -1
- package/dist/{493.js → 719.js} +1 -1
- package/dist/{493.js.map → 719.js.map} +1 -1
- package/dist/893.js +1 -1
- package/dist/893.js.map +1 -1
- package/dist/913.js +1 -1
- package/dist/913.js.LICENSE.txt +4 -27
- package/dist/913.js.map +1 -1
- package/dist/kenyaemr-esm-admin-app.js +1 -1
- package/dist/kenyaemr-esm-admin-app.js.buildmanifest.json +117 -114
- package/dist/kenyaemr-esm-admin-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/components/hook/useHWR.ts +22 -0
- package/src/components/modal/hwr-confirmation.modal.scss +21 -0
- package/src/components/modal/hwr-confirmation.modal.tsx +130 -0
- package/src/components/modal/hwr-empty.modal.component.tsx +54 -0
- package/src/components/users/manage-users/user-list/user-list.component.tsx +27 -22
- package/src/components/users/manage-users/user-management.workspace.scss +36 -0
- package/src/components/users/manage-users/user-management.workspace.tsx +388 -193
- package/src/components/users/userManagementFormSchema.tsx +5 -1
- package/src/config-schema.ts +55 -3
- package/src/constants.ts +26 -0
- package/src/index.ts +5 -0
- package/src/routes.json +8 -0
- package/src/types/index.ts +97 -0
- package/translations/en.json +7 -0
- package/dist/373.js +0 -2
- package/dist/373.js.map +0 -1
- package/dist/387.js +0 -2
- package/dist/387.js.LICENSE.txt +0 -15
- package/dist/387.js.map +0 -1
- package/dist/485.js +0 -2
- package/dist/778.js +0 -1
- package/dist/778.js.map +0 -1
- /package/dist/{373.js.LICENSE.txt → 102.js.LICENSE.txt} +0 -0
- /package/dist/{325.js.LICENSE.txt → 137.js.LICENSE.txt} +0 -0
- /package/dist/{485.js.LICENSE.txt → 675.js.LICENSE.txt} +0 -0
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemrCharts":"^1.6.7"},"extensions":[{"component":"adminLeftPanelLink","name":"admin-left-panel-link","slot":"admin-left-panel-slot"},{"component":"userManagementLeftPannelLink","name":"user-management-left-panel-link","slot":"admin-left-panel-slot"},{"component":"etlAdministrationLeftPannelLink","name":"etl-administration-left-panel-link","slot":"admin-left-panel-slot"},{"component":"facilitySetupLeftPanelLink","name":"facility-setup-left-panel-link","slot":"admin-left-panel-slot"}],"workspaces":[{"name":"manage-user-workspace","component":"manageUserWorkspace","title":"Manage User Workspace","type":"other-form","canMaximize":true,"width":"extra-wide"}],"modals":[{"component":"operationConfirmationModal","name":"operation-confirmation-modal"}],"pages":[{"component":"root","route":"admin"}],"version":"5.4.1-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemrCharts":"^1.6.7"},"extensions":[{"component":"adminLeftPanelLink","name":"admin-left-panel-link","slot":"admin-left-panel-slot"},{"component":"userManagementLeftPannelLink","name":"user-management-left-panel-link","slot":"admin-left-panel-slot"},{"component":"etlAdministrationLeftPannelLink","name":"etl-administration-left-panel-link","slot":"admin-left-panel-slot"},{"component":"facilitySetupLeftPanelLink","name":"facility-setup-left-panel-link","slot":"admin-left-panel-slot"}],"workspaces":[{"name":"manage-user-workspace","component":"manageUserWorkspace","title":"Manage User Workspace","type":"other-form","canMaximize":true,"width":"extra-wide"}],"modals":[{"component":"operationConfirmationModal","name":"operation-confirmation-modal"},{"component":"hwrConfirmationModal","name":"hwr-confirmation-modal"},{"component":"hwrEmptyModal","name":"hwr-empty-modal"}],"pages":[{"component":"root","route":"admin"}],"version":"5.4.1-pre.1912"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FetchResponse, makeUrl, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
+
import { HWR_API_NO_CREDENTIALS, PROVIDER_NOT_FOUND, RESOURCE_NOT_FOUND, UNKNOWN } from '../../constants';
|
|
3
|
+
import useSWR from 'swr';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
|
|
6
|
+
export const searchHealthCareWork = async (identifierType: string, identifierNumber: string) => {
|
|
7
|
+
const url = `${restBaseUrl}/kenyaemr/practitionersearch?identifierType=${identifierType}&identifierNumber=${identifierNumber}`;
|
|
8
|
+
const response = await fetch(makeUrl(url));
|
|
9
|
+
if (response.ok) {
|
|
10
|
+
const responseData = await response.json();
|
|
11
|
+
if (responseData?.issue) {
|
|
12
|
+
throw new Error(PROVIDER_NOT_FOUND);
|
|
13
|
+
}
|
|
14
|
+
return responseData;
|
|
15
|
+
}
|
|
16
|
+
if (response.status === 401) {
|
|
17
|
+
throw new Error(HWR_API_NO_CREDENTIALS);
|
|
18
|
+
} else if (response.status === 404) {
|
|
19
|
+
throw new Error(RESOURCE_NOT_FOUND);
|
|
20
|
+
}
|
|
21
|
+
throw new Error(UNKNOWN);
|
|
22
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/type';
|
|
4
|
+
|
|
5
|
+
.healthWorkerInfoContainer {
|
|
6
|
+
display: grid;
|
|
7
|
+
grid-template-columns: 0.25fr 0.75fr;
|
|
8
|
+
margin: layout.$spacing-02;
|
|
9
|
+
}
|
|
10
|
+
.healthWorkerInfoLabel {
|
|
11
|
+
min-width: layout.$spacing-11;
|
|
12
|
+
font-weight: bold;
|
|
13
|
+
}
|
|
14
|
+
.healthWorkerOverview {
|
|
15
|
+
display: flex;
|
|
16
|
+
margin: layout.$spacing-05;
|
|
17
|
+
}
|
|
18
|
+
.healthWorkerPhoto {
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Button, Tag } from '@carbon/react';
|
|
2
|
+
import { ExtensionSlot } from '@openmrs/esm-framework';
|
|
3
|
+
import capitalize from 'lodash-es/capitalize';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { type PractitionerResponse } from '../../types';
|
|
7
|
+
import styles from './hwr-confirmation.modal.scss';
|
|
8
|
+
|
|
9
|
+
interface HealthWorkerInfoProps {
|
|
10
|
+
label: string;
|
|
11
|
+
value: string | boolean | React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const HealthWorkerInfo: React.FC<HealthWorkerInfoProps> = ({ label, value }) => {
|
|
15
|
+
return (
|
|
16
|
+
<div className={styles.healthWorkerInfoContainer}>
|
|
17
|
+
<span className={styles.healthWorkerInfoLabel}>{label}</span>
|
|
18
|
+
<span>{value}</span>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
interface HWRConfirmModalProps {
|
|
24
|
+
onConfirm: () => void;
|
|
25
|
+
close: () => void;
|
|
26
|
+
healthWorker: PractitionerResponse;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const HWRConfirmModal: React.FC<HWRConfirmModalProps> = ({ close, onConfirm, healthWorker }) => {
|
|
30
|
+
const { t } = useTranslation();
|
|
31
|
+
const passportNumber = healthWorker?.link
|
|
32
|
+
?.find(
|
|
33
|
+
(link: { relation: string; url: string }) =>
|
|
34
|
+
link.relation === 'self' && link.url.includes('identifierType=Passport'),
|
|
35
|
+
)
|
|
36
|
+
?.url.split('identifierNumber=')[1]
|
|
37
|
+
?.split('&')[0];
|
|
38
|
+
|
|
39
|
+
const practitioner = healthWorker?.entry?.[0]?.resource;
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
<div className="cds--modal-header">
|
|
44
|
+
<h3 className="cds--modal-header__heading">{t('healthWorkerRegistry', 'Health worker registry')}</h3>
|
|
45
|
+
</div>
|
|
46
|
+
<div className="cds--modal-content">
|
|
47
|
+
<p>
|
|
48
|
+
{t(
|
|
49
|
+
'healthWorkerDetailsFound',
|
|
50
|
+
'Health worker information found in the registry, do you want to use the information to continue with registration?',
|
|
51
|
+
)}
|
|
52
|
+
</p>
|
|
53
|
+
<div className={styles.healthWorkerOverview}>
|
|
54
|
+
<ExtensionSlot
|
|
55
|
+
className={styles.healthWorkerPhoto}
|
|
56
|
+
name="patient-photo-slot"
|
|
57
|
+
state={{
|
|
58
|
+
patientName: practitioner?.name?.[0]?.text || '',
|
|
59
|
+
}}
|
|
60
|
+
/>
|
|
61
|
+
<div style={{ width: '100%', marginLeft: '0.625rem' }}>
|
|
62
|
+
<HealthWorkerInfo
|
|
63
|
+
label={t('healthWorkerName', 'Health worker name')}
|
|
64
|
+
value={practitioner?.name?.[0]?.text}
|
|
65
|
+
/>
|
|
66
|
+
|
|
67
|
+
{practitioner?.telecom?.map((telecom, index) => (
|
|
68
|
+
<HealthWorkerInfo key={index} label={capitalize(telecom?.system)} value={telecom?.value || '--'} />
|
|
69
|
+
))}
|
|
70
|
+
|
|
71
|
+
{practitioner?.identifier?.map((identifier, index) => (
|
|
72
|
+
<HealthWorkerInfo
|
|
73
|
+
key={index}
|
|
74
|
+
label={identifier.type?.coding?.map((code) => code.display).join(' ') || '--'}
|
|
75
|
+
value={identifier.value || '--'}
|
|
76
|
+
/>
|
|
77
|
+
))}
|
|
78
|
+
|
|
79
|
+
{passportNumber && (
|
|
80
|
+
<HealthWorkerInfo label={t('passportNumber', 'Passport Number')} value={passportNumber} />
|
|
81
|
+
)}
|
|
82
|
+
|
|
83
|
+
<HealthWorkerInfo
|
|
84
|
+
label={t('renewalDate', 'Renewal Date')}
|
|
85
|
+
value={
|
|
86
|
+
practitioner?.identifier?.find((id) => id.type?.coding?.some((code) => code.code === 'license-number'))
|
|
87
|
+
?.period?.end || '--'
|
|
88
|
+
}
|
|
89
|
+
/>
|
|
90
|
+
|
|
91
|
+
<HealthWorkerInfo
|
|
92
|
+
label={t('licensingBody', 'Licensing Body')}
|
|
93
|
+
value={
|
|
94
|
+
practitioner?.qualification?.[0]?.extension?.find(
|
|
95
|
+
(ext) => ext.url === 'https://hwr-kenyahie/StructureDefinition/licensing-body',
|
|
96
|
+
)?.valueCodeableConcept?.coding?.[0]?.display || '--'
|
|
97
|
+
}
|
|
98
|
+
/>
|
|
99
|
+
<HealthWorkerInfo
|
|
100
|
+
label={t('qualification', 'Qualification')}
|
|
101
|
+
value={
|
|
102
|
+
practitioner?.qualification?.[0]?.code?.coding?.[0]?.display ||
|
|
103
|
+
practitioner?.extension?.find((ext) => ext.url === 'https://ts.kenya-hie.health/Codesystem/specialty')
|
|
104
|
+
?.valueCodeableConcept?.coding?.[0]?.display ||
|
|
105
|
+
'--'
|
|
106
|
+
}
|
|
107
|
+
/>
|
|
108
|
+
|
|
109
|
+
<HealthWorkerInfo
|
|
110
|
+
label={t('licenseValid', 'License Validity')}
|
|
111
|
+
value={
|
|
112
|
+
<Tag type={practitioner?.active ? 'green' : 'red'}>
|
|
113
|
+
{practitioner?.active ? t('licenseValid', 'License Valid') : t('licenseExpired', 'License Expired')}
|
|
114
|
+
</Tag>
|
|
115
|
+
}
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
<div className="cds--modal-footer">
|
|
121
|
+
<Button kind="secondary" onClick={close}>
|
|
122
|
+
{t('cancel', 'Cancel')}
|
|
123
|
+
</Button>
|
|
124
|
+
<Button onClick={onConfirm}>{t('useValues', 'Use values')}</Button>
|
|
125
|
+
</div>
|
|
126
|
+
</>
|
|
127
|
+
);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export default HWRConfirmModal;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Button } from '@carbon/react';
|
|
4
|
+
import { HWR_API_NO_CREDENTIALS, RESOURCE_NOT_FOUND, UNKNOWN } from '../../constants';
|
|
5
|
+
|
|
6
|
+
interface HWREmptyModalProps {
|
|
7
|
+
close: () => void;
|
|
8
|
+
errorCode?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const HWREmptyModal: React.FC<HWREmptyModalProps> = ({ close, errorCode }) => {
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
|
|
14
|
+
const errorMessages = {
|
|
15
|
+
[RESOURCE_NOT_FOUND]: t(
|
|
16
|
+
'ResourceNotFound',
|
|
17
|
+
'The Health Work Registry is not reachable, kindly confirm your internet connectivity and try again. Do you want to continue to create an account',
|
|
18
|
+
),
|
|
19
|
+
[HWR_API_NO_CREDENTIALS]: t(
|
|
20
|
+
'noHwrApi',
|
|
21
|
+
'Health Care Worker Registry API credentials not configured, Kindly contact system admin. Do you want to continue to create an account',
|
|
22
|
+
),
|
|
23
|
+
[UNKNOWN]: t(
|
|
24
|
+
'unknownError',
|
|
25
|
+
'An error occurred while searching Health Worker Registry, kindly contact system admin. Do you want to continue to create an account',
|
|
26
|
+
),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const defaultMessage = t(
|
|
30
|
+
'HealthworkerNotFound',
|
|
31
|
+
'The health worker records could not be found in Health Worker registry, do you want to continue to create an account',
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const message = errorMessages[errorCode] || defaultMessage;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<div className="cds--modal-header">
|
|
39
|
+
<h3 className="cds--modal-header__heading">{t('healthWorkerRegistryEmpty', 'Create an Account')}</h3>
|
|
40
|
+
</div>
|
|
41
|
+
<div className="cds--modal-content">
|
|
42
|
+
<p>{message}</p>
|
|
43
|
+
</div>
|
|
44
|
+
<div className="cds--modal-footer">
|
|
45
|
+
<Button kind="secondary" onClick={close}>
|
|
46
|
+
{t('cancel', 'Cancel')}
|
|
47
|
+
</Button>
|
|
48
|
+
<Button onClick={close}>{t('continue', 'Continue to registration')}</Button>
|
|
49
|
+
</div>
|
|
50
|
+
</>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default HWREmptyModal;
|
|
@@ -15,10 +15,13 @@ import {
|
|
|
15
15
|
Button,
|
|
16
16
|
Pagination,
|
|
17
17
|
ButtonSet,
|
|
18
|
+
OverflowMenuItem,
|
|
19
|
+
MenuItemDivider,
|
|
20
|
+
OverflowMenu,
|
|
18
21
|
} from '@carbon/react';
|
|
19
22
|
import { Edit, UserFollow } from '@carbon/react/icons';
|
|
20
23
|
import styles from './user-list.scss';
|
|
21
|
-
import { launchWorkspace, useDebounce, WorkspaceContainer } from '@openmrs/esm-framework';
|
|
24
|
+
import { launchWorkspace, showModal, useDebounce, WorkspaceContainer } from '@openmrs/esm-framework';
|
|
22
25
|
import { useUser } from '../../../../user-management.resources';
|
|
23
26
|
|
|
24
27
|
const UserList: React.FC = () => {
|
|
@@ -28,6 +31,7 @@ const UserList: React.FC = () => {
|
|
|
28
31
|
const [searchTerm, setSearchTerm] = useState('');
|
|
29
32
|
const [currentPage, setCurrentPage] = useState(1);
|
|
30
33
|
const [pageSize, setPageSize] = useState(10);
|
|
34
|
+
const [syncLoading, setSyncLoading] = useState(false);
|
|
31
35
|
|
|
32
36
|
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
33
37
|
|
|
@@ -59,7 +63,6 @@ const UserList: React.FC = () => {
|
|
|
59
63
|
setSearchTerm(searchTerm);
|
|
60
64
|
setCurrentPage(1);
|
|
61
65
|
};
|
|
62
|
-
|
|
63
66
|
if (isLoading) {
|
|
64
67
|
return <DataTableSkeleton />;
|
|
65
68
|
}
|
|
@@ -118,26 +121,28 @@ const UserList: React.FC = () => {
|
|
|
118
121
|
familyName: familyName,
|
|
119
122
|
roles: rolesDisplay,
|
|
120
123
|
actions: (
|
|
121
|
-
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
124
|
+
<>
|
|
125
|
+
<ButtonSet className={styles.btnSet}>
|
|
126
|
+
<Button
|
|
127
|
+
className={styles.btn}
|
|
128
|
+
renderIcon={Edit}
|
|
129
|
+
hasIconOnly
|
|
130
|
+
kind="ghost"
|
|
131
|
+
iconDescription={t('edit', 'Edit')}
|
|
132
|
+
onClick={() => {
|
|
133
|
+
const selectedUser = users.find((u) => u.uuid === user.uuid);
|
|
134
|
+
if (selectedUser) {
|
|
135
|
+
launchWorkspace('manage-user-workspace', {
|
|
136
|
+
workspaceTitle: t('editUser', 'Edit User'),
|
|
137
|
+
initialUserValue: selectedUser,
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
console.error('User not found:', user.uuid);
|
|
141
|
+
}
|
|
142
|
+
}}
|
|
143
|
+
/>
|
|
144
|
+
</ButtonSet>
|
|
145
|
+
</>
|
|
141
146
|
),
|
|
142
147
|
};
|
|
143
148
|
});
|
|
@@ -136,3 +136,39 @@
|
|
|
136
136
|
word-wrap: break-word;
|
|
137
137
|
line-height: 1.4;
|
|
138
138
|
}
|
|
139
|
+
|
|
140
|
+
.formHeaderSection {
|
|
141
|
+
@include type.type-style('heading-02');
|
|
142
|
+
display: flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
justify-content: space-between;
|
|
145
|
+
row-gap: layout.$spacing-06;
|
|
146
|
+
position: relative;
|
|
147
|
+
|
|
148
|
+
&::after {
|
|
149
|
+
content: '';
|
|
150
|
+
display: block;
|
|
151
|
+
width: layout.$spacing-07;
|
|
152
|
+
border-bottom: 0.375rem solid var(--brand-03);
|
|
153
|
+
position: absolute;
|
|
154
|
+
bottom: -0.75rem;
|
|
155
|
+
left: 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
& > span {
|
|
159
|
+
@include type.type-style('body-01');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
.formIdentifierType {
|
|
163
|
+
color: colors.$gray-70;
|
|
164
|
+
display: inline-block;
|
|
165
|
+
font-size: layout.$spacing-04;
|
|
166
|
+
line-height: layout.$spacing-05;
|
|
167
|
+
line-height: layout.$spacing-05;
|
|
168
|
+
margin-bottom: layout.$spacing-03;
|
|
169
|
+
vertical-align: baseline;
|
|
170
|
+
}
|
|
171
|
+
.formRow {
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
}
|