@kenyaemr/esm-admin-app 5.4.4-pre.85 → 5.4.4-pre.89
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 +1 -1
- package/dist/2016.js +1 -0
- package/dist/2016.js.map +1 -0
- package/dist/2948.js +1 -1
- package/dist/2948.js.map +1 -1
- package/dist/349.js +1 -0
- package/dist/349.js.map +1 -0
- package/dist/3548.js +1 -1
- package/dist/3548.js.map +1 -1
- package/dist/487.js +1 -0
- package/dist/487.js.map +1 -0
- package/dist/6092.js +1 -1
- package/dist/6092.js.map +1 -1
- package/dist/7866.js +1 -1
- package/dist/7916.js +1 -1
- package/dist/7916.js.map +1 -1
- package/dist/kenyaemr-esm-admin-app.js +2 -2
- package/dist/kenyaemr-esm-admin-app.js.buildmanifest.json +86 -60
- package/dist/kenyaemr-esm-admin-app.js.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/components/facility-setup/facility-info.component.tsx +163 -94
- package/src/components/facility-setup/facility-info.scss +98 -55
- package/src/components/facility-setup/header/header.component.tsx +4 -10
- package/src/components/facility-setup/header/header.scss +3 -9
- package/src/components/facility-setup/shared/custom-info.component.tsx +9 -0
- package/src/components/facility-setup/shared/custom-section-card.component.tsx +10 -0
- package/src/components/facility-setup/shared/custom-status-tag.component.tsx +22 -0
- package/src/types/index.ts +29 -1
- package/dist/1425.js +0 -1
- package/dist/1425.js.map +0 -1
- package/dist/171.js +0 -1
- package/dist/171.js.map +0 -1
- package/src/components/facility-setup/card.component.tsx +0 -16
|
@@ -1,78 +1,53 @@
|
|
|
1
|
-
import { Button, Column, Grid, InlineLoading, Layer, Tile } from '@carbon/react';
|
|
1
|
+
import { Button, Column, Grid, InlineLoading, Layer, Tag, Tile } from '@carbon/react';
|
|
2
2
|
import { formatDate, parseDate, showSnackbar } from '@openmrs/esm-framework';
|
|
3
3
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { useLocalFacilityInfo, useShaFacilityInfo } from '../hook/useFacilityInfo';
|
|
6
6
|
import styles from './facility-info.scss';
|
|
7
|
-
import Card from './card.component';
|
|
8
|
-
import dayjs from 'dayjs';
|
|
9
7
|
import { syncPackagesAndInterventions } from './facility-setup.resource';
|
|
8
|
+
import { Renew, Phone, Email } from '@carbon/react/icons';
|
|
9
|
+
import { SectionCard } from './shared/custom-section-card.component';
|
|
10
|
+
import { InfoRow } from './shared/custom-info.component';
|
|
11
|
+
import { StatusTag } from './shared/custom-status-tag.component';
|
|
10
12
|
|
|
11
13
|
const FacilityInfo: React.FC = () => {
|
|
12
14
|
const { t } = useTranslation();
|
|
13
|
-
const [shouldSynchronize,
|
|
15
|
+
const [shouldSynchronize, setShouldSynchronize] = useState(false);
|
|
16
|
+
|
|
14
17
|
const {
|
|
15
18
|
shaFacility,
|
|
16
|
-
isLoading:
|
|
17
|
-
error:
|
|
18
|
-
mutate:
|
|
19
|
+
isLoading: isShaLoading,
|
|
20
|
+
error: shaError,
|
|
21
|
+
mutate: mutateSha,
|
|
19
22
|
} = useShaFacilityInfo(shouldSynchronize);
|
|
20
|
-
const {
|
|
21
|
-
|
|
22
|
-
isLoading: isLocalFacilityLoading,
|
|
23
|
-
mutate: mutateLocalFacility,
|
|
24
|
-
error: localFacilityError,
|
|
25
|
-
} = useLocalFacilityInfo();
|
|
23
|
+
const { localFacility, isLoading: isLocalLoading, mutate: mutateLocal } = useLocalFacilityInfo();
|
|
24
|
+
|
|
26
25
|
const mutateFacility = useCallback(async () => {
|
|
27
|
-
const defaultFacility = await
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
}, [mutateLocalFacility, mutateShafacility]);
|
|
34
|
-
const shaStatus = useMemo(
|
|
35
|
-
() =>
|
|
36
|
-
shaFacility?.operationalStatus
|
|
37
|
-
? `${shaFacility.operationalStatus.at(0).toUpperCase()}${shaFacility.operationalStatus
|
|
38
|
-
.slice(1)
|
|
39
|
-
?.toLocaleLowerCase()}`
|
|
40
|
-
: undefined,
|
|
41
|
-
[shaFacility],
|
|
42
|
-
);
|
|
43
|
-
const shaExpiry = useMemo(
|
|
44
|
-
() =>
|
|
45
|
-
shaFacility?.shaFacilityExpiryDate && dayjs(shaFacility.shaFacilityExpiryDate).isValid()
|
|
46
|
-
? formatDate(parseDate(shaFacility.shaFacilityExpiryDate))
|
|
47
|
-
: undefined,
|
|
48
|
-
[shaFacility],
|
|
49
|
-
);
|
|
26
|
+
const [defaultFacility, sha] = await Promise.all([mutateLocal(), mutateSha()]);
|
|
27
|
+
return { shaFacility: sha, defaultFacility };
|
|
28
|
+
}, [mutateLocal, mutateSha]);
|
|
29
|
+
|
|
30
|
+
const isLoading = isShaLoading || isLocalLoading;
|
|
50
31
|
|
|
51
32
|
const synchronizeFacilityData = useCallback(async () => {
|
|
52
33
|
try {
|
|
53
|
-
|
|
54
|
-
const { shaFacility } = await mutateFacility();
|
|
55
|
-
showSnackbar({
|
|
56
|
-
|
|
57
|
-
kind: 'success',
|
|
58
|
-
isLowContrast: true,
|
|
59
|
-
});
|
|
60
|
-
if (shaFacility.data?.source != 'HIE') {
|
|
34
|
+
setShouldSynchronize(true);
|
|
35
|
+
const { shaFacility: synced } = await mutateFacility();
|
|
36
|
+
showSnackbar({ title: t('syncingHieSuccess', 'Synchronization complete'), kind: 'success', isLowContrast: true });
|
|
37
|
+
if (synced?.data?.source !== 'HIE') {
|
|
61
38
|
showSnackbar({
|
|
62
39
|
kind: 'warning',
|
|
63
|
-
title: 'HIE
|
|
40
|
+
title: t('hieSyncFailed', 'HIE sync failed. Pulling local info.'),
|
|
64
41
|
isLowContrast: true,
|
|
65
42
|
});
|
|
66
43
|
}
|
|
67
|
-
// sync packages and intervensions
|
|
68
44
|
await syncPackagesAndInterventions();
|
|
69
45
|
} catch (error) {
|
|
70
|
-
const errorMessage =
|
|
71
|
-
error?.responseBody?.error?.message ??
|
|
72
|
-
t('hieSynchronizationError', 'An error occurred while synchronizing with HIE');
|
|
73
46
|
showSnackbar({
|
|
74
|
-
title: t('syncingHieError', 'Syncing with HIE
|
|
75
|
-
subtitle:
|
|
47
|
+
title: t('syncingHieError', 'Syncing with HIE failed'),
|
|
48
|
+
subtitle:
|
|
49
|
+
error?.responseBody?.error?.message ??
|
|
50
|
+
t('hieSynchronizationError', 'An error occurred while synchronizing with HIE'),
|
|
76
51
|
kind: 'error',
|
|
77
52
|
isLowContrast: true,
|
|
78
53
|
});
|
|
@@ -80,59 +55,153 @@ const FacilityInfo: React.FC = () => {
|
|
|
80
55
|
}, [mutateFacility, t]);
|
|
81
56
|
|
|
82
57
|
return (
|
|
83
|
-
<div className={styles.
|
|
84
|
-
<div>
|
|
85
|
-
<
|
|
86
|
-
{
|
|
87
|
-
<InlineLoading
|
|
88
|
-
description={t('synchronizingFacilityData', 'Please wait, Synchronizing Info.')}
|
|
89
|
-
className={styles.loading}
|
|
90
|
-
/>
|
|
58
|
+
<div className={styles.root}>
|
|
59
|
+
<div className={styles.pageHeader}>
|
|
60
|
+
<div className={styles.pageActions}>
|
|
61
|
+
{isLoading ? (
|
|
62
|
+
<InlineLoading description={t('synchronizing', 'Synchronizing...')} />
|
|
91
63
|
) : (
|
|
92
|
-
<Button kind="
|
|
93
|
-
{t('
|
|
64
|
+
<Button kind="secondary" size="sm" renderIcon={Renew} onClick={synchronizeFacilityData}>
|
|
65
|
+
{t('syncWithHie', 'Sync with HIE')}
|
|
94
66
|
</Button>
|
|
95
67
|
)}
|
|
96
|
-
</
|
|
68
|
+
</div>
|
|
97
69
|
</div>
|
|
70
|
+
<Grid narrow className={styles.grid}>
|
|
71
|
+
<Column sm={4} md={4} lg={8}>
|
|
72
|
+
<SectionCard title={t('generalInformation', 'General information')}>
|
|
73
|
+
<InfoRow label={t('facilityName', 'Facility name')} value={localFacility?.display} />
|
|
74
|
+
<InfoRow label={t('registrationNumber', 'Registration no.')} value={shaFacility?.registrationNumber} />
|
|
75
|
+
<InfoRow label={t('fidCode', 'FID code')} value={shaFacility?.fidCode} />
|
|
76
|
+
<InfoRow label={t('facilityRegistryCode', 'Registry code')} value={shaFacility?.facilityRegistryCode} />
|
|
77
|
+
<InfoRow
|
|
78
|
+
label={t('mflCode', 'MFL code')}
|
|
79
|
+
value={shaFacility?.mflCode !== '--' ? shaFacility?.mflCode : localFacility?.locationId}
|
|
80
|
+
/>
|
|
81
|
+
<InfoRow label={t('kephLevel', 'KEPH level')} value={shaFacility?.kephLevel} />
|
|
82
|
+
<InfoRow label={t('facilityType', 'Facility type')} value={shaFacility?.facilityType} />
|
|
83
|
+
<InfoRow label={t('facilityOwnership', 'Ownership')} value={shaFacility?.facilityOwnership} />
|
|
84
|
+
<InfoRow
|
|
85
|
+
label={t('hubFacility', 'Hub facility')}
|
|
86
|
+
value={
|
|
87
|
+
<Tag type={shaFacility?.isHub === 'true' ? 'blue' : 'gray'} size="sm">
|
|
88
|
+
{shaFacility?.isHub === 'true' ? 'Yes' : 'No'}
|
|
89
|
+
</Tag>
|
|
90
|
+
}
|
|
91
|
+
/>
|
|
92
|
+
</SectionCard>
|
|
93
|
+
</Column>
|
|
98
94
|
|
|
99
|
-
<Grid narrow>
|
|
100
|
-
{/* General Info Column */}
|
|
101
95
|
<Column sm={4} md={4} lg={8}>
|
|
102
|
-
<
|
|
103
|
-
<
|
|
104
|
-
<
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
96
|
+
<SectionCard title={t('licenseAndShaStatus', 'License & SHA status')}>
|
|
97
|
+
<InfoRow label={t('licenseNumber', 'License no.')} value={shaFacility?.shaFacilityLicenseNumber} />
|
|
98
|
+
<InfoRow label={t('regulatoryBody', 'Regulatory body')} value={shaFacility?.regulatoryBody} />
|
|
99
|
+
<InfoRow
|
|
100
|
+
label={t('licenseStatus', 'License status')}
|
|
101
|
+
value={<StatusTag value={shaFacility?.facilityLicenseStatus} />}
|
|
102
|
+
/>
|
|
103
|
+
<InfoRow
|
|
104
|
+
label={t('licenseStart', 'License start')}
|
|
105
|
+
value={formatDate(parseDate(shaFacility?.facilityLicenseStartDate)) ?? '—'}
|
|
106
|
+
/>
|
|
107
|
+
<InfoRow
|
|
108
|
+
label={t('licenseExpiry', 'License expiry')}
|
|
109
|
+
value={formatDate(parseDate(shaFacility?.shaFacilityExpiryDate)) ?? '—'}
|
|
110
|
+
/>
|
|
111
|
+
<InfoRow
|
|
112
|
+
label={t('operationalStatus', 'Operational status')}
|
|
113
|
+
value={<StatusTag value={shaFacility?.operationalStatus} />}
|
|
114
|
+
/>
|
|
115
|
+
<InfoRow
|
|
116
|
+
label={t('shaContractStatus', 'SHA contract')}
|
|
117
|
+
value={
|
|
118
|
+
shaFacility?.shaContractStatus &&
|
|
119
|
+
shaFacility.shaContractStatus !== '--' &&
|
|
120
|
+
shaFacility.shaContractStatus !== '' ? (
|
|
121
|
+
<StatusTag value={shaFacility.shaContractStatus} />
|
|
122
|
+
) : (
|
|
123
|
+
<Tag type="gray" size="sm">
|
|
124
|
+
Not contracted
|
|
125
|
+
</Tag>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
/>
|
|
129
|
+
<InfoRow label={t('totalBeds', 'Total beds')} value={shaFacility?.totalBeds} />
|
|
130
|
+
</SectionCard>
|
|
113
131
|
</Column>
|
|
114
132
|
|
|
115
|
-
{/* SHA Info Column */}
|
|
116
133
|
<Column sm={4} md={4} lg={8}>
|
|
117
|
-
<
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
<SectionCard title={t('location', 'Location')}>
|
|
135
|
+
<InfoRow label={t('county', 'County')} value={shaFacility?.county} />
|
|
136
|
+
<InfoRow label={t('subCounty', 'Sub-county')} value={shaFacility?.subCounty} />
|
|
137
|
+
<InfoRow label={t('town', 'Town')} value={shaFacility?.town} />
|
|
138
|
+
<InfoRow label={t('physicalLocation', 'Physical location')} value={shaFacility?.physicalLocation} />
|
|
139
|
+
<InfoRow label={t('postalAddress', 'Postal address')} value={shaFacility?.postalAddress} />
|
|
140
|
+
</SectionCard>
|
|
141
|
+
</Column>
|
|
142
|
+
|
|
143
|
+
<Column sm={4} md={4} lg={8}>
|
|
144
|
+
<SectionCard title={t('contactAndAdministrator', 'Contact & administrator')}>
|
|
145
|
+
<InfoRow
|
|
146
|
+
label={t('facilityPhone', 'Phone')}
|
|
147
|
+
value={
|
|
148
|
+
shaFacility?.facilityPhoneNumber && shaFacility.facilityPhoneNumber !== '--' ? (
|
|
149
|
+
<span className={styles.contactValue}>
|
|
150
|
+
<Phone size={14} />
|
|
151
|
+
{shaFacility.facilityPhoneNumber}
|
|
152
|
+
</span>
|
|
153
|
+
) : undefined
|
|
154
|
+
}
|
|
155
|
+
/>
|
|
156
|
+
<InfoRow
|
|
157
|
+
label={t('facilityEmail', 'Email')}
|
|
158
|
+
value={
|
|
159
|
+
shaFacility?.facilityEmail && shaFacility.facilityEmail !== '--' ? (
|
|
160
|
+
<span className={styles.contactValue}>
|
|
161
|
+
<Email size={14} />
|
|
162
|
+
{shaFacility.facilityEmail}
|
|
163
|
+
</span>
|
|
164
|
+
) : undefined
|
|
165
|
+
}
|
|
166
|
+
/>
|
|
167
|
+
{shaFacility?.facilityAdministratorName && shaFacility.facilityAdministratorName !== '--' && (
|
|
168
|
+
<div className={styles.adminCard}>
|
|
169
|
+
<div>
|
|
170
|
+
<p className={styles.adminName}>{shaFacility.facilityAdministratorName}</p>
|
|
171
|
+
<p className={styles.adminDetail}>{shaFacility.facilityAdministratorPhone}</p>
|
|
172
|
+
<p className={styles.adminDetail}>{shaFacility.facilityAdministratorEmail}</p>
|
|
173
|
+
</div>
|
|
133
174
|
</div>
|
|
134
|
-
|
|
135
|
-
</
|
|
175
|
+
)}
|
|
176
|
+
</SectionCard>
|
|
177
|
+
</Column>
|
|
178
|
+
|
|
179
|
+
<Column sm={4} md={8} lg={16}>
|
|
180
|
+
<SectionCard title={t('shaContractedServices', 'SHA contracted services')}>
|
|
181
|
+
{(() => {
|
|
182
|
+
try {
|
|
183
|
+
const services = JSON.parse(shaFacility?.shaContractedServices ?? '[]');
|
|
184
|
+
if (services.length === 0) {
|
|
185
|
+
return (
|
|
186
|
+
<p className={styles.emptyState}>
|
|
187
|
+
{t('noContractedServices', 'No contracted services on record for this facility.')}
|
|
188
|
+
</p>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
return (
|
|
192
|
+
<div className={styles.serviceList}>
|
|
193
|
+
{services.map((svc: any, idx: number) => (
|
|
194
|
+
<Tag key={idx} type="teal" size="sm">
|
|
195
|
+
{svc.name ?? svc}
|
|
196
|
+
</Tag>
|
|
197
|
+
))}
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
} catch {
|
|
201
|
+
return <p className={styles.emptyState}>—</p>;
|
|
202
|
+
}
|
|
203
|
+
})()}
|
|
204
|
+
</SectionCard>
|
|
136
205
|
</Column>
|
|
137
206
|
</Grid>
|
|
138
207
|
</div>
|
|
@@ -2,86 +2,129 @@
|
|
|
2
2
|
@use '@carbon/type';
|
|
3
3
|
@use '@carbon/colors';
|
|
4
4
|
|
|
5
|
-
.
|
|
6
|
-
|
|
5
|
+
.root {
|
|
6
|
+
padding: layout.$spacing-05;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
.
|
|
9
|
+
.pageHeader {
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: space-between;
|
|
10
13
|
margin-bottom: layout.$spacing-05;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
|
-
.
|
|
16
|
+
.pageTitle {
|
|
17
|
+
@include type.type-style('heading-03');
|
|
18
|
+
color: colors.$gray-100;
|
|
19
|
+
margin: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.pageActions {
|
|
14
23
|
display: flex;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
margin-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
width: 100%;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: layout.$spacing-03;
|
|
26
|
+
margin-left: auto;
|
|
27
|
+
margin-right: layout.$spacing-09;
|
|
28
|
+
}
|
|
29
|
+
.grid {
|
|
30
|
+
margin-top: 0;
|
|
23
31
|
}
|
|
24
32
|
|
|
25
|
-
.
|
|
26
|
-
padding
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
.sectionCard {
|
|
34
|
+
padding: layout.$spacing-05 !important;
|
|
35
|
+
background: white !important;
|
|
36
|
+
border: 1px solid colors.$gray-20 !important;
|
|
37
|
+
border-radius: 8px !important;
|
|
38
|
+
margin-bottom: layout.$spacing-05;
|
|
39
|
+
box-shadow: none !important;
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
.
|
|
42
|
+
.sectionTitle {
|
|
43
|
+
@include type.type-style('label-01');
|
|
44
|
+
font-weight: 600;
|
|
45
|
+
color: colors.$gray-60;
|
|
46
|
+
text-transform: uppercase;
|
|
47
|
+
letter-spacing: 0.06em;
|
|
48
|
+
margin: 0 0 layout.$spacing-04;
|
|
49
|
+
padding-bottom: layout.$spacing-03;
|
|
50
|
+
border-bottom: 1px solid colors.$gray-20;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.sectionBody {
|
|
33
54
|
display: flex;
|
|
34
|
-
|
|
35
|
-
padding-right: layout.$spacing-05;
|
|
36
|
-
padding-bottom: layout.$spacing-05;
|
|
37
|
-
margin-top: layout.$spacing-05;
|
|
38
|
-
flex-direction: row;
|
|
39
|
-
justify-content: flex-end;
|
|
40
|
-
background-color: white;
|
|
41
|
-
width: 100%;
|
|
55
|
+
flex-direction: column;
|
|
42
56
|
}
|
|
43
57
|
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
/* ── Info rows ── */
|
|
59
|
+
.infoRow {
|
|
60
|
+
display: flex;
|
|
61
|
+
justify-content: space-between;
|
|
62
|
+
align-items: baseline;
|
|
63
|
+
padding: layout.$spacing-02 0;
|
|
64
|
+
border-bottom: 1px solid colors.$gray-10;
|
|
65
|
+
|
|
66
|
+
&:last-child {
|
|
67
|
+
border-bottom: none;
|
|
68
|
+
}
|
|
46
69
|
}
|
|
47
70
|
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
71
|
+
.infoLabel {
|
|
72
|
+
@include type.type-style('body-01');
|
|
73
|
+
color: colors.$gray-60;
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
margin-right: layout.$spacing-05;
|
|
54
76
|
}
|
|
55
77
|
|
|
56
|
-
.
|
|
57
|
-
|
|
58
|
-
font-
|
|
59
|
-
|
|
78
|
+
.infoValue {
|
|
79
|
+
@include type.type-style('body-01');
|
|
80
|
+
font-weight: 500;
|
|
81
|
+
color: colors.$gray-100;
|
|
82
|
+
text-align: right;
|
|
83
|
+
word-break: break-word;
|
|
60
84
|
}
|
|
61
85
|
|
|
62
|
-
.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
margin: 0.5rem 0;
|
|
86
|
+
.emptyValue {
|
|
87
|
+
color: colors.$gray-40;
|
|
88
|
+
font-weight: 400;
|
|
66
89
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
|
|
91
|
+
.contactValue {
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
gap: layout.$spacing-02;
|
|
70
95
|
}
|
|
71
96
|
|
|
72
|
-
.
|
|
97
|
+
.adminCard {
|
|
73
98
|
display: flex;
|
|
74
|
-
|
|
75
|
-
|
|
99
|
+
align-items: flex-start;
|
|
100
|
+
gap: layout.$spacing-04;
|
|
101
|
+
margin-top: layout.$spacing-04;
|
|
102
|
+
padding-top: layout.$spacing-04;
|
|
103
|
+
border-top: 1px solid colors.$gray-10;
|
|
76
104
|
}
|
|
77
|
-
.
|
|
105
|
+
.adminName {
|
|
106
|
+
@include type.type-style('body-01');
|
|
107
|
+
font-weight: 500;
|
|
108
|
+
color: colors.$gray-100;
|
|
109
|
+
margin: 0 0 layout.$spacing-01;
|
|
110
|
+
text-transform: capitalize;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.adminDetail {
|
|
114
|
+
@include type.type-style('label-01');
|
|
115
|
+
color: colors.$gray-60;
|
|
116
|
+
margin: 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.serviceList {
|
|
78
120
|
display: flex;
|
|
79
|
-
|
|
80
|
-
|
|
121
|
+
flex-wrap: wrap;
|
|
122
|
+
gap: layout.$spacing-02;
|
|
81
123
|
}
|
|
82
124
|
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
125
|
+
.emptyState {
|
|
126
|
+
@include type.type-style('body-01');
|
|
127
|
+
color: colors.$gray-40;
|
|
128
|
+
font-style: italic;
|
|
129
|
+
margin: 0;
|
|
87
130
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { Development } from '@carbon/react/icons';
|
|
4
|
-
import { useSession, PageHeader } from '@openmrs/esm-framework';
|
|
2
|
+
import { PageHeader, PageHeaderContent, HomePictogram } from '@openmrs/esm-framework';
|
|
5
3
|
import styles from './header.scss';
|
|
6
4
|
|
|
7
5
|
interface HeaderProps {
|
|
@@ -9,14 +7,10 @@ interface HeaderProps {
|
|
|
9
7
|
}
|
|
10
8
|
|
|
11
9
|
const Header: React.FC<HeaderProps> = ({ title }) => {
|
|
12
|
-
const { t } = useTranslation();
|
|
13
|
-
const session = useSession();
|
|
14
|
-
const location = session?.sessionLocation?.display;
|
|
15
|
-
|
|
16
10
|
return (
|
|
17
|
-
<
|
|
18
|
-
<
|
|
19
|
-
</
|
|
11
|
+
<PageHeader className={styles.pageHeader}>
|
|
12
|
+
<PageHeaderContent title={title} illustration={<HomePictogram />} />
|
|
13
|
+
</PageHeader>
|
|
20
14
|
);
|
|
21
15
|
};
|
|
22
16
|
|
|
@@ -2,18 +2,12 @@
|
|
|
2
2
|
@use '@carbon/type';
|
|
3
3
|
@use '@carbon/colors';
|
|
4
4
|
|
|
5
|
-
.
|
|
5
|
+
.pageHeader {
|
|
6
6
|
@include type.type-style('body-compact-02');
|
|
7
7
|
height: layout.$spacing-12;
|
|
8
8
|
display: flex;
|
|
9
9
|
justify-content: space-between;
|
|
10
10
|
padding: layout.$spacing-05;
|
|
11
|
-
background: white;
|
|
12
|
-
border: 1px solid colors.$gray-20;
|
|
13
|
-
}
|
|
14
|
-
.svgContainer svg {
|
|
15
|
-
width: layout.$spacing-10;
|
|
16
|
-
height: layout.$spacing-10;
|
|
17
|
-
margin-right: layout.$spacing-06;
|
|
18
|
-
fill: var(--brand-03);
|
|
11
|
+
background: colors.$white-0;
|
|
12
|
+
border-bottom: 1px solid colors.$gray-20;
|
|
19
13
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from '../facility-info.scss';
|
|
3
|
+
|
|
4
|
+
export const InfoRow: React.FC<{ label: string; value?: React.ReactNode }> = ({ label, value }) => (
|
|
5
|
+
<div className={styles.infoRow}>
|
|
6
|
+
<span className={styles.infoLabel}>{label}</span>
|
|
7
|
+
<span className={styles.infoValue}>{value ?? <span className={styles.emptyValue}>—</span>}</span>
|
|
8
|
+
</div>
|
|
9
|
+
);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Tile } from '@carbon/react';
|
|
3
|
+
import styles from '../facility-info.scss';
|
|
4
|
+
|
|
5
|
+
export const SectionCard: React.FC<{ title: string; children: React.ReactNode }> = ({ title, children }) => (
|
|
6
|
+
<Tile className={styles.sectionCard}>
|
|
7
|
+
<p className={styles.sectionTitle}>{title}</p>
|
|
8
|
+
<div className={styles.sectionBody}>{children}</div>
|
|
9
|
+
</Tile>
|
|
10
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Tag } from '@carbon/react';
|
|
3
|
+
import styles from '../facility-info.scss';
|
|
4
|
+
|
|
5
|
+
export const StatusTag: React.FC<{ value?: string }> = ({ value }) => {
|
|
6
|
+
if (!value || value === '--' || value.trim() === '') {
|
|
7
|
+
return <span className={styles.emptyValue}>—</span>;
|
|
8
|
+
}
|
|
9
|
+
const upper = value.toUpperCase();
|
|
10
|
+
const type =
|
|
11
|
+
upper === 'ACTIVE' || upper === 'LICENSED'
|
|
12
|
+
? 'green'
|
|
13
|
+
: upper === 'INACTIVE' || upper === 'SUSPENDED'
|
|
14
|
+
? 'red'
|
|
15
|
+
: 'gray';
|
|
16
|
+
const label = `${value.charAt(0).toUpperCase()}${value.slice(1).toLowerCase()}`;
|
|
17
|
+
return (
|
|
18
|
+
<Tag type={type} size="sm">
|
|
19
|
+
{label}
|
|
20
|
+
</Tag>
|
|
21
|
+
);
|
|
22
|
+
};
|
package/src/types/index.ts
CHANGED
|
@@ -27,8 +27,36 @@ export interface SHAFacility {
|
|
|
27
27
|
shaFacilityLicenseNumber: string;
|
|
28
28
|
facilityRegistryCode: string;
|
|
29
29
|
source: string;
|
|
30
|
+
officialName: string;
|
|
31
|
+
facilityType: string;
|
|
32
|
+
facilityOwnership: string;
|
|
33
|
+
fidCode: string;
|
|
34
|
+
isHub: string;
|
|
35
|
+
facilityLicenseStatus: string;
|
|
36
|
+
facilityLicenseStartDate: string;
|
|
37
|
+
regulatoryBody: string;
|
|
38
|
+
shaContractStatus: string;
|
|
39
|
+
shaContractStartDate: string;
|
|
40
|
+
shaContractEndDate: string;
|
|
41
|
+
facilityPhoneNumber: string;
|
|
42
|
+
facilityEmail: string;
|
|
43
|
+
facilityAdministratorName: string;
|
|
44
|
+
facilityAdministratorPhone: string;
|
|
45
|
+
facilityAdministratorEmail: string;
|
|
46
|
+
county: string;
|
|
47
|
+
subCounty: string;
|
|
48
|
+
town: string;
|
|
49
|
+
physicalLocation: string;
|
|
50
|
+
postalAddress: string;
|
|
51
|
+
latitude: string;
|
|
52
|
+
longitude: string;
|
|
53
|
+
totalBeds: string;
|
|
54
|
+
normalBeds: string;
|
|
55
|
+
icuBeds: string;
|
|
56
|
+
hduBeds: string;
|
|
57
|
+
dialysisBeds: string;
|
|
58
|
+
shaContractedServices: string;
|
|
30
59
|
}
|
|
31
|
-
|
|
32
60
|
export interface DefaultFacility {
|
|
33
61
|
locationId: number;
|
|
34
62
|
uuid: string;
|