@kenyaemr/esm-admin-app 5.4.1-pre.2021 → 5.4.1-pre.2025
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 +17 -17
- package/dist/163.js +1 -1
- package/dist/163.js.map +1 -1
- package/dist/300.js +1 -1
- package/dist/{253.js → 430.js} +2 -2
- package/dist/430.js.map +1 -0
- package/dist/kenyaemr-esm-admin-app.js +1 -1
- package/dist/kenyaemr-esm-admin-app.js.buildmanifest.json +36 -36
- 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/modal/hwr-confirmation.modal.tsx +4 -1
- package/src/components/modal/hwr-sync.modal.tsx +6 -0
- package/src/components/users/manage-users/user-details/user-details.component.tsx +12 -0
- package/src/components/users/manage-users/user-list/user-list.component.tsx +20 -3
- package/src/components/users/manage-users/user-management.workspace.tsx +39 -0
- package/src/components/users/userManagementFormSchema.tsx +1 -0
- package/src/config-schema.ts +6 -0
- package/translations/en.json +1 -0
- package/dist/253.js.map +0 -1
- /package/dist/{253.js.LICENSE.txt → 430.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"},{"name":"user-role-scope-workspace","component":"userRoleScopeWorkspace","title":"User Rple Scope 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"},{"component":"hwrSyncModal","name":"hwr-syncing-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"},{"name":"user-role-scope-workspace","component":"userRoleScopeWorkspace","title":"User Rple Scope 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"},{"component":"hwrSyncModal","name":"hwr-syncing-modal"}],"pages":[{"component":"root","route":"admin"}],"version":"5.4.1-pre.2025"}
|
package/package.json
CHANGED
|
@@ -63,7 +63,10 @@ const HWRConfirmModal: React.FC<HWRConfirmModalProps> = ({ close, onConfirm, hea
|
|
|
63
63
|
label={t('healthWorkerName', 'Health worker name')}
|
|
64
64
|
value={practitioner?.name?.[0]?.text}
|
|
65
65
|
/>
|
|
66
|
-
|
|
66
|
+
<HealthWorkerInfo
|
|
67
|
+
label={t('providerUniqueIdentifier', 'Provider unique identifier')}
|
|
68
|
+
value={practitioner?.id}
|
|
69
|
+
/>
|
|
67
70
|
{practitioner?.telecom?.map((telecom, index) => (
|
|
68
71
|
<HealthWorkerInfo key={index} label={capitalize(telecom?.system)} value={telecom?.value || '--'} />
|
|
69
72
|
))}
|
|
@@ -30,6 +30,7 @@ const HWRSyncModal: React.FC<HWRSyncModalProps> = ({ close, provider }) => {
|
|
|
30
30
|
qualificationUuid,
|
|
31
31
|
providerAddressUuid,
|
|
32
32
|
providerHieFhirReference,
|
|
33
|
+
providerUniqueIdentifierAttributeTypeUuid,
|
|
33
34
|
} = config;
|
|
34
35
|
|
|
35
36
|
const attributeMapping = {
|
|
@@ -89,6 +90,7 @@ const HWRSyncModal: React.FC<HWRSyncModalProps> = ({ close, provider }) => {
|
|
|
89
90
|
?.valueCodeableConcept?.coding?.[0]?.display,
|
|
90
91
|
nationalId: resource?.identifier?.find((id) => id.type?.coding?.some((code) => code.code === 'national-id'))
|
|
91
92
|
?.value,
|
|
93
|
+
providerUniqueIdentifier: resource?.id,
|
|
92
94
|
};
|
|
93
95
|
|
|
94
96
|
const updatableAttributes = [
|
|
@@ -100,6 +102,10 @@ const HWRSyncModal: React.FC<HWRSyncModalProps> = ({ close, provider }) => {
|
|
|
100
102
|
{ attributeType: providerHieFhirReference, value: JSON.stringify(healthWorker) },
|
|
101
103
|
{ attributeType: providerAddressUuid, value: extractedAttributes.email },
|
|
102
104
|
{ attributeType: providerNationalIdUuid, value: extractedAttributes.nationalId },
|
|
105
|
+
{
|
|
106
|
+
attributeType: providerUniqueIdentifierAttributeTypeUuid,
|
|
107
|
+
value: extractedAttributes.providerUniqueIdentifier,
|
|
108
|
+
},
|
|
103
109
|
].filter((attr) => attr.value !== undefined && attr.value !== null && attr.value !== '');
|
|
104
110
|
|
|
105
111
|
await Promise.all(
|
|
@@ -26,6 +26,7 @@ interface ProviderAttributes {
|
|
|
26
26
|
registrationNumber?: ProviderAttribute;
|
|
27
27
|
emailAddress?: ProviderAttribute;
|
|
28
28
|
passportNumber: ProviderAttribute;
|
|
29
|
+
providerUniqueIdentifier: ProviderAttribute;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
const UserDetails: React.FC<UserDetailsProps> = ({ provider, user }) => {
|
|
@@ -41,6 +42,7 @@ const UserDetails: React.FC<UserDetailsProps> = ({ provider, user }) => {
|
|
|
41
42
|
registrationNumber: 'License Body',
|
|
42
43
|
emailAddress: 'Provider Address',
|
|
43
44
|
passportNumber: 'Provider passport number',
|
|
45
|
+
providerUniqueIdentifier: 'Provider unique identifier',
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
const attributes: ProviderAttributes = Object.entries(attributeMap).reduce((acc, [key, display]) => {
|
|
@@ -60,6 +62,7 @@ const UserDetails: React.FC<UserDetailsProps> = ({ provider, user }) => {
|
|
|
60
62
|
registrationNumber,
|
|
61
63
|
emailAddress,
|
|
62
64
|
passportNumber,
|
|
65
|
+
providerUniqueIdentifier,
|
|
63
66
|
} = attributes;
|
|
64
67
|
|
|
65
68
|
const formattedExpiryDate = dateAttr?.value ? dayjs(dateAttr.value).format('YYYY-MM-DD') : null;
|
|
@@ -104,6 +107,11 @@ const UserDetails: React.FC<UserDetailsProps> = ({ provider, user }) => {
|
|
|
104
107
|
<span className={styles.statusTag}>
|
|
105
108
|
{qualification?.value && <Tag type="cyan">{capitalize(qualification?.value)}</Tag>}
|
|
106
109
|
</span>
|
|
110
|
+
<span className={styles.statusTag}>
|
|
111
|
+
{providerUniqueIdentifier?.value && (
|
|
112
|
+
<Tag type="cyan">{capitalize(providerUniqueIdentifier?.value)}</Tag>
|
|
113
|
+
)}
|
|
114
|
+
</span>
|
|
107
115
|
</div>
|
|
108
116
|
</div>
|
|
109
117
|
|
|
@@ -134,9 +142,13 @@ const UserDetails: React.FC<UserDetailsProps> = ({ provider, user }) => {
|
|
|
134
142
|
{t('registrationNumber', 'Registration number')}:{' '}
|
|
135
143
|
{registrationNumber?.value ? registrationNumber.value : '--'}
|
|
136
144
|
</span>
|
|
145
|
+
<span className={styles.middot}>· </span>
|
|
146
|
+
|
|
137
147
|
<span className={styles.spanField}>
|
|
138
148
|
{t('passportNumber', 'Passport number')}: {passportNumber?.value ? passportNumber.value : '--'}
|
|
139
149
|
</span>
|
|
150
|
+
<span className={styles.middot}>· </span>
|
|
151
|
+
|
|
140
152
|
<span className={styles.spanField}>
|
|
141
153
|
{t('licenseExpiryDate', 'License expiry date')}: {formattedExpiryDate ? formattedExpiryDate : '--'}
|
|
142
154
|
</span>
|
|
@@ -42,6 +42,7 @@ import styles from './user-list.scss';
|
|
|
42
42
|
import { ConfigObject } from '../../../../config-schema';
|
|
43
43
|
import { formatDateTime } from '../../../../utils/utils';
|
|
44
44
|
import UserDetails from '../user-details/user-details.component';
|
|
45
|
+
import upperCase from 'lodash-es/upperCase';
|
|
45
46
|
|
|
46
47
|
type FilterType = 'allUsers' | 'activeLicensed' | 'expiredLicensed' | 'licensedExpiringSoon' | 'unlicensed';
|
|
47
48
|
|
|
@@ -63,8 +64,14 @@ const UserList: React.FC = () => {
|
|
|
63
64
|
const { users, isLoading: isLoadingUsers, error: usersError } = useUsers();
|
|
64
65
|
const { provider, isLoading, error: providerError } = useProvider();
|
|
65
66
|
const [syncLoading, setSyncLoading] = useState(false);
|
|
66
|
-
const {
|
|
67
|
-
|
|
67
|
+
const {
|
|
68
|
+
licenseNumberUuid,
|
|
69
|
+
licenseExpiryDateUuid,
|
|
70
|
+
providerNationalIdUuid,
|
|
71
|
+
licenseBodyUuid,
|
|
72
|
+
passportNumberUuid,
|
|
73
|
+
providerUniqueIdentifierAttributeTypeUuid,
|
|
74
|
+
} = useConfig<ConfigObject>();
|
|
68
75
|
|
|
69
76
|
const [pageSize, setPageSize] = useState(10);
|
|
70
77
|
const [searchQuery, setSearchQuery] = useState('');
|
|
@@ -198,6 +205,10 @@ const UserList: React.FC = () => {
|
|
|
198
205
|
key: 'licenseNumber',
|
|
199
206
|
header: t('licenseNumber', 'License Number'),
|
|
200
207
|
},
|
|
208
|
+
{
|
|
209
|
+
key: 'providerUniqueIdentifier',
|
|
210
|
+
header: t('providerUniqueIdentifier', 'Provider Unique Identifier'),
|
|
211
|
+
},
|
|
201
212
|
{
|
|
202
213
|
key: 'licenseExpiryDate',
|
|
203
214
|
header: t('licenseExpiryDate', 'License Expiry Date'),
|
|
@@ -221,6 +232,11 @@ const UserList: React.FC = () => {
|
|
|
221
232
|
const licenseNumber = licenseNumberAttribute ? licenseNumberAttribute.value : '--';
|
|
222
233
|
const licenseExpiryDate = licenseExpiryDateAttribute ? licenseExpiryDateAttribute.value : '--';
|
|
223
234
|
|
|
235
|
+
const providerUniqueIdentifierAttribute = userProvider?.attributes.find(
|
|
236
|
+
(attr) => attr?.attributeType?.uuid === providerUniqueIdentifierAttributeTypeUuid,
|
|
237
|
+
);
|
|
238
|
+
const providerUniqueIdentifier = providerUniqueIdentifierAttribute ? providerUniqueIdentifierAttribute.value : '--';
|
|
239
|
+
|
|
224
240
|
const providerNationalId = userProvider?.attributes.find(
|
|
225
241
|
(attr) => attr?.attributeType?.uuid === providerNationalIdUuid,
|
|
226
242
|
);
|
|
@@ -232,9 +248,10 @@ const UserList: React.FC = () => {
|
|
|
232
248
|
return {
|
|
233
249
|
id: user.uuid,
|
|
234
250
|
systemId: user.systemId,
|
|
235
|
-
names:
|
|
251
|
+
names: upperCase(user.person.display),
|
|
236
252
|
licenseNumber: licenseNumber,
|
|
237
253
|
licenseExpiryDate: formatDateTime(new Date(licenseExpiryDate)),
|
|
254
|
+
providerUniqueIdentifier: providerUniqueIdentifier,
|
|
238
255
|
userProvider,
|
|
239
256
|
user,
|
|
240
257
|
actions: (
|
|
@@ -101,6 +101,7 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
101
101
|
providerNationalIdUuid,
|
|
102
102
|
licenseNumberUuid,
|
|
103
103
|
licenseExpiryDateUuid,
|
|
104
|
+
providerUniqueIdentifierAttributeTypeUuid,
|
|
104
105
|
} = useConfig<ConfigObject>();
|
|
105
106
|
const [searchHWR, setSearchHWR] = useState({
|
|
106
107
|
identifierType: identifierTypes[0]?.key ?? '',
|
|
@@ -121,6 +122,8 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
121
122
|
phoneNumber: providerAttributeType.find((type) => type.uuid === phoneNumberUuid)?.uuid || '',
|
|
122
123
|
providerAddress: providerAttributeType.find((type) => type.uuid === providerAddressUuid)?.uuid || '',
|
|
123
124
|
passportNumber: providerAttributeType.find((type) => type.uuid === passportNumberUuid)?.uuid || '',
|
|
125
|
+
providerUniqueIdentifier:
|
|
126
|
+
providerAttributeType.find((type) => type.uuid === providerUniqueIdentifierAttributeTypeUuid)?.uuid || '',
|
|
124
127
|
};
|
|
125
128
|
}, [
|
|
126
129
|
licenseBodyUuid,
|
|
@@ -133,6 +136,7 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
133
136
|
providerHieFhirReference,
|
|
134
137
|
providerNationalIdUuid,
|
|
135
138
|
qualificationUuid,
|
|
139
|
+
providerUniqueIdentifierAttributeTypeUuid,
|
|
136
140
|
]);
|
|
137
141
|
|
|
138
142
|
const providerAttributes = useMemo(() => provider.flatMap((item) => item.attributes || []), [provider]);
|
|
@@ -176,6 +180,10 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
176
180
|
() => getProviderAttributeValue(attributeTypeMapping.providerAddress),
|
|
177
181
|
[attributeTypeMapping, getProviderAttributeValue],
|
|
178
182
|
);
|
|
183
|
+
const providerUniqueIdentifier = useMemo(
|
|
184
|
+
() => getProviderAttributeValue(attributeTypeMapping.providerUniqueIdentifier),
|
|
185
|
+
[attributeTypeMapping, getProviderAttributeValue],
|
|
186
|
+
);
|
|
179
187
|
type UserFormSchema = z.infer<typeof userManagementFormSchema>;
|
|
180
188
|
const formDefaultValues = useMemo(() => {
|
|
181
189
|
if (isInitialValuesEmpty) {
|
|
@@ -208,6 +216,7 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
208
216
|
nationalId: nationalId,
|
|
209
217
|
passportNumber: passportNumber,
|
|
210
218
|
registrationNumber: registrationNumber,
|
|
219
|
+
providerUniqueIdentifier: providerUniqueIdentifier,
|
|
211
220
|
};
|
|
212
221
|
}, [
|
|
213
222
|
isInitialValuesEmpty,
|
|
@@ -220,6 +229,7 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
220
229
|
nationalId,
|
|
221
230
|
passportNumber,
|
|
222
231
|
registrationNumber,
|
|
232
|
+
providerUniqueIdentifier,
|
|
223
233
|
]);
|
|
224
234
|
|
|
225
235
|
function extractAttributeValue(attributes, prefix: string) {
|
|
@@ -330,6 +340,7 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
330
340
|
),
|
|
331
341
|
);
|
|
332
342
|
setValue('passportNumber', healthWorkerPassPortNumber);
|
|
343
|
+
setValue('providerUniqueIdentifier', fetchedHealthWorker?.entry[0]?.resource?.id);
|
|
333
344
|
setHealthWorker(fetchedHealthWorker);
|
|
334
345
|
},
|
|
335
346
|
});
|
|
@@ -356,6 +367,10 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
356
367
|
attributeType: attributeTypeMapping?.providerHieFhirReference,
|
|
357
368
|
value: JSON.stringify(healthWorker),
|
|
358
369
|
},
|
|
370
|
+
{
|
|
371
|
+
attributeType: attributeTypeMapping.providerUniqueIdentifier,
|
|
372
|
+
value: data.providerUniqueIdentifier,
|
|
373
|
+
},
|
|
359
374
|
{
|
|
360
375
|
attributeType: attributeTypeMapping.providerNationalId,
|
|
361
376
|
value: data.nationalId,
|
|
@@ -446,6 +461,10 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
446
461
|
attributeType: passportNumberUuid,
|
|
447
462
|
value: data?.passportNumber,
|
|
448
463
|
},
|
|
464
|
+
{
|
|
465
|
+
attributeType: providerUniqueIdentifierAttributeTypeUuid,
|
|
466
|
+
value: data?.providerUniqueIdentifier,
|
|
467
|
+
},
|
|
449
468
|
].filter((attr) => attr?.value !== undefined && attr?.value !== null && attr?.value !== '');
|
|
450
469
|
|
|
451
470
|
await Promise.all(
|
|
@@ -747,6 +766,26 @@ const ManageUserWorkspace: React.FC<ManageUserWorkspaceProps> = ({
|
|
|
747
766
|
{hasProviderAccount && (
|
|
748
767
|
<ResponsiveWrapper>
|
|
749
768
|
<span className={styles.formHeaderSection}>{t('providerDetails', 'Provider details')}</span>
|
|
769
|
+
<ResponsiveWrapper>
|
|
770
|
+
<Controller
|
|
771
|
+
name="providerUniqueIdentifier"
|
|
772
|
+
control={userFormMethods.control}
|
|
773
|
+
render={({ field }) => (
|
|
774
|
+
<TextInput
|
|
775
|
+
{...field}
|
|
776
|
+
id="providerUniqueIdentifier"
|
|
777
|
+
type="text"
|
|
778
|
+
labelText={t('providerUniqueIdentifier', 'Provider Unique Identifier')}
|
|
779
|
+
placeholder={t(
|
|
780
|
+
'providerUniqueIdentifierPlaceholder',
|
|
781
|
+
'Enter Provider Unqiue Identifier',
|
|
782
|
+
)}
|
|
783
|
+
invalid={!!errors.providerUniqueIdentifier}
|
|
784
|
+
invalidText={errors.providerUniqueIdentifier?.message}
|
|
785
|
+
/>
|
|
786
|
+
)}
|
|
787
|
+
/>
|
|
788
|
+
</ResponsiveWrapper>
|
|
750
789
|
<ResponsiveWrapper>
|
|
751
790
|
<Controller
|
|
752
791
|
name="nationalId"
|
|
@@ -43,6 +43,7 @@ const UserManagementFormSchema = (existingUsernames: Array<string>, isEdit?: boo
|
|
|
43
43
|
nationalId: z.string().optional(),
|
|
44
44
|
passportNumber: z.string().optional(),
|
|
45
45
|
isEditProvider: z.boolean().optional(),
|
|
46
|
+
providerUniqueIdentifier: z.string().optional(),
|
|
46
47
|
});
|
|
47
48
|
|
|
48
49
|
return { userManagementFormSchema };
|
package/src/config-schema.ts
CHANGED
|
@@ -57,6 +57,11 @@ export const configSchema = {
|
|
|
57
57
|
_description: 'UUID for person phone number attribute',
|
|
58
58
|
_default: 'b2c38640-2603-4629-aebd-3b54f33f1e3a',
|
|
59
59
|
},
|
|
60
|
+
providerUniqueIdentifierAttributeTypeUuid: {
|
|
61
|
+
_type: Type.String,
|
|
62
|
+
_description: 'UUID for provider unique identifier attribute type',
|
|
63
|
+
_default: 'dace9d99-9f29-4653-9eae-c05929f34a32',
|
|
64
|
+
},
|
|
60
65
|
identifierTypes: {
|
|
61
66
|
_type: Type.Array,
|
|
62
67
|
_elements: {
|
|
@@ -84,6 +89,7 @@ export interface ConfigObject {
|
|
|
84
89
|
providerNationalIdUuid: string;
|
|
85
90
|
passportNumberUuid: string;
|
|
86
91
|
providerHieFhirReference: string;
|
|
92
|
+
providerUniqueIdentifierAttributeTypeUuid: string;
|
|
87
93
|
phoneNumberUuid: string;
|
|
88
94
|
providerAddressUuid: string;
|
|
89
95
|
qualificationUuid: string;
|
package/translations/en.json
CHANGED
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"phoneNumber": "Phone number",
|
|
67
67
|
"previousPage": "Previous page",
|
|
68
68
|
"procedure": "Procedure",
|
|
69
|
+
"providerUniqueIdentifier": "Provider Unique Identifier",
|
|
69
70
|
"recreated": "recreated",
|
|
70
71
|
"recreateDatatools": "Recreate datatools",
|
|
71
72
|
"recreateFacilityWideTables": "Recreate facility wide tables",
|