import { useState, useEffect } from 'react'; import { UsageProgressBar } from './UsageProgressBar'; interface ClaudeAccount { id: string; name: string; status: string; accountType: string; lastUsedAt: string | null; usage?: { daily?: { tokens: number; requests: number; cost: number; }; }; claudeUsage?: { fiveHour?: { utilization: number; resetsAt: string; remainingSeconds: number; }; sevenDay?: { utilization: number; resetsAt: string; remainingSeconds: number; }; sevenDayOpus?: { utilization: number; resetsAt: string; remainingSeconds: number; }; }; } interface OpenAIAccount { id: string; name: string; status: string; accountType: string; lastUsedAt: string | null; usage?: { daily?: { tokens: number; requests: number; cost: number; }; }; codexUsage?: { primary?: { usedPercent: number; resetAfterSeconds: number; resetAt: string; }; secondary?: { usedPercent: number; resetAfterSeconds: number; resetAt: string; }; }; } type UnifiedAccount = (ClaudeAccount | OpenAIAccount) & { platform: 'claude' | 'openai'; }; interface AIAccountsProps { apiKey: string; } export function AIAccounts({ apiKey }: AIAccountsProps) { const [claudeAccounts, setClaudeAccounts] = useState([]); const [openaiAccounts, setOpenaiAccounts] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isRefreshing, setIsRefreshing] = useState(false); const [error, setError] = useState(''); useEffect(() => { fetchAccounts(); const interval = setInterval(fetchAccounts, 30000); return () => clearInterval(interval); }, [apiKey]); const fetchAccounts = async (isRefresh = false) => { if (isRefresh) { setIsRefreshing(true); } try { const response = await fetch('/api/ai-accounts', { headers: { 'X-API-Key': apiKey, }, }); if (!response.ok) { throw new Error('Failed to fetch AI accounts'); } const data = await response.json(); setClaudeAccounts(data.claude || []); setOpenaiAccounts(data.openai || []); setError(''); } catch (err) { console.error('Error fetching AI accounts:', err); setError(err instanceof Error ? err.message : 'Failed to load AI accounts'); } finally { setIsLoading(false); if (isRefresh) { setIsRefreshing(false); } } }; const formatLastUsed = (lastUsedAt: string | null) => { if (!lastUsedAt) return 'Never'; const date = new Date(lastUsedAt); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / 60000); if (diffMins < 1) return 'Just now'; if (diffMins < 60) return `${diffMins}m ago`; const diffHours = Math.floor(diffMins / 60); if (diffHours < 24) return `${diffHours}h ago`; const diffDays = Math.floor(diffHours / 24); return `${diffDays}d ago`; }; const formatTime = (seconds: number) => { if (seconds <= 0) return '0m'; const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (days > 0) { if (hours > 0) return `${days}d ${hours}h`; return `${days}d`; } if (hours > 0) return `${hours}h ${minutes}m`; return `${minutes}m`; }; const getStatusColor = (status: string) => { switch (status) { case 'active': return 'bg-chart-1 text-white'; case 'blocked': return 'bg-chart-2 text-white'; case 'unauthorized': return 'bg-chart-3 text-white'; case 'temp_error': return 'bg-chart-4 text-white'; default: return 'bg-chart-5 text-white'; } }; const getAccountName = (account: UnifiedAccount, totalCount: number) => { if (totalCount === 1) { return account.platform === 'claude' ? 'Claude' : 'OpenAI'; } return `${account.platform === 'claude' ? 'Claude' : 'OpenAI'} (${account.name})`; }; // Merge accounts const allAccounts: UnifiedAccount[] = [ ...claudeAccounts.map(acc => ({ ...acc, platform: 'claude' as const })), ...openaiAccounts.map(acc => ({ ...acc, platform: 'openai' as const })), ]; if (isLoading) { return (

AI Accounts Status

Loading accounts...
); } if (error) { return (

AI Accounts Status

{error}

); } return (

AI Accounts Status

{allAccounts.length > 0 ? (
{allAccounts.map((account) => { const platformCount = account.platform === 'claude' ? claudeAccounts.length : openaiAccounts.length; const isClaudeAccount = account.platform === 'claude'; const claudeAcc = isClaudeAccount ? (account as ClaudeAccount) : null; const openaiAcc = !isClaudeAccount ? (account as OpenAIAccount) : null; return ( ); })}
Account Status Daily Usage Usage Windows Last Used
{getAccountName(account, platformCount)}
{account.status} {account.usage?.daily && (isClaudeAccount || account.usage.daily.requests > 0) ? (
{account.usage.daily.requests} reqs
${account.usage.daily.cost.toFixed(2)} cost
) : ( {isClaudeAccount ? 'No data' : 'No usage today'} )}
{claudeAcc?.claudeUsage ? (
{claudeAcc.claudeUsage.fiveHour && ( )} {claudeAcc.claudeUsage.sevenDay && ( )} {claudeAcc.claudeUsage.sevenDayOpus && ( )}
) : openaiAcc?.codexUsage ? (
{openaiAcc.codexUsage.primary && ( )} {openaiAcc.codexUsage.secondary && ( )}
) : ( No data )}
{formatLastUsed(account.lastUsedAt)}
) : (
No shared AI accounts found
)}
); }