@kenyaemr/esm-facility-dashboard-app 5.4.1-pre.1966 → 5.4.1-pre.1969
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 +12 -12
- package/dist/{152.js → 245.js} +1 -1
- package/dist/245.js.map +1 -0
- package/dist/300.js +1 -1
- package/dist/kenyaemr-esm-facility-dashboard-app.js +1 -1
- package/dist/kenyaemr-esm-facility-dashboard-app.js.buildmanifest.json +26 -26
- 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/constants.ts +14 -8
- package/src/hooks/useFacilityDashboardSurveillance.ts +1 -1
- package/src/hooks/useSurveillanceData.ts +46 -0
- package/src/surveillance/charts/base-art-progress-tracking-chart.component.tsx +56 -0
- package/src/surveillance/charts/base-indicator-trend-chart.component.tsx +12 -9
- package/src/surveillance/charts/base-progress-tracking-chart.component.tsx +2 -2
- package/src/surveillance/charts/charts.scss +0 -18
- package/src/surveillance/charts/delayed-eac-charts.component.tsx +19 -23
- package/src/surveillance/charts/dna-pcr-pending-chart.component.tsx +18 -24
- package/src/surveillance/charts/hei-final-outcome.component.tsx +19 -23
- package/src/surveillance/charts/hiv-not-linked-to-art.component.tsx +20 -41
- package/src/surveillance/charts/missed-opportunity-vl-chart.component.tsx +19 -24
- package/src/surveillance/charts/pbfw-not-in-prep.component.tsx +23 -23
- package/src/surveillance/surveillance-dashboard.component.tsx +18 -6
- package/src/types/index.ts +10 -0
- package/translations/en.json +8 -7
- package/dist/152.js.map +0 -1
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemrCharts":"^1.6.7"},"extensions":[{"component":"surveillanceDashboardLink","name":"surveillance-dashboard-link","slot":"facility-dashboard-left-panel-slot"},{"component":"aboveSiteDashboardLink","name":"above-site-dashboard-link","slot":"facility-dashboard-left-panel-slot"}],"workspaces":[],"modals":[],"pages":[{"component":"root","route":"facility-dashboard"}],"version":"5.4.1-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemrCharts":"^1.6.7"},"extensions":[{"component":"surveillanceDashboardLink","name":"surveillance-dashboard-link","slot":"facility-dashboard-left-panel-slot"},{"component":"aboveSiteDashboardLink","name":"above-site-dashboard-link","slot":"facility-dashboard-left-panel-slot"}],"workspaces":[],"modals":[],"pages":[{"component":"root","route":"facility-dashboard"}],"version":"5.4.1-pre.1969"}
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -9,9 +9,7 @@ export const today = () => {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export const sevenDaysAgo = () => {
|
|
12
|
-
|
|
13
|
-
date.setDate(date.getDate() - 7); // Subtract 7 days
|
|
14
|
-
return date;
|
|
12
|
+
return dayjs().subtract(7, 'day').toDate();
|
|
15
13
|
};
|
|
16
14
|
|
|
17
15
|
export const DATE_PICKER_CONTROL_FORMAT = 'd/m/Y';
|
|
@@ -23,13 +21,21 @@ export const formatNewDate = (date: Date | null | undefined) => {
|
|
|
23
21
|
};
|
|
24
22
|
|
|
25
23
|
// Generate Dammy dates
|
|
26
|
-
export const sevenDaysRunningDates = (index: number) => {
|
|
27
|
-
const date = new Date(
|
|
28
|
-
date.setDate(
|
|
29
|
-
|
|
30
|
-
return formattedDate;
|
|
24
|
+
export const sevenDaysRunningDates = (index: number, endDate: Date = new Date()): string => {
|
|
25
|
+
const date = new Date(endDate);
|
|
26
|
+
date.setDate(date.getDate() - index);
|
|
27
|
+
return date.toISOString().split('T')[0];
|
|
31
28
|
};
|
|
32
29
|
|
|
33
30
|
export const formattedDate = (date: Date) => {
|
|
34
31
|
return date ? dayjs(date).format(DATE_PICKER_FORMAT) : '';
|
|
35
32
|
};
|
|
33
|
+
|
|
34
|
+
export const getNumberOfDays = (startDate?: Date, endDate?: Date) => {
|
|
35
|
+
if (!startDate || !endDate) {
|
|
36
|
+
return 7;
|
|
37
|
+
}
|
|
38
|
+
const start = dayjs(startDate);
|
|
39
|
+
const end = dayjs(endDate);
|
|
40
|
+
return end.diff(start, 'day');
|
|
41
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { SurveillanceSummary } from '../types';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
|
|
5
|
+
export const useChartDomain = (
|
|
6
|
+
data: Array<{ group?: string; day: string; value: number }>,
|
|
7
|
+
valueKey = 'value',
|
|
8
|
+
minPadding = 0,
|
|
9
|
+
maxPadding = 0.1,
|
|
10
|
+
) => {
|
|
11
|
+
return useMemo(() => {
|
|
12
|
+
if (!data?.length) {
|
|
13
|
+
return [0, 10];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const values = data.map((item) => item[valueKey]);
|
|
17
|
+
const minValue = Math.min(...values);
|
|
18
|
+
const maxValue = Math.max(...values, 10);
|
|
19
|
+
|
|
20
|
+
const paddedMin = Math.floor(minValue * (1 - minPadding));
|
|
21
|
+
const paddedMax = Math.ceil(maxValue * (1 + maxPadding));
|
|
22
|
+
|
|
23
|
+
return [paddedMin, paddedMax];
|
|
24
|
+
}, [data, valueKey, minPadding, maxPadding]);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const useSurveillanceData = <T extends keyof SurveillanceSummary>(
|
|
28
|
+
surveillanceSummary: SurveillanceSummary | null,
|
|
29
|
+
key: T,
|
|
30
|
+
) => {
|
|
31
|
+
return useMemo(() => {
|
|
32
|
+
if (!surveillanceSummary || !surveillanceSummary[key]) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const data = (surveillanceSummary[key] as any)?.data || [];
|
|
37
|
+
|
|
38
|
+
return Array.isArray(data)
|
|
39
|
+
? data
|
|
40
|
+
.filter((record) => record?.day)
|
|
41
|
+
.sort((firstSurveillanceRecord, secondSurveillanceRecord) =>
|
|
42
|
+
dayjs(firstSurveillanceRecord.day).diff(dayjs(secondSurveillanceRecord.day)),
|
|
43
|
+
)
|
|
44
|
+
: data;
|
|
45
|
+
}, [surveillanceSummary, key]);
|
|
46
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ScaleTypes, StackedBarChart, StackedBarChartOptions } from '@carbon/charts-react';
|
|
2
|
+
import { Layer } from '@carbon/react';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import styles from './charts.scss';
|
|
6
|
+
import { useChartDomain } from '../../hooks/useSurveillanceData';
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
data: Array<{ group?: string; day: string; value: number }>;
|
|
10
|
+
height?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const BaseArtProgressTrackingChart: React.FC<Props> = ({ data, height = '400px' }) => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
|
|
16
|
+
const [minValue, maxValue] = useChartDomain(data);
|
|
17
|
+
|
|
18
|
+
const options: StackedBarChartOptions = {
|
|
19
|
+
title: t('progressInAddressingLinkedToArt', 'Progress in addressing Linkage to ART'),
|
|
20
|
+
legend: {
|
|
21
|
+
enabled: true,
|
|
22
|
+
},
|
|
23
|
+
axes: {
|
|
24
|
+
bottom: {
|
|
25
|
+
title: t('day', 'Day'),
|
|
26
|
+
mapsTo: 'day',
|
|
27
|
+
scaleType: ScaleTypes.LABELS,
|
|
28
|
+
},
|
|
29
|
+
left: {
|
|
30
|
+
title: t('numberHivPositive', 'Number HIV positive'),
|
|
31
|
+
mapsTo: 'value',
|
|
32
|
+
scaleType: ScaleTypes.LINEAR,
|
|
33
|
+
domain: [minValue, maxValue],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
color: {
|
|
37
|
+
scale: {
|
|
38
|
+
ContactedAndLinked: '#00416a', // Dark Imperial Blue
|
|
39
|
+
ContactedButNotLinked: '#c46210', // Alloy Orange
|
|
40
|
+
NotContacted: '#195905', // Lincoln Green
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
height,
|
|
44
|
+
data: {
|
|
45
|
+
groupMapsTo: 'group',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Layer className={styles.chartContainer}>
|
|
51
|
+
<StackedBarChart options={options} data={data} />
|
|
52
|
+
</Layer>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default BaseArtProgressTrackingChart;
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { LineChart, LineChartOptions, ScaleTypes } from '@carbon/charts-react';
|
|
2
2
|
import '@carbon/charts/styles.css';
|
|
3
3
|
import { Layer } from '@carbon/react';
|
|
4
|
-
import React from 'react';
|
|
4
|
+
import React, { useMemo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import styles from './charts.scss';
|
|
7
|
+
import { useChartDomain } from '../../hooks/useSurveillanceData';
|
|
7
8
|
|
|
8
9
|
type Props = {
|
|
9
10
|
data: Array<{
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
day: string;
|
|
12
|
+
value: number;
|
|
12
13
|
}>;
|
|
13
14
|
title: string;
|
|
14
15
|
yAxisTitle: string;
|
|
16
|
+
height?: string;
|
|
15
17
|
};
|
|
16
|
-
const BaseIndicatorTrendChart: React.FC<Props> = ({ data, title, yAxisTitle }) => {
|
|
18
|
+
const BaseIndicatorTrendChart: React.FC<Props> = ({ data, title, yAxisTitle, height = '400px' }) => {
|
|
17
19
|
const { t } = useTranslation();
|
|
20
|
+
const [minValue, maxValue] = useChartDomain(data);
|
|
18
21
|
const options: LineChartOptions = {
|
|
19
22
|
title: title,
|
|
20
23
|
legend: {
|
|
@@ -23,18 +26,18 @@ const BaseIndicatorTrendChart: React.FC<Props> = ({ data, title, yAxisTitle }) =
|
|
|
23
26
|
axes: {
|
|
24
27
|
left: {
|
|
25
28
|
title: yAxisTitle,
|
|
26
|
-
percentage: true,
|
|
27
29
|
scaleType: ScaleTypes.LINEAR,
|
|
30
|
+
domain: [minValue, maxValue],
|
|
28
31
|
includeZero: true,
|
|
29
|
-
mapsTo: '
|
|
32
|
+
mapsTo: 'value',
|
|
30
33
|
},
|
|
31
34
|
bottom: {
|
|
32
|
-
title: t('
|
|
35
|
+
title: t('day', 'Day'),
|
|
33
36
|
scaleType: ScaleTypes.LABELS,
|
|
34
|
-
mapsTo: '
|
|
37
|
+
mapsTo: 'day',
|
|
35
38
|
},
|
|
36
39
|
},
|
|
37
|
-
height
|
|
40
|
+
height,
|
|
38
41
|
};
|
|
39
42
|
|
|
40
43
|
return (
|
|
@@ -31,8 +31,8 @@ const BaseProgressTrackingChart: React.FC<Props> = ({ data }) => {
|
|
|
31
31
|
},
|
|
32
32
|
color: {
|
|
33
33
|
scale: {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
Declined: '#00416a', //Dark Imperial Blue
|
|
35
|
+
StartedPrEP: '#c46210', //Alloy Orange
|
|
36
36
|
},
|
|
37
37
|
},
|
|
38
38
|
height: '400px',
|
|
@@ -5,21 +5,3 @@
|
|
|
5
5
|
.chartContainer {
|
|
6
6
|
padding: layout.$spacing-05;
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
.chartGroupContainer {
|
|
10
|
-
display: flex !important;
|
|
11
|
-
flex-flow: row wrap !important;
|
|
12
|
-
}
|
|
13
|
-
.tendChart {
|
|
14
|
-
flex: 50%;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.trackingChart {
|
|
18
|
-
flex: 50;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@media (max-width: 800px) {
|
|
22
|
-
.chartGroupContainer {
|
|
23
|
-
flex-direction: column;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -3,53 +3,49 @@ import React, { useMemo } from 'react';
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
|
|
5
5
|
import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
|
|
6
|
-
import { sevenDaysRunningDates } from '../../constants';
|
|
6
|
+
import { getNumberOfDays, sevenDaysRunningDates } from '../../constants';
|
|
7
7
|
import styles from './charts.scss';
|
|
8
|
+
type DelayedEACChartsProps = {
|
|
9
|
+
startDate?: Date;
|
|
10
|
+
endDate?: Date;
|
|
11
|
+
};
|
|
8
12
|
|
|
9
|
-
const DelayedEACCharts = () => {
|
|
13
|
+
const DelayedEACCharts: React.FC<DelayedEACChartsProps> = ({ startDate, endDate }) => {
|
|
10
14
|
const { t } = useTranslation();
|
|
11
15
|
const generateRandomData = (numRecords: number) => {
|
|
12
16
|
return Array.from({ length: numRecords }, (_, i) => ({
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
day: sevenDaysRunningDates(i, endDate),
|
|
18
|
+
value: Math.floor(Math.random() * 50),
|
|
15
19
|
}));
|
|
16
20
|
};
|
|
17
21
|
|
|
22
|
+
const numberSequence = useMemo(() => Math.max(1, getNumberOfDays(startDate, endDate)), [startDate, endDate]);
|
|
23
|
+
|
|
18
24
|
const generateRandomDataProgress = (numRecords: number) => {
|
|
19
25
|
const data = [];
|
|
20
26
|
for (let i = 1; i <= numRecords; i++) {
|
|
21
27
|
data.push({
|
|
22
28
|
group: 'Pending',
|
|
23
|
-
key: sevenDaysRunningDates(i),
|
|
29
|
+
key: sevenDaysRunningDates(i, endDate),
|
|
24
30
|
value: Math.floor(Math.random() * 50),
|
|
25
31
|
});
|
|
26
32
|
data.push({
|
|
27
33
|
group: 'Completed',
|
|
28
|
-
key: sevenDaysRunningDates(i),
|
|
34
|
+
key: sevenDaysRunningDates(i, endDate),
|
|
29
35
|
value: Math.floor(Math.random() * 50),
|
|
30
36
|
});
|
|
31
37
|
}
|
|
32
38
|
return data;
|
|
33
39
|
};
|
|
34
40
|
|
|
35
|
-
const data = useMemo(() => generateRandomDataProgress(
|
|
36
|
-
|
|
37
|
-
const values = useMemo(() => generateRandomData(7), []);
|
|
41
|
+
const data = useMemo(() => generateRandomDataProgress(numberSequence), [numberSequence, startDate, endDate]);
|
|
42
|
+
const values = useMemo(() => generateRandomData(numberSequence), [numberSequence, startDate, endDate]);
|
|
38
43
|
return (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
title={t('delayedEAC', 'Delayed EAC')}
|
|
45
|
-
yAxisTitle={t('percentageDelatedEAC', '% Delayed EAC')}
|
|
46
|
-
/>
|
|
47
|
-
</div>
|
|
48
|
-
<div className={styles.trackingChart}>
|
|
49
|
-
<BaseProgressTrackingChart data={data} />
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</>
|
|
44
|
+
<BaseIndicatorTrendChart
|
|
45
|
+
data={values}
|
|
46
|
+
title={t('delayedEAC', 'Delayed enhanced adherence counselling')}
|
|
47
|
+
yAxisTitle={t('percentageDelatedEAC', '% Delayed EAC')}
|
|
48
|
+
/>
|
|
53
49
|
);
|
|
54
50
|
};
|
|
55
51
|
|
|
@@ -3,53 +3,47 @@ import React, { useMemo } from 'react';
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
|
|
5
5
|
import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
|
|
6
|
-
import { sevenDaysRunningDates } from '../../constants';
|
|
6
|
+
import { getNumberOfDays, sevenDaysRunningDates } from '../../constants';
|
|
7
7
|
import styles from './charts.scss';
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
type DNAPCRPendingChartsProps = {
|
|
9
|
+
startDate?: Date;
|
|
10
|
+
endDate?: Date;
|
|
11
|
+
};
|
|
12
|
+
const DNAPCRPendingCharts: React.FC<DNAPCRPendingChartsProps> = ({ startDate, endDate }) => {
|
|
10
13
|
const { t } = useTranslation();
|
|
11
14
|
const generateRandomData = (numRecords: number) => {
|
|
12
15
|
return Array.from({ length: numRecords }, (_, i) => ({
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
day: sevenDaysRunningDates(i, endDate),
|
|
17
|
+
value: Math.floor(Math.random() * 50),
|
|
15
18
|
}));
|
|
16
19
|
};
|
|
17
20
|
|
|
21
|
+
const numberSequence = useMemo(() => Math.max(1, getNumberOfDays(startDate, endDate)), [startDate, endDate]);
|
|
18
22
|
const generateRandomDataProgress = (numRecords: number) => {
|
|
19
23
|
const data = [];
|
|
20
24
|
for (let i = 1; i <= numRecords; i++) {
|
|
21
25
|
data.push({
|
|
22
26
|
group: 'Pending',
|
|
23
|
-
key: sevenDaysRunningDates(i),
|
|
27
|
+
key: sevenDaysRunningDates(i, endDate),
|
|
24
28
|
value: Math.floor(Math.random() * 50),
|
|
25
29
|
});
|
|
26
30
|
data.push({
|
|
27
31
|
group: 'Completed',
|
|
28
|
-
key: sevenDaysRunningDates(i),
|
|
32
|
+
key: sevenDaysRunningDates(i, endDate),
|
|
29
33
|
value: Math.floor(Math.random() * 50),
|
|
30
34
|
});
|
|
31
35
|
}
|
|
32
36
|
return data;
|
|
33
37
|
};
|
|
34
38
|
|
|
35
|
-
const data = useMemo(() => generateRandomDataProgress(
|
|
36
|
-
|
|
37
|
-
const values = useMemo(() => generateRandomData(7), []);
|
|
39
|
+
const data = useMemo(() => generateRandomDataProgress(numberSequence), [numberSequence, startDate, endDate]);
|
|
40
|
+
const values = useMemo(() => generateRandomData(numberSequence), [numberSequence, startDate, endDate]);
|
|
38
41
|
return (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
title={t('dnapcrPending', 'Pending DNA-PCR Results')}
|
|
45
|
-
yAxisTitle={t('percentagePendingPCRDNAResults', '% of pending PCR-DNA Results')}
|
|
46
|
-
/>
|
|
47
|
-
</div>
|
|
48
|
-
<div className={styles.trackingChart}>
|
|
49
|
-
<BaseProgressTrackingChart data={data} />
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</>
|
|
42
|
+
<BaseIndicatorTrendChart
|
|
43
|
+
data={values}
|
|
44
|
+
title={t('dnapcrPending', 'HEI (6-8 weeks) without DNA-PCR Results')}
|
|
45
|
+
yAxisTitle={t('percentagePendingPCRDNAResults', '% of HEI (6-8 weeks) without DNA-PCR Results')}
|
|
46
|
+
/>
|
|
53
47
|
);
|
|
54
48
|
};
|
|
55
49
|
|
|
@@ -3,53 +3,49 @@ import React, { useMemo } from 'react';
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
|
|
5
5
|
import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
|
|
6
|
-
import { sevenDaysRunningDates } from '../../constants';
|
|
6
|
+
import { getNumberOfDays, sevenDaysRunningDates } from '../../constants';
|
|
7
7
|
import styles from './charts.scss';
|
|
8
|
+
type HEIFinalOutcomesChartProps = {
|
|
9
|
+
startDate?: Date;
|
|
10
|
+
endDate?: Date;
|
|
11
|
+
};
|
|
8
12
|
|
|
9
|
-
const HEIFinalOutcomesChart = () => {
|
|
13
|
+
const HEIFinalOutcomesChart: React.FC<HEIFinalOutcomesChartProps> = ({ startDate, endDate }) => {
|
|
10
14
|
const { t } = useTranslation();
|
|
11
15
|
const generateRandomData = (numRecords: number) => {
|
|
12
16
|
return Array.from({ length: numRecords }, (_, i) => ({
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
day: sevenDaysRunningDates(i),
|
|
18
|
+
value: Math.floor(Math.random() * 50),
|
|
15
19
|
}));
|
|
16
20
|
};
|
|
17
21
|
|
|
22
|
+
const numberSequence = useMemo(() => Math.max(0, getNumberOfDays(startDate, endDate)), [startDate, endDate]);
|
|
23
|
+
|
|
18
24
|
const generateRandomDataProgress = (numRecords: number) => {
|
|
19
25
|
const data = [];
|
|
20
26
|
for (let i = 1; i <= numRecords; i++) {
|
|
21
27
|
data.push({
|
|
22
28
|
group: 'Pending',
|
|
23
|
-
key: sevenDaysRunningDates(i),
|
|
29
|
+
key: sevenDaysRunningDates(i, endDate),
|
|
24
30
|
value: Math.floor(Math.random() * 50),
|
|
25
31
|
});
|
|
26
32
|
data.push({
|
|
27
33
|
group: 'Completed',
|
|
28
|
-
key: sevenDaysRunningDates(i),
|
|
34
|
+
key: sevenDaysRunningDates(i, endDate),
|
|
29
35
|
value: Math.floor(Math.random() * 50),
|
|
30
36
|
});
|
|
31
37
|
}
|
|
32
38
|
return data;
|
|
33
39
|
};
|
|
34
40
|
|
|
35
|
-
const data = useMemo(() => generateRandomDataProgress(
|
|
36
|
-
|
|
37
|
-
const values = useMemo(() => generateRandomData(7), []);
|
|
41
|
+
const data = useMemo(() => generateRandomDataProgress(numberSequence), [numberSequence, startDate, endDate]);
|
|
42
|
+
const values = useMemo(() => generateRandomData(numberSequence), [numberSequence, startDate, endDate]);
|
|
38
43
|
return (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
title={t('heiFinalOutcomes', 'HEI Final Outcomes')}
|
|
45
|
-
yAxisTitle={t('percentageHEIOutcome', '% 24 month old HEI without documented outcomes')}
|
|
46
|
-
/>
|
|
47
|
-
</div>
|
|
48
|
-
<div className={styles.trackingChart}>
|
|
49
|
-
<BaseProgressTrackingChart data={data} />
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</>
|
|
44
|
+
<BaseIndicatorTrendChart
|
|
45
|
+
data={values}
|
|
46
|
+
title={t('heiFinalOutcomes', 'Undocumented final outcome')}
|
|
47
|
+
yAxisTitle={t('percentageHEIOutcome', '% of Undocumented final outcome')}
|
|
48
|
+
/>
|
|
53
49
|
);
|
|
54
50
|
};
|
|
55
51
|
|
|
@@ -2,54 +2,33 @@ import '@carbon/charts/styles.css';
|
|
|
2
2
|
import React, { useMemo } from 'react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
5
|
+
import BaseArtProgressTrackingChart from './base-art-progress-tracking-chart.component';
|
|
6
|
+
import useFacilityDashboardSurveillance from '../../hooks/useFacilityDashboardSurveillance';
|
|
7
|
+
import { useSurveillanceData } from '../../hooks/useSurveillanceData';
|
|
8
|
+
type HIVPositiveNotLinkedToARTProps = {
|
|
9
|
+
startDate?: Date;
|
|
10
|
+
endDate?: Date;
|
|
11
|
+
};
|
|
12
|
+
const HIVPositiveNotLinkedToART: React.FC<HIVPositiveNotLinkedToARTProps> = ({ startDate, endDate }) => {
|
|
9
13
|
const { t } = useTranslation();
|
|
10
14
|
|
|
11
|
-
const
|
|
12
|
-
return Array.from({ length: numRecords }, (_, i) => ({
|
|
13
|
-
week: sevenDaysRunningDates(i),
|
|
14
|
-
abnomallPercentage: Math.floor(Math.random() * 50),
|
|
15
|
-
}));
|
|
16
|
-
};
|
|
15
|
+
const { error, isLoading, surveillanceSummary } = useFacilityDashboardSurveillance(startDate, endDate);
|
|
17
16
|
|
|
18
|
-
const
|
|
19
|
-
const data = [];
|
|
20
|
-
for (let i = 1; i <= numRecords; i++) {
|
|
21
|
-
const formattedDate = sevenDaysRunningDates(i);
|
|
22
|
-
data.push({
|
|
23
|
-
group: 'Pending',
|
|
24
|
-
key: formattedDate,
|
|
25
|
-
value: Math.floor(Math.random() * 50),
|
|
26
|
-
});
|
|
27
|
-
data.push({
|
|
28
|
-
group: 'Completed',
|
|
29
|
-
key: formattedDate,
|
|
30
|
-
value: Math.floor(Math.random() * 50),
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
return data;
|
|
34
|
-
};
|
|
17
|
+
const hivPositivePatientValue = useSurveillanceData(surveillanceSummary, 'getMonthlyHivPositiveNotLinked');
|
|
35
18
|
|
|
36
|
-
const
|
|
19
|
+
const monthlyHivPositivePatientData = useSurveillanceData(
|
|
20
|
+
surveillanceSummary,
|
|
21
|
+
'getMonthlyHivPositiveNotLinkedPatients',
|
|
22
|
+
);
|
|
37
23
|
|
|
38
|
-
const values = useMemo(() => generateRandomData(7), []);
|
|
39
24
|
return (
|
|
40
25
|
<>
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/>
|
|
48
|
-
</div>
|
|
49
|
-
<div className={styles.trackingChart}>
|
|
50
|
-
<BaseProgressTrackingChart data={data} />
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
26
|
+
<BaseIndicatorTrendChart
|
|
27
|
+
data={hivPositivePatientValue}
|
|
28
|
+
title={t('hivPositiveNotLinkedToART', 'HIV +VE Not linked to ART')}
|
|
29
|
+
yAxisTitle={t('numberTestedPositiveNotLinked', 'no tested positive not linked')}
|
|
30
|
+
/>
|
|
31
|
+
<BaseArtProgressTrackingChart data={monthlyHivPositivePatientData} />
|
|
53
32
|
</>
|
|
54
33
|
);
|
|
55
34
|
};
|
|
@@ -3,53 +3,48 @@ import React, { useMemo } from 'react';
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
|
|
5
5
|
import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
|
|
6
|
-
import { sevenDaysRunningDates } from '../../constants';
|
|
6
|
+
import { getNumberOfDays, sevenDaysRunningDates } from '../../constants';
|
|
7
7
|
import styles from './charts.scss';
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
type MissedOpportunityChartProps = {
|
|
9
|
+
startDate?: Date;
|
|
10
|
+
endDate?: Date;
|
|
11
|
+
};
|
|
12
|
+
const MissedOpportunityChart: React.FC<MissedOpportunityChartProps> = ({ startDate, endDate }) => {
|
|
10
13
|
const { t } = useTranslation();
|
|
11
14
|
const generateRandomData = (numRecords: number) => {
|
|
12
15
|
return Array.from({ length: numRecords }, (_, i) => ({
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
day: sevenDaysRunningDates(i, endDate),
|
|
17
|
+
value: Math.floor(Math.random() * 50),
|
|
15
18
|
}));
|
|
16
19
|
};
|
|
17
20
|
|
|
21
|
+
const numberSequence = useMemo(() => Math.max(1, getNumberOfDays(startDate, endDate)), [startDate, endDate]);
|
|
22
|
+
|
|
18
23
|
const generateRandomDataProgress = (numRecords: number) => {
|
|
19
24
|
const data = [];
|
|
20
25
|
for (let i = 1; i <= numRecords; i++) {
|
|
21
26
|
data.push({
|
|
22
27
|
group: 'Pending',
|
|
23
|
-
key: sevenDaysRunningDates(i),
|
|
28
|
+
key: sevenDaysRunningDates(i, endDate),
|
|
24
29
|
value: Math.floor(Math.random() * 50),
|
|
25
30
|
});
|
|
26
31
|
data.push({
|
|
27
32
|
group: 'Completed',
|
|
28
|
-
key: sevenDaysRunningDates(i),
|
|
33
|
+
key: sevenDaysRunningDates(i, endDate),
|
|
29
34
|
value: Math.floor(Math.random() * 50),
|
|
30
35
|
});
|
|
31
36
|
}
|
|
32
37
|
return data;
|
|
33
38
|
};
|
|
34
39
|
|
|
35
|
-
const data = useMemo(() => generateRandomDataProgress(
|
|
36
|
-
|
|
37
|
-
const values = useMemo(() => generateRandomData(40), []);
|
|
40
|
+
const data = useMemo(() => generateRandomDataProgress(numberSequence), [numberSequence, startDate, endDate]);
|
|
41
|
+
const values = useMemo(() => generateRandomData(numberSequence), [numberSequence, startDate, endDate]);
|
|
38
42
|
return (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
title={t('missedoppotunityVL', 'Missed opportunity VL')}
|
|
45
|
-
yAxisTitle={t('percentageMissedVL', '% of missed opportunity VL')}
|
|
46
|
-
/>
|
|
47
|
-
</div>
|
|
48
|
-
<div className={styles.trackingChart}>
|
|
49
|
-
<BaseProgressTrackingChart data={data} />
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</>
|
|
43
|
+
<BaseIndicatorTrendChart
|
|
44
|
+
data={values}
|
|
45
|
+
title={t('missedoppotunityVL', 'Missed opportunity in viral load testing')}
|
|
46
|
+
yAxisTitle={t('percentageMissedVL', '% of missed opportunity VL')}
|
|
47
|
+
/>
|
|
53
48
|
);
|
|
54
49
|
};
|
|
55
50
|
|