'use client' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { PaginationControls } from '@/components/pagination-controls' import { usePagination } from '@/hooks/use-pagination' import type { DailyUsage, SessionSummary } from '@/lib/parse-logs' import { formatCost, formatTokens, formatNumber } from '@/lib/format' interface DailyTableProps { daily: DailyUsage[] sessions: SessionSummary[] } function shortModel(name: string): string { // Strip the leading "claude-" so the table reads "opus-4-7" / "haiku-4-5" return name.replace(/^claude-/, '') } export function DailyTable({ daily, sessions }: DailyTableProps) { // Fall back to session-derived models for days without modelBreakdowns // (happens when the user filters by project on the client — see // components/data-provider.tsx). const modelsByDate = new Map>() for (const s of sessions) { const date = s.startTime.slice(0, 10) if (!modelsByDate.has(date)) modelsByDate.set(date, new Set()) modelsByDate.get(date)!.add(s.model) } // Totals const totals = daily.reduce( (acc, d) => ({ sessions: acc.sessions + d.sessions, messages: acc.messages + d.messages, inputTokens: acc.inputTokens + d.inputTokens, outputTokens: acc.outputTokens + d.outputTokens, cacheCreationTokens: acc.cacheCreationTokens + d.cacheCreationTokens, cacheReadTokens: acc.cacheReadTokens + d.cacheReadTokens, totalTokens: acc.totalTokens + d.totalTokens, costUSD: acc.costUSD + d.costUSD, }), { sessions: 0, messages: 0, inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0, totalTokens: 0, costUSD: 0, } ) // Sort daily by date descending (most recent first) const sorted = [...daily].sort((a, b) => b.date.localeCompare(a.date)) const pagination = usePagination(sorted, 20) return ( Daily Breakdown {daily.length} days of activity Date Models Sessions Input Output Cache Create Cache Read Total Tokens Cost {pagination.pageItems.map((d) => { const modelList = d.modelBreakdowns.length > 0 ? d.modelBreakdowns.map((b) => b.model) : Array.from(modelsByDate.get(d.date) ?? []).sort() return ( {d.date} {modelList.map((m) => (
- {shortModel(m)}
))}
{d.sessions} {formatNumber(d.inputTokens)} {formatNumber(d.outputTokens)} {formatNumber(d.cacheCreationTokens)} {formatNumber(d.cacheReadTokens)} {formatNumber(d.totalTokens)} {formatCost(d.costUSD)}
) })}
Total {totals.sessions} {formatTokens(totals.inputTokens)} {formatTokens(totals.outputTokens)} {formatTokens(totals.cacheCreationTokens)} {formatTokens(totals.cacheReadTokens)} {formatTokens(totals.totalTokens)} {formatCost(totals.costUSD)}
) }