From 3b7dce8bde505dfd1d9b3b3dc22ca5e102d7d361 Mon Sep 17 00:00:00 2001 From: clucraft Date: Thu, 22 Jan 2026 08:18:26 -0500 Subject: [PATCH] Fix countdown timer using server's next_check_at MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add next_check_at to Product interface - Use server-calculated next check time instead of client-side estimate - Accounts for server-side jitter (±5 min) correctly Co-Authored-By: Claude Opus 4.5 --- frontend/src/api/client.ts | 1 + frontend/src/components/ProductCard.tsx | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index e401313..34a1764 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -59,6 +59,7 @@ export interface Product { image_url: string | null; refresh_interval: number; last_checked: string | null; + next_check_at: string | null; stock_status: StockStatus; price_drop_threshold: number | null; target_price: number | null; diff --git a/frontend/src/components/ProductCard.tsx b/frontend/src/components/ProductCard.tsx index 28f21f2..902a520 100644 --- a/frontend/src/components/ProductCard.tsx +++ b/frontend/src/components/ProductCard.tsx @@ -18,23 +18,25 @@ export default function ProductCard({ product, onDelete, onRefresh, isSelected, const [timeRemaining, setTimeRemaining] = useState(''); const [isComplete, setIsComplete] = useState(false); - // Calculate progress and time remaining + // Calculate progress and time remaining using next_check_at from server useEffect(() => { const calculateProgress = () => { - if (!product.last_checked) { + if (!product.next_check_at || !product.last_checked) { setProgress(100); setTimeRemaining('Soon'); return; } const lastChecked = new Date(product.last_checked).getTime(); - const intervalMs = product.refresh_interval * 1000; - const nextCheck = lastChecked + intervalMs; + const nextCheck = new Date(product.next_check_at).getTime(); const now = Date.now(); + const totalDuration = nextCheck - lastChecked; const elapsed = now - lastChecked; const remaining = nextCheck - now; - const progressPercent = Math.min((elapsed / intervalMs) * 100, 100); + const progressPercent = totalDuration > 0 + ? Math.min((elapsed / totalDuration) * 100, 100) + : 100; setProgress(progressPercent); // Trigger complete animation when reaching 100% @@ -64,7 +66,7 @@ export default function ProductCard({ product, onDelete, onRefresh, isSelected, calculateProgress(); const interval = setInterval(calculateProgress, 1000); return () => clearInterval(interval); - }, [product.last_checked, product.refresh_interval, isComplete]); + }, [product.last_checked, product.next_check_at, isComplete]); const handleRefresh = async () => { setIsRefreshing(true);