@kenyaemr/esm-facility-dashboard-app 5.4.1-pre.2025 → 5.4.1-pre.2029

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/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.2025"}
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.2029"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-facility-dashboard-app",
3
- "version": "5.4.1-pre.2025",
3
+ "version": "5.4.1-pre.2029",
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
@@ -20,22 +20,6 @@ export const formatNewDate = (date: Date | null | undefined) => {
20
20
  return date ? new Date(date) : '';
21
21
  };
22
22
 
23
- // Generate Dammy dates
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];
28
- };
29
-
30
23
  export const formattedDate = (date: Date) => {
31
24
  return date ? dayjs(date).format(DATE_PICKER_FORMAT) : '';
32
25
  };
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
- };
@@ -1,10 +1,12 @@
1
1
  import '@carbon/charts/styles.css';
2
- import React, { useMemo } from 'react';
2
+ import React from 'react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
5
- import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
6
- import { getNumberOfDays, sevenDaysRunningDates } from '../../constants';
7
5
  import styles from './charts.scss';
6
+ import EmptyState from '../empty-state/empty-state-log.components';
7
+ import useFacilityDashboardSurveillance from '../../hooks/useFacilityDashboardSurveillance';
8
+ import { useSurveillanceData } from '../../hooks/useSurveillanceData';
9
+ import { InlineLoading } from '@carbon/react';
8
10
  type DelayedEACChartsProps = {
9
11
  startDate?: Date;
10
12
  endDate?: Date;
@@ -12,40 +14,23 @@ type DelayedEACChartsProps = {
12
14
 
13
15
  const DelayedEACCharts: React.FC<DelayedEACChartsProps> = ({ startDate, endDate }) => {
14
16
  const { t } = useTranslation();
15
- const generateRandomData = (numRecords: number) => {
16
- return Array.from({ length: numRecords }, (_, i) => ({
17
- day: sevenDaysRunningDates(i, endDate),
18
- value: Math.floor(Math.random() * 50),
19
- }));
20
- };
17
+ const { error, isLoading, surveillanceSummary } = useFacilityDashboardSurveillance(startDate, endDate);
21
18
 
22
- const numberSequence = useMemo(() => Math.max(1, getNumberOfDays(startDate, endDate)), [startDate, endDate]);
23
-
24
- const generateRandomDataProgress = (numRecords: number) => {
25
- const data = [];
26
- for (let i = 1; i <= numRecords; i++) {
27
- data.push({
28
- group: 'Pending',
29
- key: sevenDaysRunningDates(i, endDate),
30
- value: Math.floor(Math.random() * 50),
31
- });
32
- data.push({
33
- group: 'Completed',
34
- key: sevenDaysRunningDates(i, endDate),
35
- value: Math.floor(Math.random() * 50),
36
- });
37
- }
38
- return data;
39
- };
40
-
41
- const data = useMemo(() => generateRandomDataProgress(numberSequence), [numberSequence, startDate, endDate]);
42
- const values = useMemo(() => generateRandomData(numberSequence), [numberSequence, startDate, endDate]);
19
+ const delayedEACValue = useSurveillanceData(surveillanceSummary, 'getMonthlyVirallyUnsuppressedWithoutEAC');
43
20
  return (
44
- <BaseIndicatorTrendChart
45
- data={values}
46
- title={t('delayedEAC', 'Delayed enhanced adherence counselling')}
47
- yAxisTitle={t('percentageDelatedEAC', '% Delayed EAC')}
48
- />
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>
49
34
  );
50
35
  };
51
36
 
@@ -1,49 +1,35 @@
1
1
  import '@carbon/charts/styles.css';
2
- import React, { useMemo } from 'react';
2
+ import React from 'react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
5
- import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
6
- import { getNumberOfDays, sevenDaysRunningDates } from '../../constants';
7
5
  import styles from './charts.scss';
6
+ import useFacilityDashboardSurveillance from '../../hooks/useFacilityDashboardSurveillance';
7
+ import { useSurveillanceData } from '../../hooks/useSurveillanceData';
8
+ import EmptyState from '../empty-state/empty-state-log.components';
9
+ import { InlineLoading } from '@carbon/react';
8
10
  type DNAPCRPendingChartsProps = {
9
11
  startDate?: Date;
10
12
  endDate?: Date;
11
13
  };
12
14
  const DNAPCRPendingCharts: React.FC<DNAPCRPendingChartsProps> = ({ startDate, endDate }) => {
13
15
  const { t } = useTranslation();
14
- const generateRandomData = (numRecords: number) => {
15
- return Array.from({ length: numRecords }, (_, i) => ({
16
- day: sevenDaysRunningDates(i, endDate),
17
- value: Math.floor(Math.random() * 50),
18
- }));
19
- };
16
+ const { error, isLoading, surveillanceSummary } = useFacilityDashboardSurveillance(startDate, endDate);
20
17
 
21
- const numberSequence = useMemo(() => Math.max(1, getNumberOfDays(startDate, endDate)), [startDate, endDate]);
22
- const generateRandomDataProgress = (numRecords: number) => {
23
- const data = [];
24
- for (let i = 1; i <= numRecords; i++) {
25
- data.push({
26
- group: 'Pending',
27
- key: sevenDaysRunningDates(i, endDate),
28
- value: Math.floor(Math.random() * 50),
29
- });
30
- data.push({
31
- group: 'Completed',
32
- key: sevenDaysRunningDates(i, endDate),
33
- value: Math.floor(Math.random() * 50),
34
- });
35
- }
36
- return data;
37
- };
38
-
39
- const data = useMemo(() => generateRandomDataProgress(numberSequence), [numberSequence, startDate, endDate]);
40
- const values = useMemo(() => generateRandomData(numberSequence), [numberSequence, startDate, endDate]);
18
+ const PendingPCRDNAResultsValue = useSurveillanceData(surveillanceSummary, 'getMonthlyHeiDNAPCRPending');
41
19
  return (
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
- />
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>
47
33
  );
48
34
  };
49
35
 
@@ -1,10 +1,12 @@
1
1
  import '@carbon/charts/styles.css';
2
- import React, { useMemo } from 'react';
2
+ import React from 'react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
5
- import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
6
- import { getNumberOfDays, sevenDaysRunningDates } from '../../constants';
7
5
  import styles from './charts.scss';
6
+ import useFacilityDashboardSurveillance from '../../hooks/useFacilityDashboardSurveillance';
7
+ import { useSurveillanceData } from '../../hooks/useSurveillanceData';
8
+ import EmptyState from '../empty-state/empty-state-log.components';
9
+ import { InlineLoading } from '@carbon/react';
8
10
  type HEIFinalOutcomesChartProps = {
9
11
  startDate?: Date;
10
12
  endDate?: Date;
@@ -12,40 +14,26 @@ type HEIFinalOutcomesChartProps = {
12
14
 
13
15
  const HEIFinalOutcomesChart: React.FC<HEIFinalOutcomesChartProps> = ({ startDate, endDate }) => {
14
16
  const { t } = useTranslation();
15
- const generateRandomData = (numRecords: number) => {
16
- return Array.from({ length: numRecords }, (_, i) => ({
17
- day: sevenDaysRunningDates(i),
18
- value: Math.floor(Math.random() * 50),
19
- }));
20
- };
17
+ const { error, isLoading, surveillanceSummary } = useFacilityDashboardSurveillance(startDate, endDate);
21
18
 
22
- const numberSequence = useMemo(() => Math.max(0, getNumberOfDays(startDate, endDate)), [startDate, endDate]);
23
-
24
- const generateRandomDataProgress = (numRecords: number) => {
25
- const data = [];
26
- for (let i = 1; i <= numRecords; i++) {
27
- data.push({
28
- group: 'Pending',
29
- key: sevenDaysRunningDates(i, endDate),
30
- value: Math.floor(Math.random() * 50),
31
- });
32
- data.push({
33
- group: 'Completed',
34
- key: sevenDaysRunningDates(i, endDate),
35
- value: Math.floor(Math.random() * 50),
36
- });
37
- }
38
- return data;
39
- };
40
-
41
- const data = useMemo(() => generateRandomDataProgress(numberSequence), [numberSequence, startDate, endDate]);
42
- const values = useMemo(() => generateRandomData(numberSequence), [numberSequence, startDate, endDate]);
19
+ const heiFinalOutcomesValue = useSurveillanceData(
20
+ surveillanceSummary,
21
+ 'getMonthlyHei24MonthsWithoutDocumentedOutcome',
22
+ );
43
23
  return (
44
- <BaseIndicatorTrendChart
45
- data={values}
46
- title={t('heiFinalOutcomes', 'Undocumented final outcome')}
47
- yAxisTitle={t('percentageHEIOutcome', '% of Undocumented final outcome')}
48
- />
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>
49
37
  );
50
38
  };
51
39
 
@@ -7,6 +7,7 @@ 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 styles from './charts.scss';
10
+ import { InlineLoading } from '@carbon/react';
10
11
  type HIVPositiveNotLinkedToARTProps = {
11
12
  startDate?: Date;
12
13
  endDate?: Date;
@@ -24,26 +25,32 @@ const HIVPositiveNotLinkedToART: React.FC<HIVPositiveNotLinkedToARTProps> = ({ s
24
25
  );
25
26
 
26
27
  return (
27
- <>
28
- <div className={styles.chart}>
29
- {hivPositivePatientValue.length > 0 ? (
30
- <BaseIndicatorTrendChart
31
- data={hivPositivePatientValue}
32
- title={t('hivPositiveNotLinkedToART', 'HIV +VE Not linked to ART')}
33
- yAxisTitle={t('numberTestedPositiveNotLinked', 'Number tested positive not linked')}
34
- />
35
- ) : (
36
- <EmptyState subTitle={t('noHivPositiveNotLinked', 'No HIV +VE Not linked to ART data to display')} />
37
- )}
38
- </div>
39
- <div className={styles.chart}>
40
- {monthlyHivPositivePatientData.length > 0 ? (
41
- <BaseArtProgressTrackingChart data={monthlyHivPositivePatientData} />
42
- ) : (
43
- <EmptyState subTitle={'No Linkage to ART data to display'} />
44
- )}
45
- </div>
46
- </>
28
+ <div>
29
+ {isLoading ? (
30
+ <InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
31
+ ) : (
32
+ <>
33
+ <div className={styles.chart}>
34
+ {hivPositivePatientValue.length > 0 ? (
35
+ <BaseIndicatorTrendChart
36
+ data={hivPositivePatientValue}
37
+ title={t('hivPositiveNotLinkedToART', 'HIV +VE Not linked to ART')}
38
+ yAxisTitle={t('numberTestedPositiveNotLinked', 'Number tested positive not linked')}
39
+ />
40
+ ) : (
41
+ <EmptyState subTitle={t('noHivPositiveNotLinked', 'No HIV +VE Not linked to ART data to display')} />
42
+ )}
43
+ </div>
44
+ <div className={styles.chart}>
45
+ {monthlyHivPositivePatientData.length > 0 ? (
46
+ <BaseArtProgressTrackingChart data={monthlyHivPositivePatientData} />
47
+ ) : (
48
+ <EmptyState subTitle={'No Linkage to ART data to display'} />
49
+ )}
50
+ </div>
51
+ </>
52
+ )}
53
+ </div>
47
54
  );
48
55
  };
49
56
 
@@ -1,50 +1,34 @@
1
- import '@carbon/charts/styles.css';
2
- import React, { useMemo } from 'react';
1
+ import React from 'react';
3
2
  import { useTranslation } from 'react-i18next';
4
3
  import BaseIndicatorTrendChart from './base-indicator-trend-chart.component';
5
- import BaseProgressTrackingChart from './base-progress-tracking-chart.component';
6
- import { getNumberOfDays, sevenDaysRunningDates } from '../../constants';
7
4
  import styles from './charts.scss';
5
+ import useFacilityDashboardSurveillance from '../../hooks/useFacilityDashboardSurveillance';
6
+ import { useSurveillanceData } from '../../hooks/useSurveillanceData';
7
+ import EmptyState from '../empty-state/empty-state-log.components';
8
+ import { InlineLoading } from '@carbon/react';
8
9
  type MissedOpportunityChartProps = {
9
10
  startDate?: Date;
10
11
  endDate?: Date;
11
12
  };
12
13
  const MissedOpportunityChart: React.FC<MissedOpportunityChartProps> = ({ startDate, endDate }) => {
13
14
  const { t } = useTranslation();
14
- const generateRandomData = (numRecords: number) => {
15
- return Array.from({ length: numRecords }, (_, i) => ({
16
- day: sevenDaysRunningDates(i, endDate),
17
- value: Math.floor(Math.random() * 50),
18
- }));
19
- };
15
+ const { error, isLoading, surveillanceSummary } = useFacilityDashboardSurveillance(startDate, endDate);
20
16
 
21
- const numberSequence = useMemo(() => Math.max(1, getNumberOfDays(startDate, endDate)), [startDate, endDate]);
22
-
23
- const generateRandomDataProgress = (numRecords: number) => {
24
- const data = [];
25
- for (let i = 1; i <= numRecords; i++) {
26
- data.push({
27
- group: 'Pending',
28
- key: sevenDaysRunningDates(i, endDate),
29
- value: Math.floor(Math.random() * 50),
30
- });
31
- data.push({
32
- group: 'Completed',
33
- key: sevenDaysRunningDates(i, endDate),
34
- value: Math.floor(Math.random() * 50),
35
- });
36
- }
37
- return data;
38
- };
39
-
40
- const data = useMemo(() => generateRandomDataProgress(numberSequence), [numberSequence, startDate, endDate]);
41
- const values = useMemo(() => generateRandomData(numberSequence), [numberSequence, startDate, endDate]);
17
+ const missedoppotunityVLValue = useSurveillanceData(surveillanceSummary, 'getMonthlyEligibleForVlSampleNotTaken');
42
18
  return (
43
- <BaseIndicatorTrendChart
44
- data={values}
45
- title={t('missedoppotunityVL', 'Missed opportunity in viral load testing')}
46
- yAxisTitle={t('percentageMissedVL', '% of missed opportunity VL')}
47
- />
19
+ <div className={styles.chart}>
20
+ {isLoading ? (
21
+ <InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
22
+ ) : missedoppotunityVLValue.length > 0 ? (
23
+ <BaseIndicatorTrendChart
24
+ data={missedoppotunityVLValue}
25
+ title={t('missedoppotunityVL', 'Missed opportunity in viral load testing')}
26
+ yAxisTitle={t('numberMissedVL', 'Number of missed opportunity VL')}
27
+ />
28
+ ) : (
29
+ <EmptyState subTitle={t('nomissedoppotunityVL', 'No missed opportunity VL data to display')} />
30
+ )}
31
+ </div>
48
32
  );
49
33
  };
50
34
 
@@ -7,6 +7,7 @@ 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 styles from './charts.scss';
10
+ import { InlineLoading } from '@carbon/react';
10
11
 
11
12
  type PBFWNotInPrepProps = {
12
13
  startDate?: Date;
@@ -23,26 +24,32 @@ const PBFWNotInPrep: React.FC<PBFWNotInPrepProps> = ({ startDate, endDate }) =>
23
24
  );
24
25
 
25
26
  return (
26
- <>
27
- <div className={styles.chart}>
28
- {highRiskPBFWNotOnPrepValue.length > 0 ? (
29
- <BaseIndicatorTrendChart
30
- data={highRiskPBFWNotOnPrepValue}
31
- title={t('prepNotlinked', 'High risk +ve PBFW not on PrEP')}
32
- yAxisTitle={t('numberHightRiskPBFW', 'Number of High risk PBFW Not on PrEP')}
33
- />
34
- ) : (
35
- <EmptyState subTitle={t('noHighRiskPBFW', 'No High risk PBFW Not on PrEP data to display')} />
36
- )}
37
- </div>
38
- <div>
39
- {monthlyhighRiskPBFWNotOnPrepPatientData.length > 0 ? (
40
- <BaseProgressTrackingChart data={monthlyhighRiskPBFWNotOnPrepPatientData} />
41
- ) : (
42
- <EmptyState subTitle={t('noHighRiskPBFW', 'No High risk PBFW Not on PrEP data to display')} />
43
- )}
44
- </div>
45
- </>
27
+ <div>
28
+ {isLoading ? (
29
+ <InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
30
+ ) : (
31
+ <>
32
+ <div className={styles.chart}>
33
+ {highRiskPBFWNotOnPrepValue.length > 0 ? (
34
+ <BaseIndicatorTrendChart
35
+ data={highRiskPBFWNotOnPrepValue}
36
+ title={t('prepNotlinked', 'High risk +ve PBFW not on PrEP')}
37
+ yAxisTitle={t('numberHightRiskPBFW', 'Number of High risk PBFW Not on PrEP')}
38
+ />
39
+ ) : (
40
+ <EmptyState subTitle={t('noHighRiskPBFW', 'No High risk PBFW Not on PrEP data to display')} />
41
+ )}
42
+ </div>
43
+ <div className={styles.chart}>
44
+ {monthlyhighRiskPBFWNotOnPrepPatientData.length > 0 ? (
45
+ <BaseProgressTrackingChart data={monthlyhighRiskPBFWNotOnPrepPatientData} />
46
+ ) : (
47
+ <EmptyState subTitle={t('noHighRiskPBFW', 'No High risk PBFW Not on PrEP data to display')} />
48
+ )}
49
+ </div>
50
+ </>
51
+ )}
52
+ </div>
46
53
  );
47
54
  };
48
55
 
@@ -10,35 +10,55 @@ import MissedOpportunityChart from './charts/missed-opportunity-vl-chart.compone
10
10
  import DNAPCRPendingCharts from './charts/dna-pcr-pending-chart.component';
11
11
  import HEIFinalOutcomesChart from './charts/hei-final-outcome.component';
12
12
  import { SurveillanceindicatorsFilter } from '../types';
13
+ import { Tabs, TabList, Tab, TabPanels, TabPanel } from '@carbon/react';
13
14
  const SurveillancelanceDashboard = () => {
14
15
  const { t } = useTranslation();
15
16
  const [currFilters, setCurrFilters] = useState<SurveillanceindicatorsFilter>({
16
17
  indicator: 'getHivPositiveNotLinked',
17
18
  });
19
+ const [activeTab, setActiveTab] = useState(0);
18
20
 
19
21
  return (
20
22
  <div>
21
23
  <FacilityDashboardHeader title={t('surveillance', 'Surveillance')} />
22
- <SurveillanceFilters filters={currFilters} onFiltersChange={setCurrFilters} />
23
- <SurveillanceSummaryCards startDate={currFilters.startdate} endDate={currFilters.endDate} />
24
- {currFilters.indicator === 'getHivPositiveNotLinked' && (
25
- <HIVPositiveNotLinkedToART startDate={currFilters.startdate} endDate={currFilters.endDate} />
26
- )}
27
- {currFilters.indicator === 'getPregnantPostpartumNotInPrep' && (
28
- <PBFWNotInPrep startDate={currFilters.startdate} endDate={currFilters.endDate} />
29
- )}
30
- {currFilters.indicator === 'getEligibleForVlSampleNotTaken' && (
31
- <DelayedEACCharts startDate={currFilters.startdate} endDate={currFilters.endDate} />
32
- )}
33
- {currFilters.indicator === 'getVirallyUnsuppressedWithoutEAC' && (
34
- <MissedOpportunityChart startDate={currFilters.startdate} endDate={currFilters.endDate} />
35
- )}
36
- {currFilters.indicator === 'getHeiSixToEightWeeksWithoutPCRResults' && (
37
- <DNAPCRPendingCharts startDate={currFilters.startdate} endDate={currFilters.endDate} />
38
- )}
39
- {currFilters.indicator === 'getHei24MonthsWithoutDocumentedOutcome' && (
40
- <HEIFinalOutcomesChart startDate={currFilters.startdate} endDate={currFilters.endDate} />
41
- )}
24
+
25
+ <Tabs onChange={({ selectedIndex }) => setActiveTab(selectedIndex)}>
26
+ <TabList>
27
+ <Tab>{t('kpi', 'KPI')}</Tab>
28
+ <Tab>{t('monitoringCharts', 'Monitoring charts')}</Tab>
29
+ </TabList>
30
+ <TabPanels>
31
+ <TabPanel>
32
+ <>
33
+ <SurveillanceFilters filters={currFilters} onFiltersChange={setCurrFilters} tabSelected={activeTab} />
34
+ <SurveillanceSummaryCards startDate={currFilters.startdate} endDate={currFilters.endDate} />
35
+ </>
36
+ </TabPanel>
37
+ <TabPanel>
38
+ <>
39
+ <SurveillanceFilters filters={currFilters} onFiltersChange={setCurrFilters} tabSelected={activeTab} />
40
+ {currFilters.indicator === 'getHivPositiveNotLinked' && (
41
+ <HIVPositiveNotLinkedToART startDate={currFilters.startdate} endDate={currFilters.endDate} />
42
+ )}
43
+ {currFilters.indicator === 'getPregnantPostpartumNotInPrep' && (
44
+ <PBFWNotInPrep startDate={currFilters.startdate} endDate={currFilters.endDate} />
45
+ )}
46
+ {currFilters.indicator === 'getEligibleForVlSampleNotTaken' && (
47
+ <DelayedEACCharts startDate={currFilters.startdate} endDate={currFilters.endDate} />
48
+ )}
49
+ {currFilters.indicator === 'getVirallyUnsuppressedWithoutEAC' && (
50
+ <MissedOpportunityChart startDate={currFilters.startdate} endDate={currFilters.endDate} />
51
+ )}
52
+ {currFilters.indicator === 'getHeiSixToEightWeeksWithoutPCRResults' && (
53
+ <DNAPCRPendingCharts startDate={currFilters.startdate} endDate={currFilters.endDate} />
54
+ )}
55
+ {currFilters.indicator === 'getHei24MonthsWithoutDocumentedOutcome' && (
56
+ <HEIFinalOutcomesChart startDate={currFilters.startdate} endDate={currFilters.endDate} />
57
+ )}
58
+ </>
59
+ </TabPanel>
60
+ </TabPanels>
61
+ </Tabs>
42
62
  </div>
43
63
  );
44
64
  };
@@ -9,8 +9,9 @@ import { formatDatetime } from '@openmrs/esm-framework';
9
9
  type Props = {
10
10
  filters: SurveillanceindicatorsFilter;
11
11
  onFiltersChange?: (filters: SurveillanceindicatorsFilter) => void;
12
+ tabSelected?: number;
12
13
  };
13
- const SurveillanceFilters: React.FC<Props> = ({ filters, onFiltersChange }) => {
14
+ const SurveillanceFilters: React.FC<Props> = ({ filters, onFiltersChange, tabSelected }) => {
14
15
  const { t } = useTranslation();
15
16
  const MaxDate: Date = today();
16
17
  const indicators = [
@@ -23,48 +24,52 @@ const SurveillanceFilters: React.FC<Props> = ({ filters, onFiltersChange }) => {
23
24
  ];
24
25
  return (
25
26
  <div className={styles.filtersContainer}>
26
- <DatePicker
27
- datePickerType="range"
28
- minDate={formatDatetime(MaxDate)}
29
- locale="en"
30
- dateFormat={DATE_PICKER_CONTROL_FORMAT}
31
- onChange={(dates: Array<Date>) => {
32
- if (onFiltersChange) {
33
- onFiltersChange({
34
- ...filters,
35
- startdate: dates[0],
36
- endDate: dates[1],
37
- });
27
+ {tabSelected === 0 && (
28
+ <DatePicker
29
+ datePickerType="range"
30
+ minDate={formatDatetime(MaxDate)}
31
+ locale="en"
32
+ dateFormat={DATE_PICKER_CONTROL_FORMAT}
33
+ onChange={(dates: Array<Date>) => {
34
+ if (onFiltersChange) {
35
+ onFiltersChange({
36
+ ...filters,
37
+ startdate: dates[0],
38
+ endDate: dates[1],
39
+ });
40
+ }
41
+ }}>
42
+ <DatePickerInput
43
+ id="date-picker-input-id-start"
44
+ placeholder={DATE_PICKER_FORMAT}
45
+ labelText={t('startDate', 'Start date')}
46
+ size="md"
47
+ />
48
+ <DatePickerInput
49
+ id="date-picker-input-id-finish"
50
+ placeholder={DATE_PICKER_FORMAT}
51
+ labelText={t('endDate', 'End date')}
52
+ size="md"
53
+ />
54
+ </DatePicker>
55
+ )}
56
+
57
+ {tabSelected === 1 && (
58
+ <Dropdown
59
+ className={styles.filterInput}
60
+ autoAlign
61
+ id="filters"
62
+ itemToString={(item: { key: string; label: string }) =>
63
+ indicators.find(({ key }) => key === item.key)?.label ?? ''
38
64
  }
39
- }}>
40
- <DatePickerInput
41
- id="date-picker-input-id-start"
42
- placeholder={DATE_PICKER_FORMAT}
43
- labelText={t('startDate', 'Start date')}
44
- size="md"
45
- />
46
- <DatePickerInput
47
- id="date-picker-input-id-finish"
48
- placeholder={DATE_PICKER_FORMAT}
49
- labelText={t('endDate', 'End date')}
50
- size="md"
65
+ items={indicators}
66
+ selectedItem={indicators.find(({ key }) => key === filters.indicator)}
67
+ label={t('indicator', 'Indicator')}
68
+ onChange={({ selectedItem: { key } }) => {
69
+ onFiltersChange({ ...filters, indicator: key });
70
+ }}
51
71
  />
52
- </DatePicker>
53
-
54
- <Dropdown
55
- className={styles.filterInput}
56
- autoAlign
57
- id="filters"
58
- itemToString={(item: { key: string; label: string }) =>
59
- indicators.find(({ key }) => key === item.key)?.label ?? ''
60
- }
61
- items={indicators}
62
- selectedItem={indicators.find(({ key }) => key === filters.indicator)}
63
- label={t('indicator', 'Indicator')}
64
- onChange={({ selectedItem: { key } }) => {
65
- onFiltersChange({ ...filters, indicator: key });
66
- }}
67
- />
72
+ )}
68
73
  </div>
69
74
  );
70
75
  };
@@ -17,6 +17,10 @@ export type SurveillanceSummary = {
17
17
  getMonthlyHivPositiveNotLinkedPatients: HivPositiveNotLinkedData;
18
18
  getMonthlyHighRiskPBFWNotOnPrep: HivPositiveNotLinkedData;
19
19
  getMonthlyHighRiskPBFWNotOnPrepPatients: HivPositiveNotLinkedData;
20
+ getMonthlyHeiDNAPCRPending: HivPositiveNotLinkedData;
21
+ getMonthlyEligibleForVlSampleNotTaken: HivPositiveNotLinkedData;
22
+ getMonthlyHei24MonthsWithoutDocumentedOutcome: HivPositiveNotLinkedData;
23
+ getMonthlyVirallyUnsuppressedWithoutEAC: HivPositiveNotLinkedData;
20
24
  };
21
25
 
22
26
  export type IndicationMode = 'decreasing' | 'increasing';