mirror of
https://github.com/clucraft/PriceGhost.git
synced 2026-05-15 10:52:36 +02:00
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:
parent
d09850d84e
commit
3b7dce8bde
2 changed files with 9 additions and 6 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue