/** * Individual Gemini CLI quota card component. */ import { useTranslation } from 'react-i18next'; import type { GeminiCliQuotaState, AuthFileItem, ResolvedTheme, ThemeColors } from '@/types'; import { TYPE_COLORS, formatQuotaResetTime } from '@/utils/quota'; import styles from '@/pages/QuotaPage.module.scss'; interface GeminiCliCardProps { item: AuthFileItem; quota?: GeminiCliQuotaState; resolvedTheme: ResolvedTheme; getQuotaErrorMessage: (status: number | undefined, fallback: string) => string; } export function GeminiCliCard({ item, quota, resolvedTheme, getQuotaErrorMessage }: GeminiCliCardProps) { const { t } = useTranslation(); const displayType = item.type || item.provider || 'gemini-cli'; const typeColorSet = TYPE_COLORS[displayType] || TYPE_COLORS.unknown; const typeColor: ThemeColors = resolvedTheme === 'dark' && typeColorSet.dark ? typeColorSet.dark : typeColorSet.light; const quotaStatus = quota?.status ?? 'idle'; const buckets = quota?.buckets ?? []; const quotaErrorMessage = getQuotaErrorMessage( quota?.errorStatus, quota?.error || t('common.unknown_error') ); const getTypeLabel = (type: string): string => { const key = `auth_files.filter_${type}`; const translated = t(key); if (translated !== key) return translated; if (type.toLowerCase() === 'iflow') return 'iFlow'; return type.charAt(0).toUpperCase() + type.slice(1); }; return (
{getTypeLabel(displayType)} {item.name}
{quotaStatus === 'loading' ? (
{t('gemini_cli_quota.loading')}
) : quotaStatus === 'idle' ? (
{t('gemini_cli_quota.idle')}
) : quotaStatus === 'error' ? (
{t('gemini_cli_quota.load_failed', { message: quotaErrorMessage })}
) : buckets.length === 0 ? (
{t('gemini_cli_quota.empty_buckets')}
) : ( buckets.map((bucket) => { const fraction = bucket.remainingFraction; const clamped = fraction === null ? null : Math.max(0, Math.min(1, fraction)); const percent = clamped === null ? null : Math.round(clamped * 100); const percentLabel = percent === null ? '--' : `${percent}%`; const resetLabel = formatQuotaResetTime(bucket.resetTime); const remainingAmountLabel = bucket.remainingAmount === null || bucket.remainingAmount === undefined ? null : t('gemini_cli_quota.remaining_amount', { count: bucket.remainingAmount }); const titleBase = bucket.modelIds && bucket.modelIds.length > 0 ? bucket.modelIds.join(', ') : bucket.label; const quotaBarClass = percent === null ? styles.quotaBarFillMedium : percent >= 60 ? styles.quotaBarFillHigh : percent >= 20 ? styles.quotaBarFillMedium : styles.quotaBarFillLow; return (
{bucket.label}
{percentLabel} {remainingAmountLabel && ( {remainingAmountLabel} )} {resetLabel}
); }) )}
); }