import { useState, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Card } from '@/components/ui/Card'; import { formatTokensInMillions, formatUsd, type ApiStats } from '@/utils/usage'; import styles from '@/pages/UsagePage.module.scss'; export interface ApiDetailsCardProps { apiStats: ApiStats[]; loading: boolean; hasPrices: boolean; } type ApiSortKey = 'endpoint' | 'requests' | 'tokens' | 'cost'; type SortDir = 'asc' | 'desc'; export function ApiDetailsCard({ apiStats, loading, hasPrices }: ApiDetailsCardProps) { const { t } = useTranslation(); const [expandedApis, setExpandedApis] = useState>(new Set()); const [sortKey, setSortKey] = useState('requests'); const [sortDir, setSortDir] = useState('desc'); const toggleExpand = (endpoint: string) => { setExpandedApis((prev) => { const newSet = new Set(prev); if (newSet.has(endpoint)) { newSet.delete(endpoint); } else { newSet.add(endpoint); } return newSet; }); }; const handleSort = (key: ApiSortKey) => { if (sortKey === key) { setSortDir((d) => (d === 'asc' ? 'desc' : 'asc')); } else { setSortKey(key); setSortDir(key === 'endpoint' ? 'asc' : 'desc'); } }; const sorted = useMemo(() => { const list = [...apiStats]; const dir = sortDir === 'asc' ? 1 : -1; list.sort((a, b) => { switch (sortKey) { case 'endpoint': return dir * a.endpoint.localeCompare(b.endpoint); case 'requests': return dir * (a.totalRequests - b.totalRequests); case 'tokens': return dir * (a.totalTokens - b.totalTokens); case 'cost': return dir * (a.totalCost - b.totalCost); default: return 0; } }); return list; }, [apiStats, sortKey, sortDir]); const arrow = (key: ApiSortKey) => sortKey === key ? (sortDir === 'asc' ? ' ▲' : ' ▼') : ''; return ( {loading ? (
{t('common.loading')}
) : sorted.length > 0 ? ( <>
{([ ['endpoint', 'usage_stats.api_endpoint'], ['requests', 'usage_stats.requests_count'], ['tokens', 'usage_stats.tokens_count'], ...(hasPrices ? [['cost', 'usage_stats.total_cost']] : []), ] as [ApiSortKey, string][]).map(([key, labelKey]) => ( ))}
{sorted.map((api) => (
toggleExpand(api.endpoint)}>
{api.endpoint}
{t('usage_stats.requests_count')}: {api.totalRequests.toLocaleString()} ({api.successCount.toLocaleString()}{' '} {api.failureCount.toLocaleString()}) {t('usage_stats.tokens_count')}: {formatTokensInMillions(api.totalTokens)} {hasPrices && api.totalCost > 0 && ( {t('usage_stats.total_cost')}: {formatUsd(api.totalCost)} )}
{expandedApis.has(api.endpoint) ? '▼' : '▶'}
{expandedApis.has(api.endpoint) && (
{Object.entries(api.models).map(([model, stats]) => (
{model} {stats.requests.toLocaleString()} ({stats.successCount.toLocaleString()}{' '} {stats.failureCount.toLocaleString()}) {formatTokensInMillions(stats.tokens)}
))}
)}
))}
) : (
{t('usage_stats.no_data')}
)}
); }