@kenyaemr/esm-facility-dashboard-app 5.4.2-pre.2122 → 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.
Files changed (32) hide show
  1. package/.turbo/turbo-build.log +18 -18
  2. package/dist/367.js +1 -1
  3. package/dist/367.js.map +1 -1
  4. package/dist/574.js +1 -1
  5. package/dist/983.js +1 -0
  6. package/dist/983.js.map +1 -0
  7. package/dist/kenyaemr-esm-facility-dashboard-app.js +1 -1
  8. package/dist/kenyaemr-esm-facility-dashboard-app.js.buildmanifest.json +32 -32
  9. package/dist/main.js +1 -1
  10. package/dist/main.js.map +1 -1
  11. package/dist/routes.json +1 -1
  12. package/package.json +1 -1
  13. package/src/constants.ts +4 -0
  14. package/src/hooks/useFacilityDashboardSurveillance.ts +106 -28
  15. package/src/surveillance/charts/base-cumulative-progress-tracking-chart.component.tsx +50 -0
  16. package/src/surveillance/charts/base-indicator-trend-chart.component.tsx +9 -3
  17. package/src/surveillance/charts/base-progress-tracking-chart.component.tsx +16 -10
  18. package/src/surveillance/charts/charts.scss +4 -0
  19. package/src/surveillance/charts/delayed-eac-charts.component.tsx +81 -15
  20. package/src/surveillance/charts/dna-pcr-pending-chart.component.tsx +84 -15
  21. package/src/surveillance/charts/hei-final-outcome.component.tsx +80 -17
  22. package/src/surveillance/charts/hiv-not-linked-to-art.component.tsx +74 -15
  23. package/src/surveillance/charts/missed-opportunity-vl-chart.component.tsx +83 -15
  24. package/src/surveillance/charts/pbfw-not-in-prep.component.tsx +78 -29
  25. package/src/surveillance/surveillance-dashboard.component.tsx +15 -10
  26. package/src/surveillance/surveillance-filters.component.tsx +23 -16
  27. package/src/surveillance/surveillance.scss +14 -1
  28. package/src/types/index.ts +14 -0
  29. package/translations/en.json +31 -12
  30. package/dist/561.js +0 -1
  31. package/dist/561.js.map +0 -1
  32. 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.2122"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-facility-dashboard-app",
3
- "version": "5.4.2-pre.2122",
3
+ "version": "5.4.2-pre.2126",
4
4
  "description": "Facility dashboard app",
5
5
  "browser": "dist/kenyaemr-esm-facility-dashboard-app.js",
6
6
  "main": "src/index.ts",
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, formatDatetime, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
1
+ import { FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
2
  import useSWR from 'swr';
3
- import { IndicationMode, type SurveillanceSummary } from '../types';
4
- import { useCallback } from 'react';
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 && endDate
10
- ? `${restBaseUrl}/kenyaemr/facility-dashboard?startDate=${formattedDate(startDate)}&endDate=${formattedDate(
11
- endDate,
12
- )}`
13
- : `${restBaseUrl}/kenyaemr/facility-dashboard?startDate=${formattedDate(today())}&endDate=${formattedDate(
14
- sevenDaysAgo(),
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
- const getIndication = useCallback((indicator: number, denominator: number, threshold: number): IndicationMode => {
19
- if (denominator === 0 || indicator <= denominator * threshold) {
20
- return 'decreasing';
21
- }
22
- return 'increasing';
23
- }, []);
24
- const getPercentage = useCallback((indicator: number, denominator: number): string => {
25
- if (indicator === null || indicator === undefined || denominator === null || denominator === undefined) {
26
- return `- %`;
27
- }
28
- if (denominator === 0) {
29
- return '0 %';
30
- }
31
- const percent = (indicator / denominator) * 100;
32
- return `${percent.toFixed(2)} %`;
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 = '400px' }) => {
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: [minValue, maxValue],
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: string; key: string; value: number }>;
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: t('progresstracking', 'Progress tracking'),
21
+ title: stackTitle,
16
22
  legend: {
17
23
  enabled: true,
18
24
  },
19
25
  axes: {
20
26
  bottom: {
21
- title: t('days', 'Days'),
22
- mapsTo: 'key',
27
+ title: t('day', 'Day'),
28
+ mapsTo: 'day',
23
29
  scaleType: ScaleTypes.LABELS,
24
30
  },
25
31
  left: {
26
- title: t('percentage', 'Percentage'),
32
+ title: leftAxiTtitle,
27
33
  mapsTo: 'value',
28
34
  scaleType: ScaleTypes.LINEAR,
29
- percentage: true,
35
+ domain: [0, 100],
30
36
  },
31
37
  },
32
38
  color: {
33
39
  scale: {
34
- Declined: '#00416a', //Dark Imperial Blue
35
- StartedPrEP: '#c46210', //Alloy Orange
40
+ Completed: '#008000',
41
+ Pending: '#FF0000',
36
42
  },
37
43
  },
38
- height: '400px',
44
+ height,
39
45
  data: {
40
46
  groupMapsTo: 'group',
41
47
  },
@@ -8,3 +8,7 @@
8
8
  .chart {
9
9
  margin-top: layout.$spacing-05;
10
10
  }
11
+ .cumulativeChart {
12
+ margin-top: layout.$spacing-05;
13
+ width: 50%;
14
+ }
@@ -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 { error, isLoading, surveillanceSummary } = useFacilityDashboardSurveillance(startDate, endDate);
19
+ const {
20
+ error,
21
+ isLoading,
22
+ surveillanceSummary,
23
+ getCompletedPercentage,
24
+ getPendingPercentage,
25
+ getThirtydaysRunninPercentage,
26
+ getThirtydaysRunninPendingPercentage,
27
+ } = useFacilityDashboardSurveillance(startDate, endDate);
18
28
 
19
- const delayedEACValue = useSurveillanceData(surveillanceSummary, 'getMonthlyVirallyUnsuppressedWithoutEAC');
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
- <div className={styles.chart}>
22
- {isLoading ? (
23
- <InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
24
- ) : delayedEACValue.length > 0 ? (
25
- <BaseIndicatorTrendChart
26
- data={delayedEACValue}
27
- title={t('delayedEAC', 'Delayed enhanced adherence counselling')}
28
- yAxisTitle={t('numberDelayedEAC', 'Number of Delayed EAC')}
29
- />
30
- ) : (
31
- <EmptyState subTitle={t('noDelayedEAC', 'No Delayed EAC data to display')} />
32
- )}
33
- </div>
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 { error, isLoading, surveillanceSummary } = useFacilityDashboardSurveillance(startDate, endDate);
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
- <div className={styles.chart}>
21
- {isLoading ? (
22
- <InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
23
- ) : PendingPCRDNAResultsValue.length > 0 ? (
24
- <BaseIndicatorTrendChart
25
- data={PendingPCRDNAResultsValue}
26
- title={t('dnapcrPending', 'HEI (6-8 weeks) without DNA-PCR results')}
27
- yAxisTitle={t('numberOfPendingPCRDNAResults', 'Number of HEI (6-8 weeks) without DNA-PCR results')}
28
- />
29
- ) : (
30
- <EmptyState subTitle={t('noPendingPCRDNAResults', 'No pending PCR DNA results data to display')} />
31
- )}
32
- </div>
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 { error, isLoading, surveillanceSummary } = useFacilityDashboardSurveillance(startDate, endDate);
18
-
19
- const heiFinalOutcomesValue = useSurveillanceData(
19
+ const {
20
+ error,
21
+ isLoading,
20
22
  surveillanceSummary,
21
- 'getMonthlyHei24MonthsWithoutDocumentedOutcome',
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
- <div className={styles.chart}>
25
- {isLoading ? (
26
- <InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
27
- ) : heiFinalOutcomesValue.length > 0 ? (
28
- <BaseIndicatorTrendChart
29
- data={heiFinalOutcomesValue}
30
- title={t('heiFinalOutcomes', 'Undocumented final outcome')}
31
- yAxisTitle={t('numberHEIOutcome', 'Number of undocumented final outcome')}
32
- />
33
- ) : (
34
- <EmptyState subTitle={t('noheiFinalOutcomes', 'No undocumented final outcome data to display')} />
35
- )}
36
- </div>
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