pagamio-frontend-commons-lib
Version:
Pagamio library for Frontend reusable components like the form engine and table container
202 lines (201 loc) • 12.5 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
// BaseChart.tsx
import { useCallback, useMemo, useState } from 'react';
import Card from '../components/CardWrapper';
import ChartDetailsModal from '../components/ChartDetailsModal';
import ChartWrapper from '../components/ChartWrapper';
import { useChartData } from '../hooks/useChartData';
import { DashboardPaths, formatDonutChartData } from '../utils';
import { getChartBarOptions, getLargeDatasetChartOptions } from '../utils/chartOptions';
import { createTooltipFormatter, processTooltipFields } from '../utils/tooltipUtils';
import { sortMetricData } from '../visuals/HorizontalBarChart';
const BaseChart = ({ title, url = DashboardPaths.QUERY, query, chartDetails, children, detailsModalTitle, statisticsUrl = DashboardPaths.METRICS, itemStatisticsQuery, valueMetricsQuery, averageMetricsQuery, distributionMetricsQuery, yAxisDataNameKey, xAxisNameKey, xAxisLabel, yAxisLabel, nameKey, valueKey, dataGridSearchKey, dataGridColumns, dataSearchInputPlaceHolder, chartToolTip, detailsTableTitle, getChartOptions, tooltipValueFormat = 'value', tooltipTitle = 'Value', tooltipUnit = '', tooltipAdditionalFields = [], topFivePerformingChartTitle, bottomFivePerformingChartTitle, distributionChartTooltip, showDetailsModal = true, currencyDisplaySymbol, ...props }) => {
const [isModalOpen, setIsModalOpen] = useState(false);
const { data: metricData = [], error, isEmpty, loading, refresh } = useChartData(url, query);
// Process tooltip fields
const processedTooltipFields = useMemo(() => processTooltipFields(tooltipAdditionalFields), [tooltipAdditionalFields]);
const processedDistributionTooltipFields = useMemo(() => processTooltipFields(distributionChartTooltip.tooltipAdditionalFields), [distributionChartTooltip.tooltipAdditionalFields]);
// Create tooltip formatter function
const tooltipFormatterFn = useMemo(() => {
// Use the currency from metricData, or fallback to a default
const currency = metricData?.[0]?.currency || 'ZAR';
return createTooltipFormatter(tooltipValueFormat, tooltipTitle, tooltipUnit, processedTooltipFields, metricData, currency, currencyDisplaySymbol);
}, [tooltipValueFormat, tooltipTitle, tooltipUnit, processedTooltipFields, metricData, currencyDisplaySymbol]);
// Get full data for detailed view
const { data: fullMetricData = [], error: fullDataError, isEmpty: isfullMetricDataEmpty, loading: isLoadingFullMetricData, refresh: refreshFullMetricData, } = useChartData(url, {
...query,
limit: undefined,
});
// Get item Statistics Query data for detailed view
const { data: itemStatData, error: itemStatDataError, isEmpty: isitemStatMetricDataEmpty, loading: isLoadingItemStatlMetricData, refresh: refreshItemStatMetricData, } = useChartData(statisticsUrl, {
...itemStatisticsQuery.query,
});
// Get value Metrics Query data for detailed view
const { data: valueStatData, error: valueStatDataError, isEmpty: isValueStatMetricDataEmpty, loading: isLoadingValueStatlMetricData, refresh: refreshValueStatMetricData, } = useChartData(statisticsUrl, {
...valueMetricsQuery.query,
});
// Get average Metrics Query data for detailed view
const { data: averageStatData, error: averageStatDataError, isEmpty: isAverageStatMetricDataEmpty, loading: isLoadingAverageStatlMetricData, refresh: refreshAverageStatMetricData, } = useChartData(statisticsUrl, {
...averageMetricsQuery.query,
});
// Get distribution Metrics Query data for detailed view
const { data: distributionStatData, error: distributionStatDataError, isEmpty: isDistributionStatMetricDataEmpty, loading: isLoadingDistributionStatlMetricData, refresh: refreshDistributionStatMetricData, } = useChartData(url, {
...distributionMetricsQuery.query,
});
const distributionMetricData = useMemo(() => {
const formattedData = formatDonutChartData(distributionStatData ?? [], distributionMetricsQuery.xAxisDataValueKey, distributionMetricsQuery.seriesDataValueKey);
const { tooltipValueFormat, tooltipTitle, tooltipUnit, treeMapSegmentLabel } = distributionChartTooltip;
const labelFormatter = (params) => {
const formattedValue = params.value.toLocaleString();
return `${params.name}\n${treeMapSegmentLabel}: ${formattedValue}`;
};
const tooltipFormatter = createTooltipFormatter(tooltipValueFormat, tooltipTitle, tooltipUnit, processedDistributionTooltipFields, distributionStatData ?? [], distributionStatData?.[0]?.currency, currencyDisplaySymbol);
const distributionMetricOptions = getLargeDatasetChartOptions({
data: formattedData,
labelFormatter,
tooltipFormatter,
});
return distributionMetricOptions;
}, [
distributionStatData,
distributionMetricsQuery.seriesDataValueKey,
distributionMetricsQuery.xAxisDataValueKey,
currencyDisplaySymbol,
]);
const fullChartOptions = useMemo(() => {
const chartOptions = getChartOptions(fullMetricData);
return chartOptions;
}, [fullMetricData]);
const createChartOptions = useCallback((data, title, colorScheme, metricDetailData, tooltipConfig) => {
const currency = data?.[0]?.currency;
const formatterFn = tooltipConfig
? createTooltipFormatter(tooltipValueFormat, tooltipConfig.tooltipTitle ?? tooltipTitle, tooltipConfig.tooltipUnit ?? tooltipUnit, tooltipConfig.tooltipFields ?? processedTooltipFields, tooltipConfig.data ?? data, currency, currencyDisplaySymbol)
: tooltipFormatterFn;
return getChartBarOptions({
title,
colorScheme,
yAxisDataNameKey: metricDetailData.yAxisDataNameKey,
xAxisNameKey: metricDetailData.xAxisNameKey,
xAxisLabel: metricDetailData.xAxisLabel,
yAxisLabel: metricDetailData.yAxisLabel,
chartToolTip: {
...metricDetailData.chartToolTip,
formatter: formatterFn,
},
data,
});
}, [tooltipFormatterFn, tooltipTitle, tooltipUnit, processedTooltipFields]);
const createChartOptionsWithData = useCallback((data, tooltipConfig) => createChartOptions(data, title, ['#60A5FA', '#93C5FD'], {
yAxisDataNameKey,
xAxisNameKey,
xAxisLabel,
yAxisLabel,
chartToolTip,
}, tooltipConfig), [title, yAxisDataNameKey, xAxisNameKey, xAxisLabel, yAxisLabel, chartToolTip, createChartOptions]);
const sortedFullMetricData = useMemo(() => sortMetricData(fullMetricData, valueKey, 'desc'), [fullMetricData, valueKey]);
const { topFiveItems, bottomFiveItems } = useMemo(() => {
if (!sortedFullMetricData || sortedFullMetricData.length === 0) {
return {
topFiveItems: [],
bottomFiveItems: [],
};
}
const topFiveMetric = sortedFullMetricData.slice(0, 5);
const bottomFiveMetric = sortedFullMetricData.slice(-5).reverse();
return {
topFiveItems: createChartOptionsWithData(topFiveMetric, {
tooltipTitle: topFivePerformingChartTitle,
tooltipUnit,
tooltipFields: processedTooltipFields,
data: topFiveMetric,
}),
bottomFiveItems: createChartOptionsWithData(bottomFiveMetric, {
tooltipTitle: bottomFivePerformingChartTitle,
tooltipUnit,
tooltipFields: processedTooltipFields,
data: bottomFiveMetric,
}),
};
}, [
sortedFullMetricData,
createChartOptionsWithData,
tooltipUnit,
processedTooltipFields,
topFivePerformingChartTitle,
bottomFivePerformingChartTitle,
]);
const itemMetricsData = {
value: itemStatData?.[itemStatisticsQuery.valueKey] ?? 0,
previousValue: itemStatisticsQuery.previousValueKey
? (itemStatData?.[itemStatisticsQuery.previousValueKey] ?? 0)
: undefined,
change: itemStatData?.[itemStatisticsQuery.changeKey] ?? 0,
currency: itemStatData?.additionalData?.currency,
};
const valueMetricsData = {
value: valueStatData?.[valueMetricsQuery.valueKey] ?? 0,
previousValue: valueMetricsQuery.previousValueKey
? (valueStatData?.[valueMetricsQuery.previousValueKey] ?? 0)
: undefined,
change: valueStatData?.[valueMetricsQuery.changeKey] ?? 0,
currency: valueStatData?.additionalData?.currency,
};
const averageMetricsData = {
value: averageStatData?.[averageMetricsQuery.valueKey] ?? 0,
previousValue: averageMetricsQuery.previousValueKey
? (averageStatData?.[averageMetricsQuery.previousValueKey] ?? 0)
: undefined,
change: averageStatData?.[averageMetricsQuery.changeKey] ?? 0,
currency: averageStatData?.additionalData?.currency,
};
return (_jsxs(_Fragment, { children: [_jsx(Card, { title: title, ...props, onOpenDetails: metricData.length > 0 && showDetailsModal ? () => setIsModalOpen(true) : undefined, children: _jsx(ChartWrapper, { loading: loading, error: error, isEmpty: isEmpty, onRetry: refresh, children: children({
loading,
error,
isEmpty,
refresh,
metricData,
tooltipFormatterFn,
processedTooltipFields,
}) }) }), showDetailsModal && (_jsx(ChartDetailsModal, { title: detailsModalTitle, isOpen: isModalOpen, onClose: () => setIsModalOpen(false), data: fullMetricData, columns: dataGridColumns, error: fullDataError, isEmpty: isfullMetricDataEmpty, loading: isLoadingFullMetricData, detailsTableTitle: detailsTableTitle, refresh: refreshFullMetricData, renderDetailsChart: fullMetricData.length <= 40, chartData: fullChartOptions, topFivePerformingChartTitle: topFivePerformingChartTitle, bottomFivePerformingChartTitle: bottomFivePerformingChartTitle, top5PerformingItems: topFiveItems, bottom5NonPerformingItems: bottomFiveItems, valueKey: valueKey, dataGridQuery: query, searchKey: dataGridSearchKey, searchInputPlaceHolder: dataSearchInputPlaceHolder, itemMetricsData: {
...itemMetricsData,
title: itemStatisticsQuery.title,
format: itemStatisticsQuery.format,
isEmpty: isitemStatMetricDataEmpty,
loading: isLoadingItemStatlMetricData,
error: itemStatDataError,
refresh: () => {
refreshItemStatMetricData().catch(() => { });
},
}, valueMetricsData: {
...valueMetricsData,
title: valueMetricsQuery.title,
format: valueMetricsQuery.format,
isEmpty: isValueStatMetricDataEmpty,
loading: isLoadingValueStatlMetricData,
error: valueStatDataError,
refresh: () => {
refreshValueStatMetricData().catch(() => { });
},
}, averageMetricsData: {
...averageMetricsData,
title: averageMetricsQuery.title,
format: averageMetricsQuery.format,
isEmpty: isAverageStatMetricDataEmpty,
loading: isLoadingAverageStatlMetricData,
error: averageStatDataError,
refresh: () => {
refreshAverageStatMetricData().catch(() => { });
},
}, distributionMetricsData: {
data: distributionMetricData ?? [],
title: distributionMetricsQuery.title,
isEmpty: isDistributionStatMetricDataEmpty,
loading: isLoadingDistributionStatlMetricData,
error: distributionStatDataError,
refresh: () => {
refreshDistributionStatMetricData().catch(() => { });
},
chartToolTip: distributionMetricsQuery.chartToolTip,
} }))] }));
};
export default BaseChart;