UNPKG

@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
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;