Progress bar: forward-only crawl, never goes backward
This commit is contained in:
@@ -45,27 +45,35 @@ export function LoadingCard({ jobId, onDone, onError }: LoadingCardProps) {
|
||||
totalLeads: 0,
|
||||
emailsFound: 0,
|
||||
});
|
||||
const [progressWidth, setProgressWidth] = useState(40);
|
||||
const [progressWidth, setProgressWidth] = useState(3);
|
||||
|
||||
// Phase → minimum progress threshold (never go below these)
|
||||
const PHASE_MIN: Record<Phase, number> = {
|
||||
scraping: 3,
|
||||
enriching: 35,
|
||||
emails: 60,
|
||||
done: 100,
|
||||
};
|
||||
const PHASE_MAX: Record<Phase, number> = {
|
||||
scraping: 34,
|
||||
enriching: 59,
|
||||
emails: 88,
|
||||
done: 100,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
let pendulumInterval: ReturnType<typeof setInterval> | null = null;
|
||||
let crawlInterval: ReturnType<typeof setInterval> | null = null;
|
||||
let pollTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
// Pendulum animation while running
|
||||
let goingUp = true;
|
||||
pendulumInterval = setInterval(() => {
|
||||
// Slowly creep forward — never backwards
|
||||
crawlInterval = setInterval(() => {
|
||||
if (cancelled) return;
|
||||
setProgressWidth((prev) => {
|
||||
if (goingUp) {
|
||||
if (prev >= 85) { goingUp = false; return 84; }
|
||||
return prev + 1;
|
||||
} else {
|
||||
if (prev <= 40) { goingUp = true; return 41; }
|
||||
return prev - 1;
|
||||
}
|
||||
setProgressWidth(prev => {
|
||||
if (prev >= 88) return prev; // hard cap while loading
|
||||
return prev + 0.4; // ~0.4% per 200ms → ~2min to reach 88%
|
||||
});
|
||||
}, 120);
|
||||
}, 200);
|
||||
|
||||
async function poll() {
|
||||
if (cancelled) return;
|
||||
@@ -76,16 +84,23 @@ export function LoadingCard({ jobId, onDone, onError }: LoadingCardProps) {
|
||||
|
||||
if (!cancelled) {
|
||||
setJobStatus(data);
|
||||
const phase = getPhase(data);
|
||||
|
||||
// Advance to at least the phase minimum — never go backwards
|
||||
setProgressWidth(prev => Math.max(prev, PHASE_MIN[phase]));
|
||||
|
||||
if (data.status === "complete") {
|
||||
if (pendulumInterval) clearInterval(pendulumInterval);
|
||||
if (crawlInterval) clearInterval(crawlInterval);
|
||||
setProgressWidth(100);
|
||||
setTimeout(() => {
|
||||
if (!cancelled) onDone(data.totalLeads);
|
||||
}, 800);
|
||||
} else if (data.status === "failed") {
|
||||
if (pendulumInterval) clearInterval(pendulumInterval);
|
||||
if (crawlInterval) clearInterval(crawlInterval);
|
||||
onError();
|
||||
} else {
|
||||
// Cap crawl at phase max while in that phase
|
||||
setProgressWidth(prev => Math.min(prev, PHASE_MAX[phase]));
|
||||
pollTimeout = setTimeout(poll, 2500);
|
||||
}
|
||||
}
|
||||
@@ -100,7 +115,7 @@ export function LoadingCard({ jobId, onDone, onError }: LoadingCardProps) {
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
if (pendulumInterval) clearInterval(pendulumInterval);
|
||||
if (crawlInterval) clearInterval(crawlInterval);
|
||||
if (pollTimeout) clearTimeout(pollTimeout);
|
||||
};
|
||||
}, [jobId, onDone, onError]);
|
||||
|
||||
Reference in New Issue
Block a user