import { useState, useEffect } from 'react'; import { RankingTable } from './RankingTable'; import { UserDetailCard } from './UserDetailCard'; interface Period { index: number; startSnapshotId: number | null; startAt: string | null; endAt: string | null; isCurrent: boolean; } interface PeriodSummary { period: { index: number; startAt: string | null; endAt: string | null; isCurrent: boolean; }; totals: { totalCost: number; userCount: number; }; ranking: Array<{ id: string; name: string; cost: number; share: number; isMe: boolean; rawStart: any; rawEnd: any; periodTokens: number; periodRequests: number; }>; } interface HistoricalPeriodsProps { periods: Period[]; apiKey: string; userId: string; } export function HistoricalPeriods({ periods, apiKey, userId }: HistoricalPeriodsProps) { const [selectedPeriod, setSelectedPeriod] = useState(null); const [summary, setSummary] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); useEffect(() => { if (periods.length > 0 && !selectedPeriod) { setSelectedPeriod(periods[0] || null); // Select the most recent historical period } }, [periods]); useEffect(() => { if (selectedPeriod) { fetchSummary(selectedPeriod.index); } }, [selectedPeriod]); const fetchSummary = async (periodIndex: number) => { setIsLoading(true); setError(''); try { const response = await fetch(`/api/periods/${periodIndex}/summary`, { headers: { 'X-API-Key': apiKey, }, }); if (!response.ok) { throw new Error(`Failed to fetch period summary: ${response.status}`); } const data = await response.json(); setSummary(data); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load period data'); setSummary(null); } finally { setIsLoading(false); } }; const formatDate = (dateString: string | null) => { if (!dateString) return 'Unknown'; const date = new Date(dateString); return date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false, }); }; const formatDateRange = (startAt: string | null, endAt: string | null) => { return `${formatDate(startAt)} → ${formatDate(endAt)}`; }; const formatCurrency = (amount: number) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(amount); }; if (periods.length === 0) { return (

No Historical Periods

Historical periods will appear here after you create billing snapshots using the bun begin-period command.

); } const myUser = summary?.ranking.find(u => u.isMe); return (
{/* Period Selector */}
{selectedPeriod && ( <> {/* Period Summary */} {isLoading ? (
) : error ? (

Failed to Load Period Data

{error}

) : summary && ( <>

Period #{selectedPeriod.index}: {formatDateRange(summary.period.startAt, summary.period.endAt)}

{formatCurrency(summary.totals.totalCost)}
Total Cost
{summary.totals.userCount}
Active Users
{myUser ? formatCurrency(myUser.cost) : '$0.00'}
Your Cost ({myUser ? (myUser.share * 100).toFixed(2) : '0.00'}%)
{/* Ranking Table */} {/* User Detail Card */} )} )}
); }