From 9516e71f17c112eb71d7e0283e5c9d8c654fa2f9 Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Sun, 25 Jan 2026 16:35:35 -0500 Subject: [PATCH] fix(ui): show Claude reset time for quota display (not earliest) - add getClaudeResetTime to match getMinClaudeQuota logic - weekly Claude resets now show absolute date (01/27, 12:07) - daily Gemini resets no longer overshadow Claude weekly limits --- .../account/flow-viz/account-card.tsx | 4 +- .../cliproxy/provider-editor/account-item.tsx | 4 +- ui/src/lib/utils.ts | 53 ++++++++++++++++--- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/ui/src/components/account/flow-viz/account-card.tsx b/ui/src/components/account/flow-viz/account-card.tsx index 569d640c..ac86917b 100644 --- a/ui/src/components/account/flow-viz/account-card.tsx +++ b/ui/src/components/account/flow-viz/account-card.tsx @@ -6,7 +6,7 @@ import { cn, sortModelsByPriority, formatResetTime, - getEarliestResetTime, + getClaudeResetTime, getMinClaudeQuota, } from '@/lib/utils'; import { PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context'; @@ -226,7 +226,7 @@ export function AccountCard({ ))} {(() => { - const resetTime = getEarliestResetTime(quota?.models || []); + const resetTime = getClaudeResetTime(quota?.models || []); return resetTime ? (
diff --git a/ui/src/components/cliproxy/provider-editor/account-item.tsx b/ui/src/components/cliproxy/provider-editor/account-item.tsx index f0f4aed6..8126989a 100644 --- a/ui/src/components/cliproxy/provider-editor/account-item.tsx +++ b/ui/src/components/cliproxy/provider-editor/account-item.tsx @@ -33,7 +33,7 @@ import { cn, sortModelsByPriority, formatResetTime, - getEarliestResetTime, + getClaudeResetTime, getMinClaudeQuota, } from '@/lib/utils'; import { PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context'; @@ -121,7 +121,7 @@ export function AccountItem({ // Get earliest reset time const nextReset = - quota?.success && quota.models.length > 0 ? getEarliestResetTime(quota.models) : null; + quota?.success && quota.models.length > 0 ? getClaudeResetTime(quota.models) : null; return (
=24h (weekly limits) */ export function formatResetTime(resetTime: string | null): string | null { if (!resetTime) return null; @@ -92,8 +92,19 @@ export function formatResetTime(resetTime: string | null): string | null { if (diff <= 0) return 'soon'; const hours = Math.floor(diff / (1000 * 60 * 60)); - const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); + // Weekly/long resets: show absolute date (e.g., "01/27, 12:07") + if (hours >= 24) { + return reset.toLocaleDateString(undefined, { + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + }); + } + + // Daily resets: show relative time + const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); if (hours > 0) return `in ${hours}h ${minutes}m`; return `in ${minutes}m`; } catch { @@ -117,6 +128,16 @@ export function getEarliestResetTime( ); } +/** + * Filter to get Claude models from a model array + */ +function filterClaudeModels(models: T[]): T[] { + return models.filter((m) => { + const name = (m.displayName || m.name || '').toLowerCase(); + return name.includes('claude'); + }); +} + /** * Calculate the minimum quota percentage from Claude models (primary usage). * Falls back to minimum of all models if no Claude models exist. @@ -127,11 +148,7 @@ export function getMinClaudeQuota< >(models: T[]): number | null { if (models.length === 0) return null; - const claudeModels = models.filter((m) => { - const name = (m.displayName || m.name || '').toLowerCase(); - return name.includes('claude'); - }); - + const claudeModels = filterClaudeModels(models); const targetModels = claudeModels.length > 0 ? claudeModels : models; const percentages = targetModels .map((m) => m.percentage) @@ -140,3 +157,25 @@ export function getMinClaudeQuota< if (percentages.length === 0) return null; return Math.min(...percentages); } + +/** + * Get reset time for Claude models (matches getMinClaudeQuota logic). + * Shows when the Claude quota will reset, not just earliest across all models. + */ +export function getClaudeResetTime< + T extends { name: string; displayName?: string; resetTime: string | null }, +>(models: T[]): string | null { + if (models.length === 0) return null; + + const claudeModels = filterClaudeModels(models); + const targetModels = claudeModels.length > 0 ? claudeModels : models; + + return targetModels.reduce( + (earliest, m) => { + if (!m.resetTime) return earliest; + if (!earliest) return m.resetTime; + return new Date(m.resetTime) < new Date(earliest) ? m.resetTime : earliest; + }, + null as string | null + ); +}