/**
* Usage Trend Chart Component
*
* Displays usage trends over time with tokens and cost.
* Supports daily, hourly, and monthly granularity with interactive tooltips.
* Respects privacy mode to blur sensitive data.
*/
import { useMemo } from 'react';
import {
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Area,
AreaChart,
} from 'recharts';
import { format } from 'date-fns';
import { useTranslation } from 'react-i18next';
import { Skeleton } from '@/components/ui/skeleton';
import { cn } from '@/lib/utils';
import type { DailyUsage, HourlyUsage } from '@/hooks/use-usage';
import { usePrivacy, PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context';
// TODO i18n: import { useTranslation } from 'react-i18next'; when keys are ready
type ChartData = DailyUsage | HourlyUsage;
interface UsageTrendChartProps {
data: ChartData[];
isLoading?: boolean;
granularity?: 'daily' | 'monthly' | 'hourly';
className?: string;
}
export function UsageTrendChart({
data,
isLoading,
granularity = 'daily',
className,
}: UsageTrendChartProps) {
const { privacyMode } = usePrivacy();
const { t } = useTranslation();
const chartData = useMemo(() => {
if (!data || data.length === 0) return [];
// For hourly data, already sorted ascending from API
const sortedData = data;
return sortedData.map((item) => {
// Handle hourly vs daily data format
const timeKey = 'hour' in item ? item.hour : (item as DailyUsage).date;
return {
...item,
dateFormatted: formatTime(timeKey, granularity),
costRounded: Number(item.cost.toFixed(4)),
};
});
}, [data, granularity]);
if (isLoading) {
return
{granularity === 'hourly' ? t('analytics.noDailyUsage') : t('analytics.noUsageData')}
{label}
{payload.map((entry, index) => ({entry.name}:{' '} {entry.name === 'Tokens' ? formatNumber(Number(entry.value) || 0) : `$${entry.value}`}
))}