mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 22:17:14 +00:00
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
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
|||||||
cn,
|
cn,
|
||||||
sortModelsByPriority,
|
sortModelsByPriority,
|
||||||
formatResetTime,
|
formatResetTime,
|
||||||
getEarliestResetTime,
|
getClaudeResetTime,
|
||||||
getMinClaudeQuota,
|
getMinClaudeQuota,
|
||||||
} from '@/lib/utils';
|
} from '@/lib/utils';
|
||||||
import { PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context';
|
import { PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context';
|
||||||
@@ -226,7 +226,7 @@ export function AccountCard({
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{(() => {
|
{(() => {
|
||||||
const resetTime = getEarliestResetTime(quota?.models || []);
|
const resetTime = getClaudeResetTime(quota?.models || []);
|
||||||
return resetTime ? (
|
return resetTime ? (
|
||||||
<div className="flex items-center gap-1.5 mt-2 pt-2 border-t border-border/50">
|
<div className="flex items-center gap-1.5 mt-2 pt-2 border-t border-border/50">
|
||||||
<Clock className="w-3 h-3 text-blue-400" />
|
<Clock className="w-3 h-3 text-blue-400" />
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import {
|
|||||||
cn,
|
cn,
|
||||||
sortModelsByPriority,
|
sortModelsByPriority,
|
||||||
formatResetTime,
|
formatResetTime,
|
||||||
getEarliestResetTime,
|
getClaudeResetTime,
|
||||||
getMinClaudeQuota,
|
getMinClaudeQuota,
|
||||||
} from '@/lib/utils';
|
} from '@/lib/utils';
|
||||||
import { PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context';
|
import { PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context';
|
||||||
@@ -121,7 +121,7 @@ export function AccountItem({
|
|||||||
|
|
||||||
// Get earliest reset time
|
// Get earliest reset time
|
||||||
const nextReset =
|
const nextReset =
|
||||||
quota?.success && quota.models.length > 0 ? getEarliestResetTime(quota.models) : null;
|
quota?.success && quota.models.length > 0 ? getClaudeResetTime(quota.models) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
+46
-7
@@ -81,7 +81,7 @@ export function sortModelsByPriority<T extends { name: string; displayName?: str
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format reset time as relative time (e.g., "in 2h 30m")
|
* Format reset time - relative for <24h, absolute date for >=24h (weekly limits)
|
||||||
*/
|
*/
|
||||||
export function formatResetTime(resetTime: string | null): string | null {
|
export function formatResetTime(resetTime: string | null): string | null {
|
||||||
if (!resetTime) return null;
|
if (!resetTime) return null;
|
||||||
@@ -92,8 +92,19 @@ export function formatResetTime(resetTime: string | null): string | null {
|
|||||||
if (diff <= 0) return 'soon';
|
if (diff <= 0) return 'soon';
|
||||||
|
|
||||||
const hours = Math.floor(diff / (1000 * 60 * 60));
|
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`;
|
if (hours > 0) return `in ${hours}h ${minutes}m`;
|
||||||
return `in ${minutes}m`;
|
return `in ${minutes}m`;
|
||||||
} catch {
|
} catch {
|
||||||
@@ -117,6 +128,16 @@ export function getEarliestResetTime<T extends { resetTime: string | null }>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to get Claude models from a model array
|
||||||
|
*/
|
||||||
|
function filterClaudeModels<T extends { name: string; displayName?: string }>(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).
|
* Calculate the minimum quota percentage from Claude models (primary usage).
|
||||||
* Falls back to minimum of all models if no Claude models exist.
|
* Falls back to minimum of all models if no Claude models exist.
|
||||||
@@ -127,11 +148,7 @@ export function getMinClaudeQuota<
|
|||||||
>(models: T[]): number | null {
|
>(models: T[]): number | null {
|
||||||
if (models.length === 0) return null;
|
if (models.length === 0) return null;
|
||||||
|
|
||||||
const claudeModels = models.filter((m) => {
|
const claudeModels = filterClaudeModels(models);
|
||||||
const name = (m.displayName || m.name || '').toLowerCase();
|
|
||||||
return name.includes('claude');
|
|
||||||
});
|
|
||||||
|
|
||||||
const targetModels = claudeModels.length > 0 ? claudeModels : models;
|
const targetModels = claudeModels.length > 0 ? claudeModels : models;
|
||||||
const percentages = targetModels
|
const percentages = targetModels
|
||||||
.map((m) => m.percentage)
|
.map((m) => m.percentage)
|
||||||
@@ -140,3 +157,25 @@ export function getMinClaudeQuota<
|
|||||||
if (percentages.length === 0) return null;
|
if (percentages.length === 0) return null;
|
||||||
return Math.min(...percentages);
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user