import { useState, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Line } from 'react-chartjs-2'; import { Card } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { buildHourlyTokenBreakdown, buildDailyTokenBreakdown, type TokenCategory } from '@/utils/usage'; import { buildChartOptions, getHourChartMinWidth } from '@/utils/usage/chartConfig'; import type { UsagePayload } from './hooks/useUsageData'; import styles from '@/pages/UsagePage.module.scss'; const TOKEN_COLORS: Record = { input: { border: '#8b8680', bg: 'rgba(139, 134, 128, 0.25)' }, output: { border: '#22c55e', bg: 'rgba(34, 197, 94, 0.25)' }, cached: { border: '#f59e0b', bg: 'rgba(245, 158, 11, 0.25)' }, reasoning: { border: '#8b5cf6', bg: 'rgba(139, 92, 246, 0.25)' } }; const CATEGORIES: TokenCategory[] = ['input', 'output', 'cached', 'reasoning']; export interface TokenBreakdownChartProps { usage: UsagePayload | null; loading: boolean; isDark: boolean; isMobile: boolean; hourWindowHours?: number; } export function TokenBreakdownChart({ usage, loading, isDark, isMobile, hourWindowHours }: TokenBreakdownChartProps) { const { t } = useTranslation(); const [period, setPeriod] = useState<'hour' | 'day'>('hour'); const { chartData, chartOptions } = useMemo(() => { const series = period === 'hour' ? buildHourlyTokenBreakdown(usage, hourWindowHours) : buildDailyTokenBreakdown(usage); const categoryLabels: Record = { input: t('usage_stats.input_tokens'), output: t('usage_stats.output_tokens'), cached: t('usage_stats.cached_tokens'), reasoning: t('usage_stats.reasoning_tokens') }; const data = { labels: series.labels, datasets: CATEGORIES.map((cat) => ({ label: categoryLabels[cat], data: series.dataByCategory[cat], borderColor: TOKEN_COLORS[cat].border, backgroundColor: TOKEN_COLORS[cat].bg, pointBackgroundColor: TOKEN_COLORS[cat].border, pointBorderColor: TOKEN_COLORS[cat].border, fill: true, tension: 0.35 })) }; const baseOptions = buildChartOptions({ period, labels: series.labels, isDark, isMobile }); const options = { ...baseOptions, scales: { ...baseOptions.scales, y: { ...baseOptions.scales?.y, stacked: true }, x: { ...baseOptions.scales?.x, stacked: true } } }; return { chartData: data, chartOptions: options }; }, [usage, period, isDark, isMobile, hourWindowHours, t]); return ( } > {loading ? (
{t('common.loading')}
) : chartData.labels.length > 0 ? (
{chartData.datasets.map((dataset, index) => (
{dataset.label}
))}
) : (
{t('usage_stats.no_data')}
)}
); }