@kenyaemr/esm-facility-dashboard-app 5.4.2-pre.2120 → 5.4.2-pre.2126
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 +21 -21
- package/dist/367.js +1 -1
- package/dist/367.js.map +1 -1
- package/dist/574.js +1 -1
- package/dist/983.js +1 -0
- package/dist/983.js.map +1 -0
- package/dist/kenyaemr-esm-facility-dashboard-app.js +1 -1
- package/dist/kenyaemr-esm-facility-dashboard-app.js.buildmanifest.json +32 -32
- 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 +4 -0
- package/src/hooks/useFacilityDashboardSurveillance.ts +106 -28
- package/src/surveillance/charts/base-cumulative-progress-tracking-chart.component.tsx +50 -0
- package/src/surveillance/charts/base-indicator-trend-chart.component.tsx +9 -3
- package/src/surveillance/charts/base-progress-tracking-chart.component.tsx +16 -10
- package/src/surveillance/charts/charts.scss +4 -0
- package/src/surveillance/charts/delayed-eac-charts.component.tsx +81 -15
- package/src/surveillance/charts/dna-pcr-pending-chart.component.tsx +84 -15
- package/src/surveillance/charts/hei-final-outcome.component.tsx +80 -17
- package/src/surveillance/charts/hiv-not-linked-to-art.component.tsx +74 -15
- package/src/surveillance/charts/missed-opportunity-vl-chart.component.tsx +83 -15
- package/src/surveillance/charts/pbfw-not-in-prep.component.tsx +78 -29
- package/src/surveillance/surveillance-dashboard.component.tsx +15 -10
- package/src/surveillance/surveillance-filters.component.tsx +23 -16
- package/src/surveillance/surveillance.scss +14 -1
- package/src/types/index.ts +14 -0
- package/translations/en.json +31 -12
- package/dist/561.js +0 -1
- package/dist/561.js.map +0 -1
- package/src/surveillance/charts/base-art-progress-tracking-chart.component.tsx +0 -56
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.2-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.2-pre.2126"}
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -23,3 +23,7 @@ export const formatNewDate = (date: Date | null | undefined) => {
|
|
|
23
23
|
export const formattedDate = (date: Date) => {
|
|
24
24
|
return date ? dayjs(date).format(DATE_PICKER_FORMAT) : '';
|
|
25
25
|
};
|
|
26
|
+
|
|
27
|
+
export const thirtyDays = () => {
|
|
28
|
+
return dayjs().subtract(30, 'day').toDate();
|
|
29
|
+
};
|
|
@@ -1,44 +1,122 @@
|
|
|
1
|
-
import { FetchResponse,
|
|
1
|
+
import { FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
2
|
import useSWR from 'swr';
|
|
3
|
-
import { IndicationMode, type SurveillanceSummary } from '../types';
|
|
4
|
-
import {
|
|
3
|
+
import { HivPositiveNotLinked, IndicationMode, type SurveillanceSummary } from '../types';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
5
|
import { formattedDate, sevenDaysAgo, today } from '../constants';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Handling null/undefined/zero values
|
|
9
|
+
*/
|
|
10
|
+
const safeCalculatePercentage = (numerator: number, denominator: number): number | null => {
|
|
11
|
+
if (!numerator || !denominator || denominator === 0) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return parseFloat(((numerator / denominator) * 100).toFixed(2));
|
|
15
|
+
};
|
|
16
|
+
|
|
7
17
|
const useFacilityDashboardSurveillance = (startDate?: Date, endDate?: Date) => {
|
|
8
|
-
const url =
|
|
9
|
-
startDate
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
const { formattedStartDate, formattedEndDate, url } = useMemo(() => {
|
|
19
|
+
const formattedStartDate = startDate ? formattedDate(startDate) : formattedDate(sevenDaysAgo());
|
|
20
|
+
const formattedEndDate = endDate ? formattedDate(endDate) : formattedDate(today());
|
|
21
|
+
|
|
22
|
+
const url = `${restBaseUrl}/kenyaemr/facility-dashboard?startDate=${formattedStartDate}&endDate=${formattedEndDate}`;
|
|
23
|
+
|
|
24
|
+
return { formattedStartDate, formattedEndDate, url };
|
|
25
|
+
}, [startDate, endDate]);
|
|
16
26
|
|
|
17
27
|
const { data, error, isLoading, mutate } = useSWR<FetchResponse<SurveillanceSummary>>(url, openmrsFetch);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
|
|
29
|
+
const calculations = useMemo(() => {
|
|
30
|
+
const getIndication = (indicator: number, denominator: number, threshold: number): IndicationMode => {
|
|
31
|
+
if (denominator === 0 || indicator <= denominator * threshold) {
|
|
32
|
+
return 'decreasing';
|
|
33
|
+
}
|
|
34
|
+
return 'increasing';
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getPercentage = (indicator: number, denominator: number): string => {
|
|
38
|
+
const result = safeCalculatePercentage(indicator, denominator);
|
|
39
|
+
if (result === null) {
|
|
40
|
+
return indicator === null || indicator === undefined ? '- %' : '0 %';
|
|
41
|
+
}
|
|
42
|
+
return `${result} %`;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const getCompletedPercentage = (indicator: number, denominator: number): number | null => {
|
|
46
|
+
if (!denominator) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return safeCalculatePercentage(denominator - indicator, denominator);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const getPendingPercentage = (indicator: number, denominator: number): number | null => {
|
|
53
|
+
return safeCalculatePercentage(indicator, denominator);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const getThirtydaysRunninPercentage = (
|
|
57
|
+
denominator: Array<HivPositiveNotLinked>,
|
|
58
|
+
numerator: Array<HivPositiveNotLinked>,
|
|
59
|
+
) => {
|
|
60
|
+
if (!denominator?.length) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const result: Array<HivPositiveNotLinked> = new Array(denominator.length * 2);
|
|
65
|
+
let index = 0;
|
|
66
|
+
|
|
67
|
+
const numeratorMap = new Map(numerator.map((item) => [item.day, item.value]));
|
|
68
|
+
|
|
69
|
+
for (const denomItem of denominator) {
|
|
70
|
+
const numValue = numeratorMap.get(denomItem.day) ?? 0;
|
|
71
|
+
const denomValue = denomItem.value;
|
|
72
|
+
|
|
73
|
+
const completedPct = denomValue > 0 ? parseFloat((((denomValue - numValue) / denomValue) * 100).toFixed(2)) : 0;
|
|
74
|
+
const pendingPct = denomValue > 0 ? parseFloat(((numValue / denomValue) * 100).toFixed(2)) : 0;
|
|
75
|
+
|
|
76
|
+
result[index++] = { day: denomItem.day, group: 'Completed', value: completedPct };
|
|
77
|
+
result[index++] = { day: denomItem.day, group: 'Pending', value: pendingPct };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return result;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const getThirtydaysRunninPendingPercentage = (
|
|
84
|
+
denominator: Array<HivPositiveNotLinked>,
|
|
85
|
+
numerator: Array<HivPositiveNotLinked>,
|
|
86
|
+
) => {
|
|
87
|
+
if (!denominator?.length) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const result: Array<HivPositiveNotLinked> = new Array(denominator.length);
|
|
92
|
+
|
|
93
|
+
const numeratorMap = new Map(numerator.map((item) => [item.day, item.value]));
|
|
94
|
+
|
|
95
|
+
return denominator.map((denomItem) => {
|
|
96
|
+
const numValue = numeratorMap.get(denomItem.day) ?? 0;
|
|
97
|
+
const denomValue = denomItem.value;
|
|
98
|
+
const pendingPct = denomValue > 0 ? parseFloat(((numValue / denomValue) * 100).toFixed(2)) : 0;
|
|
99
|
+
|
|
100
|
+
return { day: denomItem.day, group: 'Pending', value: pendingPct };
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
getIndication,
|
|
106
|
+
getPercentage,
|
|
107
|
+
getCompletedPercentage,
|
|
108
|
+
getPendingPercentage,
|
|
109
|
+
getThirtydaysRunninPercentage,
|
|
110
|
+
getThirtydaysRunninPendingPercentage,
|
|
111
|
+
};
|
|
33
112
|
}, []);
|
|
34
113
|
|
|
35
114
|
return {
|
|
36
115
|
surveillanceSummary: data?.data ?? null,
|
|
37
|
-
getIndication,
|
|
38
|
-
getPercentage,
|
|
39
116
|
isLoading,
|
|
40
117
|
mutate,
|
|
41
118
|
error,
|
|
119
|
+
...calculations,
|
|
42
120
|
};
|
|
43
121
|
};
|
|
44
122
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ScaleTypes, SimpleBarChart, BarChartOptions } 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 { LinkageData } from '../../types';
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
data: LinkageData;
|
|
10
|
+
height?: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
yAxisTitle?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const BaseCumulativeProgressTrackingChart: React.FC<Props> = ({ data, title, yAxisTitle, height = '300px' }) => {
|
|
16
|
+
const { t } = useTranslation();
|
|
17
|
+
|
|
18
|
+
const chartData = data?.data || [];
|
|
19
|
+
|
|
20
|
+
const options: BarChartOptions = {
|
|
21
|
+
title: title,
|
|
22
|
+
axes: {
|
|
23
|
+
left: {
|
|
24
|
+
title: yAxisTitle,
|
|
25
|
+
scaleType: ScaleTypes.LINEAR,
|
|
26
|
+
domain: [0, 100],
|
|
27
|
+
includeZero: true,
|
|
28
|
+
mapsTo: 'value',
|
|
29
|
+
},
|
|
30
|
+
bottom: {
|
|
31
|
+
mapsTo: 'group',
|
|
32
|
+
scaleType: ScaleTypes.LABELS,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
height: height,
|
|
36
|
+
color: {
|
|
37
|
+
scale: {
|
|
38
|
+
Completed: '#008000',
|
|
39
|
+
Pending: '#FF0000',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
return (
|
|
44
|
+
<Layer className={styles.chartContainer}>
|
|
45
|
+
<SimpleBarChart options={options} data={chartData} />
|
|
46
|
+
</Layer>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default BaseCumulativeProgressTrackingChart;
|
|
@@ -15,7 +15,7 @@ type Props = {
|
|
|
15
15
|
yAxisTitle: string;
|
|
16
16
|
height?: string;
|
|
17
17
|
};
|
|
18
|
-
const BaseIndicatorTrendChart: React.FC<Props> = ({ data, title, yAxisTitle, height = '
|
|
18
|
+
const BaseIndicatorTrendChart: React.FC<Props> = ({ data, title, yAxisTitle, height = '300px' }) => {
|
|
19
19
|
const { t } = useTranslation();
|
|
20
20
|
const [minValue, maxValue] = useChartDomain(data);
|
|
21
21
|
const options: LineChartOptions = {
|
|
@@ -27,7 +27,7 @@ const BaseIndicatorTrendChart: React.FC<Props> = ({ data, title, yAxisTitle, hei
|
|
|
27
27
|
left: {
|
|
28
28
|
title: yAxisTitle,
|
|
29
29
|
scaleType: ScaleTypes.LINEAR,
|
|
30
|
-
domain: [
|
|
30
|
+
domain: [0, 100],
|
|
31
31
|
includeZero: true,
|
|
32
32
|
mapsTo: 'value',
|
|
33
33
|
},
|
|
@@ -37,7 +37,13 @@ const BaseIndicatorTrendChart: React.FC<Props> = ({ data, title, yAxisTitle, hei
|
|
|
37
37
|
mapsTo: 'day',
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
|
-
height,
|
|
40
|
+
height: height,
|
|
41
|
+
color: {
|
|
42
|
+
scale: {
|
|
43
|
+
Completed: '#008000',
|
|
44
|
+
Pending: '#FF0000',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
41
47
|
};
|
|
42
48
|
|
|
43
49
|
return (
|
|
@@ -3,39 +3,45 @@ import { Layer } from '@carbon/react';
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import styles from './charts.scss';
|
|
6
|
+
import { useChartDomain } from '../../hooks/useSurveillanceData';
|
|
6
7
|
|
|
7
8
|
type Props = {
|
|
8
|
-
data: Array<{ group
|
|
9
|
+
data: Array<{ group?: string; day: string; value: number }>;
|
|
10
|
+
height?: string;
|
|
11
|
+
stackTitle?: string;
|
|
12
|
+
leftAxiTtitle?: string;
|
|
9
13
|
};
|
|
10
14
|
|
|
11
|
-
const BaseProgressTrackingChart: React.FC<Props> = ({ data }) => {
|
|
15
|
+
const BaseProgressTrackingChart: React.FC<Props> = ({ data, stackTitle, leftAxiTtitle, height = '300px' }) => {
|
|
12
16
|
const { t } = useTranslation();
|
|
13
17
|
|
|
18
|
+
const [minValue, maxValue] = useChartDomain(data);
|
|
19
|
+
|
|
14
20
|
const options: StackedBarChartOptions = {
|
|
15
|
-
title:
|
|
21
|
+
title: stackTitle,
|
|
16
22
|
legend: {
|
|
17
23
|
enabled: true,
|
|
18
24
|
},
|
|
19
25
|
axes: {
|
|
20
26
|
bottom: {
|
|
21
|
-
title: t('
|
|
22
|
-
mapsTo: '
|
|
27
|
+
title: t('day', 'Day'),
|
|
28
|
+
mapsTo: 'day',
|
|
23
29
|
scaleType: ScaleTypes.LABELS,
|
|
24
30
|
},
|
|
25
31
|
left: {
|
|
26
|
-
title:
|
|
32
|
+
title: leftAxiTtitle,
|
|
27
33
|
mapsTo: 'value',
|
|
28
34
|
scaleType: ScaleTypes.LINEAR,
|
|
29
|
-
|
|
35
|
+
domain: [0, 100],
|
|
30
36
|
},
|
|
31
37
|
},
|
|
32
38
|
color: {
|
|
33
39
|
scale: {
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
Completed: '#008000',
|
|
41
|
+
Pending: '#FF0000',
|
|
36
42
|
},
|
|
37
43
|
},
|
|
38
|
-
height
|
|
44
|
+
height,
|
|
39
45
|
data: {
|
|
40
46
|
groupMapsTo: 'group',
|
|
41
47
|
},
|
|
@@ -7,6 +7,8 @@ import EmptyState from '../empty-state/empty-state-log.components';
|
|
|
7
7
|
import useFacilityDashboardSurveillance from '../../hooks/useFacilityDashboardSurveillance';
|
|
8
8
|
import { useSurveillanceData } from '../../hooks/useSurveillanceData';
|
|
9
9
|
import { InlineLoading } from '@carbon/react';
|
|
10
|
+
import BaseCumulativeProgressTrackingChart from './base-cumulative-progress-tracking-chart.component';
|
|
11
|
+
import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
|
|
10
12
|
type DelayedEACChartsProps = {
|
|
11
13
|
startDate?: Date;
|
|
12
14
|
endDate?: Date;
|
|
@@ -14,23 +16,87 @@ type DelayedEACChartsProps = {
|
|
|
14
16
|
|
|
15
17
|
const DelayedEACCharts: React.FC<DelayedEACChartsProps> = ({ startDate, endDate }) => {
|
|
16
18
|
const { t } = useTranslation();
|
|
17
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
error,
|
|
21
|
+
isLoading,
|
|
22
|
+
surveillanceSummary,
|
|
23
|
+
getCompletedPercentage,
|
|
24
|
+
getPendingPercentage,
|
|
25
|
+
getThirtydaysRunninPercentage,
|
|
26
|
+
getThirtydaysRunninPendingPercentage,
|
|
27
|
+
} = useFacilityDashboardSurveillance(startDate, endDate);
|
|
18
28
|
|
|
19
|
-
const
|
|
29
|
+
const cumulativedelayedEACValueData = {
|
|
30
|
+
data: [
|
|
31
|
+
{
|
|
32
|
+
group: 'Completed',
|
|
33
|
+
value: getCompletedPercentage(
|
|
34
|
+
surveillanceSummary?.getVirallyUnsuppressedWithoutEAC,
|
|
35
|
+
surveillanceSummary?.getVirallyUnsuppressed,
|
|
36
|
+
),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
group: 'Pending',
|
|
40
|
+
value: getPendingPercentage(
|
|
41
|
+
surveillanceSummary?.getVirallyUnsuppressedWithoutEAC,
|
|
42
|
+
surveillanceSummary?.getVirallyUnsuppressed,
|
|
43
|
+
),
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const thirtyDaysrunningData = getThirtydaysRunninPercentage(
|
|
49
|
+
surveillanceSummary?.getMonthlyVirallyUnsuppressed.data,
|
|
50
|
+
surveillanceSummary?.getMonthlyVirallyUnsuppressedWithoutEAC.data,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const lineGraphData = getThirtydaysRunninPendingPercentage(
|
|
54
|
+
surveillanceSummary?.getMonthlyVirallyUnsuppressed.data,
|
|
55
|
+
surveillanceSummary?.getMonthlyVirallyUnsuppressedWithoutEAC.data,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (error) {
|
|
59
|
+
return <EmptyState subTitle={t('errorLoadingData', 'Error loading data')} />;
|
|
60
|
+
}
|
|
20
61
|
return (
|
|
21
|
-
|
|
22
|
-
{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
62
|
+
<>
|
|
63
|
+
<div className={styles.chart}>
|
|
64
|
+
{isLoading ? (
|
|
65
|
+
<InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
|
|
66
|
+
) : lineGraphData.length > 0 ? (
|
|
67
|
+
<BaseIndicatorTrendChart
|
|
68
|
+
data={lineGraphData}
|
|
69
|
+
title={t('delayedEAC', 'Delayed enhanced adherence counselling')}
|
|
70
|
+
yAxisTitle={t('numberDelayedEAC', 'Number of Delayed EAC')}
|
|
71
|
+
/>
|
|
72
|
+
) : (
|
|
73
|
+
<EmptyState subTitle={t('noDelayedEAC', 'No delayed EAC data to display')} />
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
<div className={styles.chart}>
|
|
77
|
+
{thirtyDaysrunningData.length > 0 ? (
|
|
78
|
+
<BaseProgressTrackingChart
|
|
79
|
+
data={thirtyDaysrunningData}
|
|
80
|
+
stackTitle={t('progressInAddressingDelayedEAC', 'Progress in addressing delayed EAC')}
|
|
81
|
+
leftAxiTtitle={t('percentageDelayedEAC', '% Delayed EAC')}
|
|
82
|
+
/>
|
|
83
|
+
) : (
|
|
84
|
+
<EmptyState subTitle={t('noPendingPCRDNAResults', 'No pending PCR DNA results data to display')} />
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
<div className={styles.chart}>
|
|
88
|
+
{surveillanceSummary?.getVirallyUnsuppressed > 0 ? (
|
|
89
|
+
<div className={styles.cumulativeChart}>
|
|
90
|
+
<BaseCumulativeProgressTrackingChart
|
|
91
|
+
data={cumulativedelayedEACValueData}
|
|
92
|
+
title={t('cumulativeProgressDelayedEAC', 'Cumulative Progress in addressing delayed EAC')}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
) : (
|
|
96
|
+
<EmptyState subTitle={t('noDelayedEAC', 'No delayed EAC data to display')} />
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
</>
|
|
34
100
|
);
|
|
35
101
|
};
|
|
36
102
|
|
|
@@ -7,29 +7,98 @@ import useFacilityDashboardSurveillance from '../../hooks/useFacilityDashboardSu
|
|
|
7
7
|
import { useSurveillanceData } from '../../hooks/useSurveillanceData';
|
|
8
8
|
import EmptyState from '../empty-state/empty-state-log.components';
|
|
9
9
|
import { InlineLoading } from '@carbon/react';
|
|
10
|
+
import BaseCumulativeProgressTrackingChart from './base-cumulative-progress-tracking-chart.component';
|
|
11
|
+
import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
|
|
10
12
|
type DNAPCRPendingChartsProps = {
|
|
11
13
|
startDate?: Date;
|
|
12
14
|
endDate?: Date;
|
|
13
15
|
};
|
|
14
16
|
const DNAPCRPendingCharts: React.FC<DNAPCRPendingChartsProps> = ({ startDate, endDate }) => {
|
|
15
17
|
const { t } = useTranslation();
|
|
16
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
error,
|
|
20
|
+
isLoading,
|
|
21
|
+
surveillanceSummary,
|
|
22
|
+
getCompletedPercentage,
|
|
23
|
+
getPendingPercentage,
|
|
24
|
+
getThirtydaysRunninPercentage,
|
|
25
|
+
getThirtydaysRunninPendingPercentage,
|
|
26
|
+
} = useFacilityDashboardSurveillance(startDate, endDate);
|
|
27
|
+
|
|
28
|
+
const cumulativeDnapcrPendingData = {
|
|
29
|
+
data: [
|
|
30
|
+
{
|
|
31
|
+
group: 'Completed',
|
|
32
|
+
value: getCompletedPercentage(
|
|
33
|
+
surveillanceSummary?.getHeiSixToEightWeeksWithoutPCRResults,
|
|
34
|
+
surveillanceSummary.getHeiSixToEightWeeksOld,
|
|
35
|
+
),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
group: 'Pending',
|
|
39
|
+
value: getPendingPercentage(
|
|
40
|
+
surveillanceSummary?.getHeiSixToEightWeeksWithoutPCRResults,
|
|
41
|
+
surveillanceSummary.getHeiSixToEightWeeksOld,
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const thirtyDaysrunningData = getThirtydaysRunninPercentage(
|
|
48
|
+
surveillanceSummary?.getMonthlyHeiSixToEightWeeksOld.data,
|
|
49
|
+
surveillanceSummary?.getMonthlyHeiDNAPCRPending.data,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const lineGraphData = getThirtydaysRunninPendingPercentage(
|
|
53
|
+
surveillanceSummary?.getMonthlyHeiSixToEightWeeksOld.data,
|
|
54
|
+
surveillanceSummary?.getMonthlyHeiDNAPCRPending.data,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (error) {
|
|
58
|
+
return <EmptyState subTitle={t('errorLoadingData', 'Error loading data')} />;
|
|
59
|
+
}
|
|
17
60
|
|
|
18
|
-
const PendingPCRDNAResultsValue = useSurveillanceData(surveillanceSummary, 'getMonthlyHeiDNAPCRPending');
|
|
19
61
|
return (
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
62
|
+
<>
|
|
63
|
+
<div className={styles.chart}>
|
|
64
|
+
{isLoading ? (
|
|
65
|
+
<InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
|
|
66
|
+
) : lineGraphData.length > 0 ? (
|
|
67
|
+
<BaseIndicatorTrendChart
|
|
68
|
+
data={lineGraphData}
|
|
69
|
+
title={t('dnapcrPending', 'HEI (6-8 weeks) without DNA-PCR results')}
|
|
70
|
+
yAxisTitle={t('percentageOfPendingPCRDNAResults', '% HEI (6-8 weeks) without DNA-PCR results')}
|
|
71
|
+
/>
|
|
72
|
+
) : (
|
|
73
|
+
<EmptyState subTitle={t('noPendingPCRDNAResults', 'No pending PCR DNA results data to display')} />
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
<div className={styles.chart}>
|
|
77
|
+
{thirtyDaysrunningData.length > 0 ? (
|
|
78
|
+
<BaseProgressTrackingChart
|
|
79
|
+
data={thirtyDaysrunningData}
|
|
80
|
+
stackTitle={t('progressInAddressingHEIPCRResults ', 'Progress in addressing HEI PCR results')}
|
|
81
|
+
leftAxiTtitle={t('percentageHEIPCRResults', '% HEI (6-8 weeks) PCR result')}
|
|
82
|
+
/>
|
|
83
|
+
) : (
|
|
84
|
+
<EmptyState subTitle={t('noPendingPCRDNAResults', 'No pending PCR DNA results data to display')} />
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
<div className={styles.chart}>
|
|
88
|
+
{surveillanceSummary?.getHeiSixToEightWeeksOld > 0 ? (
|
|
89
|
+
<div className={styles.cumulativeChart}>
|
|
90
|
+
<BaseCumulativeProgressTrackingChart
|
|
91
|
+
data={cumulativeDnapcrPendingData}
|
|
92
|
+
title={t('cumulativeProgressDnapcrPending', 'Cumulative Progress in addressing HEI PCR results')}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
) : (
|
|
96
|
+
<EmptyState
|
|
97
|
+
subTitle={t('noCumulativeDnapcrPending', 'No cumulative HEI (6-8 weeks) without DNA-PCR data to display')}
|
|
98
|
+
/>
|
|
99
|
+
)}
|
|
100
|
+
</div>
|
|
101
|
+
</>
|
|
33
102
|
);
|
|
34
103
|
};
|
|
35
104
|
|
|
@@ -7,6 +7,8 @@ import useFacilityDashboardSurveillance from '../../hooks/useFacilityDashboardSu
|
|
|
7
7
|
import { useSurveillanceData } from '../../hooks/useSurveillanceData';
|
|
8
8
|
import EmptyState from '../empty-state/empty-state-log.components';
|
|
9
9
|
import { InlineLoading } from '@carbon/react';
|
|
10
|
+
import BaseCumulativeProgressTrackingChart from './base-cumulative-progress-tracking-chart.component';
|
|
11
|
+
import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
|
|
10
12
|
type HEIFinalOutcomesChartProps = {
|
|
11
13
|
startDate?: Date;
|
|
12
14
|
endDate?: Date;
|
|
@@ -14,26 +16,87 @@ type HEIFinalOutcomesChartProps = {
|
|
|
14
16
|
|
|
15
17
|
const HEIFinalOutcomesChart: React.FC<HEIFinalOutcomesChartProps> = ({ startDate, endDate }) => {
|
|
16
18
|
const { t } = useTranslation();
|
|
17
|
-
const {
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const {
|
|
20
|
+
error,
|
|
21
|
+
isLoading,
|
|
20
22
|
surveillanceSummary,
|
|
21
|
-
|
|
23
|
+
getCompletedPercentage,
|
|
24
|
+
getPendingPercentage,
|
|
25
|
+
getThirtydaysRunninPercentage,
|
|
26
|
+
getThirtydaysRunninPendingPercentage,
|
|
27
|
+
} = useFacilityDashboardSurveillance(startDate, endDate);
|
|
28
|
+
|
|
29
|
+
const cumulativeHeiFinalOutcomesData = {
|
|
30
|
+
data: [
|
|
31
|
+
{
|
|
32
|
+
group: 'Completed',
|
|
33
|
+
value: getCompletedPercentage(
|
|
34
|
+
surveillanceSummary?.getHei24MonthsWithoutDocumentedOutcome,
|
|
35
|
+
surveillanceSummary?.getHei24MonthsOld,
|
|
36
|
+
),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
group: 'Pending',
|
|
40
|
+
value: getPendingPercentage(
|
|
41
|
+
surveillanceSummary?.getHei24MonthsWithoutDocumentedOutcome,
|
|
42
|
+
surveillanceSummary?.getHei24MonthsOld,
|
|
43
|
+
),
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const thirtyDaysrunningData = getThirtydaysRunninPercentage(
|
|
49
|
+
surveillanceSummary?.getMonthlyHei24MonthsOld.data,
|
|
50
|
+
surveillanceSummary?.getMonthlyHei24MonthsWithoutDocumentedOutcome.data,
|
|
22
51
|
);
|
|
52
|
+
|
|
53
|
+
const lineGraphData = getThirtydaysRunninPendingPercentage(
|
|
54
|
+
surveillanceSummary?.getMonthlyHei24MonthsOld.data,
|
|
55
|
+
surveillanceSummary?.getMonthlyHei24MonthsWithoutDocumentedOutcome.data,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (error) {
|
|
59
|
+
return <EmptyState subTitle={t('errorLoadingData', 'Error loading data')} />;
|
|
60
|
+
}
|
|
23
61
|
return (
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
62
|
+
<>
|
|
63
|
+
<div className={styles.chart}>
|
|
64
|
+
{isLoading ? (
|
|
65
|
+
<InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
|
|
66
|
+
) : lineGraphData.length > 0 ? (
|
|
67
|
+
<BaseIndicatorTrendChart
|
|
68
|
+
data={lineGraphData}
|
|
69
|
+
title={t('heiFinalOutcomes', 'Undocumented final outcome')}
|
|
70
|
+
yAxisTitle={t('percentageHEIOutcome', '% undocumented final outcome')}
|
|
71
|
+
/>
|
|
72
|
+
) : (
|
|
73
|
+
<EmptyState subTitle={t('noheiFinalOutcomes', 'No undocumented final outcome data to display')} />
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
<div className={styles.chart}>
|
|
77
|
+
{thirtyDaysrunningData.length > 0 ? (
|
|
78
|
+
<BaseProgressTrackingChart
|
|
79
|
+
data={thirtyDaysrunningData}
|
|
80
|
+
stackTitle={t('progressInAddressingHEIFinalOutcome', 'Progress in addressing HEI final Outcome')}
|
|
81
|
+
leftAxiTtitle={t('percentageHEIFinalOutcome', '% HEI final outcome')}
|
|
82
|
+
/>
|
|
83
|
+
) : (
|
|
84
|
+
<EmptyState subTitle={t('noHEIFinalOutcome', 'No HEI final outcome data to display')} />
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
<div className={styles.chart}>
|
|
88
|
+
{surveillanceSummary?.getHei24MonthsOld > 0 ? (
|
|
89
|
+
<div className={styles.cumulativeChart}>
|
|
90
|
+
<BaseCumulativeProgressTrackingChart
|
|
91
|
+
data={cumulativeHeiFinalOutcomesData}
|
|
92
|
+
title={t('cumulativeProgressHeiFinalOutcomes', 'Cumulative progress in addressing HEI final outcome')}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
) : (
|
|
96
|
+
<EmptyState subTitle={t('noheiFinalOutcomes', 'No undocumented final outcome data to display')} />
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
</>
|
|
37
100
|
);
|
|
38
101
|
};
|
|
39
102
|
|