// Track when the time estimate was last updated to calculate live remaining time const [estimateSnapshot, setEstimateSnapshot] = useState<{ remainingSeconds: number; capturedAt: number; }>(() => ({ remainingSeconds:timeEstimate.estimatedRemainingSeconds, capturedAt:Date.now(), }));
// Reset snapshot capturedAt when resuming from pause to start countdown fresh useEffect(() => { if (!isPaused) { setEstimateSnapshot((prev) => ({ ...prev, capturedAt:Date.now(), })); } }, [isPaused]);
// Calculate live remaining time that decreases as actual time passes const [liveRemainingSeconds, setLiveRemainingSeconds] = useState<number>( () =>timeEstimate.estimatedRemainingSeconds, );
// Update elapsed time and live remaining time every second when matching is active useEffect(() => { conststartTimeMs = Number(timeEstimate.startTime); consthasValidStartTime = Number.isFinite(startTimeMs) && startTimeMs > 0;
// Calculate how much time has actually passed since the estimate was captured constsecondsSinceEstimate = Math.floor( (now - estimateSnapshot.capturedAt) / 1000, ); // Subtract elapsed time from the snapshot to get live remaining time constcalculatedRemaining = Math.max( 0, estimateSnapshot.remainingSeconds - secondsSinceEstimate, ); setLiveRemainingSeconds(calculatedRemaining); };
updateTimes();
// Update every second while matching is active and not paused constintervalId = setInterval(updateTimes, 1000);
Displays the progress of the manga matching process, including progress bar, status, and time estimate.
Source