/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { VChart } from '@visactor/react-vchart' import { AreaChart, BarChart3, WalletCards } from 'lucide-react' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { IconBadge } from '@/components/ui/icon-badge' import { useThemeCustomization } from '@/context/theme-customization-provider' import { useTheme } from '@/context/theme-provider' import { CONSUMPTION_DISTRIBUTION_CHART_OPTIONS, DEFAULT_TIME_GRANULARITY, } from '@/features/dashboard/constants' import { processChartData } from '@/features/dashboard/lib' import type { ConsumptionDistributionChartType, QuotaDataItem, } from '@/features/dashboard/types' import { useThemeRadiusPx } from '@/lib/theme-radius' import type { TimeGranularity } from '@/lib/time' import { VCHART_OPTION } from '@/lib/vchart' let themeManagerPromise: Promise< (typeof import('@visactor/vchart'))['ThemeManager'] > | null = null interface ConsumptionDistributionChartProps { data: QuotaDataItem[] loading?: boolean timeGranularity?: TimeGranularity defaultChartType?: ConsumptionDistributionChartType } const CHART_TYPE_ICONS: Record< ConsumptionDistributionChartType, typeof BarChart3 > = { bar: BarChart3, area: AreaChart, } export function ConsumptionDistributionChart( props: ConsumptionDistributionChartProps ) { const { t } = useTranslation() const { resolvedTheme } = useTheme() const { customization } = useThemeCustomization() const chartRadius = useThemeRadiusPx( '--radius-md', `${customization.preset}:${customization.radius}` ) const [chartType, setChartType] = useState( props.defaultChartType ?? 'bar' ) const [themeReady, setThemeReady] = useState(false) const themeManagerRef = useRef< (typeof import('@visactor/vchart'))['ThemeManager'] | null >(null) const timeGranularity = props.timeGranularity ?? DEFAULT_TIME_GRANULARITY useEffect(() => { if (props.defaultChartType) setChartType(props.defaultChartType) }, [props.defaultChartType]) useEffect(() => { const updateTheme = async () => { setThemeReady(false) if (!themeManagerPromise) { themeManagerPromise = import('@visactor/vchart').then( (m) => m.ThemeManager ) } const ThemeManager = await themeManagerPromise themeManagerRef.current = ThemeManager ThemeManager.setCurrentTheme(resolvedTheme === 'dark' ? 'dark' : 'light') setThemeReady(true) } updateTheme() }, [resolvedTheme]) const chartData = useMemo( () => processChartData( props.loading ? [] : props.data, timeGranularity, t, chartRadius ), [props.data, props.loading, timeGranularity, t, chartRadius] ) const spec = chartType === 'bar' ? chartData.spec_line : chartData.spec_area const specType = typeof spec?.type === 'string' ? spec.type : chartType const chartKey = [ chartType, specType, props.loading ? 'loading' : 'ready', props.data.length, resolvedTheme, customization.preset, ].join('-') return (
{t('Quota Distribution')}
{t('Total:')} {chartData.totalQuotaDisplay}
{CONSUMPTION_DISTRIBUTION_CHART_OPTIONS.map((item) => { const Icon = CHART_TYPE_ICONS[item.value] return ( ) })}
{themeReady && spec && ( )}
) }