From a7dd47ab8f5205b8415f11f345fd96eb0f016160 Mon Sep 17 00:00:00 2001 From: YouXam Date: Wed, 7 Jan 2026 14:26:34 +0800 Subject: [PATCH] fix: resets time update --- client/components/AIAccounts.tsx | 110 +++++++++++++------------ client/components/UsageProgressBar.tsx | 69 +++++++++++++--- 2 files changed, 117 insertions(+), 62 deletions(-) diff --git a/client/components/AIAccounts.tsx b/client/components/AIAccounts.tsx index 1feec5f..bc31021 100644 --- a/client/components/AIAccounts.tsx +++ b/client/components/AIAccounts.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { UsageProgressBar } from './UsageProgressBar'; interface ClaudeAccount { @@ -73,17 +73,20 @@ export function AIAccounts({ apiKey }: AIAccountsProps) { const [openaiAccounts, setOpenaiAccounts] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isRefreshing, setIsRefreshing] = useState(false); - const [error, setError] = useState(''); + const [refreshError, setRefreshError] = useState(''); + const [initialError, setInitialError] = useState(''); + const hasLoadedDataRef = useRef(false); useEffect(() => { - fetchAccounts(); - const interval = setInterval(fetchAccounts, 30000); + fetchAccounts('initial'); + const interval = setInterval(() => fetchAccounts('auto'), 30000); return () => clearInterval(interval); }, [apiKey]); - const fetchAccounts = async (isRefresh = false) => { - if (isRefresh) { + const fetchAccounts = async (type: 'initial' | 'manual' | 'auto' = 'auto') => { + if (type === 'manual') { setIsRefreshing(true); + setRefreshError(''); } try { @@ -100,18 +103,34 @@ export function AIAccounts({ apiKey }: AIAccountsProps) { const data = await response.json(); setClaudeAccounts(data.claude || []); setOpenaiAccounts(data.openai || []); - setError(''); + setRefreshError(''); + setInitialError(''); + hasLoadedDataRef.current = true; } catch (err) { console.error('Error fetching AI accounts:', err); - setError(err instanceof Error ? err.message : 'Failed to load AI accounts'); + const errorMessage = err instanceof Error ? err.message : 'Failed to load AI accounts'; + + if (type === 'initial') { + setInitialError(errorMessage); + } else if (hasLoadedDataRef.current) { + // Only set refresh error if we have previously loaded data successfully + setRefreshError(errorMessage); + } } finally { - setIsLoading(false); - if (isRefresh) { + if (type === 'initial') { + setIsLoading(false); + } + if (type === 'manual') { setIsRefreshing(false); } } }; + const handleRetry = () => { + setRefreshError(''); + fetchAccounts('manual'); + }; + const formatLastUsed = (lastUsedAt: string | null) => { if (!lastUsedAt) return 'Never'; const date = new Date(lastUsedAt); @@ -127,20 +146,6 @@ export function AIAccounts({ apiKey }: AIAccountsProps) { 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': @@ -186,16 +191,16 @@ export function AIAccounts({ apiKey }: AIAccountsProps) { ); } - if (error) { + if (initialError) { return (

AI Accounts Status

-

{error}

+

{initialError}

+
+ )} + + + + + {isRefreshing ? 'Refreshing...' : 'Refresh'} + +
@@ -275,27 +293,21 @@ export function AIAccounts({ apiKey }: AIAccountsProps) { {claudeAcc.claudeUsage.fiveHour && ( )} {claudeAcc.claudeUsage.sevenDay && ( )} {claudeAcc.claudeUsage.sevenDayOpus && ( )} @@ -305,18 +317,14 @@ export function AIAccounts({ apiKey }: AIAccountsProps) { {openaiAcc.codexUsage.primary && ( )} {openaiAcc.codexUsage.secondary && ( )} diff --git a/client/components/UsageProgressBar.tsx b/client/components/UsageProgressBar.tsx index c1b2b29..b6afa3d 100644 --- a/client/components/UsageProgressBar.tsx +++ b/client/components/UsageProgressBar.tsx @@ -1,18 +1,65 @@ +import { useState, useEffect } from 'react'; + interface UsageProgressBarProps { label: string; - resetTime: string; percentage: number; - resetAfterSeconds?: number; - resetAt?: string; + resetAt: string; } -export function UsageProgressBar({ label, resetTime, percentage, resetAfterSeconds, resetAt }: UsageProgressBarProps) { - // Check if reset time has passed - const resetElapsed = - resetAfterSeconds !== undefined && ( - resetAfterSeconds <= 0 || - (resetAt && !isNaN(Date.parse(resetAt)) && Date.now() >= Date.parse(resetAt)) - ); +export function UsageProgressBar({ label, percentage, resetAt }: UsageProgressBarProps) { + const [remainingTime, setRemainingTime] = useState(''); + const [resetElapsed, setResetElapsed] = useState(false); + + useEffect(() => { + const updateRemainingTime = () => { + const resetTimestamp = Date.parse(resetAt); + + if (isNaN(resetTimestamp)) { + setRemainingTime('--'); + setResetElapsed(false); + return; + } + + const now = Date.now(); + const diffMs = resetTimestamp - now; + + if (diffMs <= 0) { + setResetElapsed(true); + setRemainingTime(''); + return; + } + + setResetElapsed(false); + + const totalSeconds = Math.floor(diffMs / 1000); + const days = Math.floor(totalSeconds / 86400); + const hours = Math.floor((totalSeconds % 86400) / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + + if (days > 0) { + if (hours > 0) { + setRemainingTime(`${days}d ${hours}h`); + } else { + setRemainingTime(`${days}d`); + } + } else if (hours > 0) { + setRemainingTime(`${hours}h ${minutes}m`); + } else if (minutes > 0) { + setRemainingTime(`${minutes}m ${seconds}s`); + } else { + setRemainingTime(`${seconds}s`); + } + }; + + // Initial update + updateRemainingTime(); + + // Update every second + const interval = setInterval(updateRemainingTime, 1000); + + return () => clearInterval(interval); + }, [resetAt]); // If reset time has passed, show 0% const displayPercentage = resetElapsed ? 0 : percentage; @@ -20,7 +67,7 @@ export function UsageProgressBar({ label, resetTime, percentage, resetAfterSecon return (
- {label}{!resetElapsed && ` · Resets in ${resetTime}`} + {label}{!resetElapsed && remainingTime && ` · Resets in ${remainingTime}`}