Fix countdown timer using server's next_check_at

- 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 <noreply@anthropic.com>
This commit is contained in:
clucraft 2026-01-22 08:18:26 -05:00
parent d09850d84e
commit 3b7dce8bde
2 changed files with 9 additions and 6 deletions

View file

@ -59,6 +59,7 @@ export interface Product {
image_url: string | null; image_url: string | null;
refresh_interval: number; refresh_interval: number;
last_checked: string | null; last_checked: string | null;
next_check_at: string | null;
stock_status: StockStatus; stock_status: StockStatus;
price_drop_threshold: number | null; price_drop_threshold: number | null;
target_price: number | null; target_price: number | null;

View file

@ -18,23 +18,25 @@ export default function ProductCard({ product, onDelete, onRefresh, isSelected,
const [timeRemaining, setTimeRemaining] = useState(''); const [timeRemaining, setTimeRemaining] = useState('');
const [isComplete, setIsComplete] = useState(false); const [isComplete, setIsComplete] = useState(false);
// Calculate progress and time remaining // Calculate progress and time remaining using next_check_at from server
useEffect(() => { useEffect(() => {
const calculateProgress = () => { const calculateProgress = () => {
if (!product.last_checked) { if (!product.next_check_at || !product.last_checked) {
setProgress(100); setProgress(100);
setTimeRemaining('Soon'); setTimeRemaining('Soon');
return; return;
} }
const lastChecked = new Date(product.last_checked).getTime(); const lastChecked = new Date(product.last_checked).getTime();
const intervalMs = product.refresh_interval * 1000; const nextCheck = new Date(product.next_check_at).getTime();
const nextCheck = lastChecked + intervalMs;
const now = Date.now(); const now = Date.now();
const totalDuration = nextCheck - lastChecked;
const elapsed = now - lastChecked; const elapsed = now - lastChecked;
const remaining = nextCheck - now; 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); setProgress(progressPercent);
// Trigger complete animation when reaching 100% // Trigger complete animation when reaching 100%
@ -64,7 +66,7 @@ export default function ProductCard({ product, onDelete, onRefresh, isSelected,
calculateProgress(); calculateProgress();
const interval = setInterval(calculateProgress, 1000); const interval = setInterval(calculateProgress, 1000);
return () => clearInterval(interval); return () => clearInterval(interval);
}, [product.last_checked, product.refresh_interval, isComplete]); }, [product.last_checked, product.next_check_at, isComplete]);
const handleRefresh = async () => { const handleRefresh = async () => {
setIsRefreshing(true); setIsRefreshing(true);