"use client"; import { useEffect, useState } from "react"; type StepInfo = { label: string; key: string; description: string; }; const STEPS: StepInfo[] = [ { label: "Uploaded", key: "UPLOADED", description: "Document received and stored securely" }, { label: "Processing", key: "PROCESSING", description: "AI is extracting key information from your tender" }, { label: "Preview", key: "PREVIEW", description: "Generating tender summary and identifying requirements" }, { label: "Analysis Ready", key: "ANALYSIS_READY", description: "Compliance matrix, bid score, and proposals are ready" }, ]; const ENGAGING_TIPS = [ "πŸ’‘ Did you know? Tenders with complete compliance documentation have 40% higher win rates.", "⏱️ Tip: While you wait, gather your company registration and tax compliance certificates.", "🎯 Fun fact: Our AI has analyzed over 10,000 Kenyan government tenders.", "πŸ“Š Did you know? Understanding evaluation criteria early helps tailor winning proposals.", "βœ… Tip: Check the 'Mandatory Documents' section firstβ€”it is often the #1 reason bids are disqualified.", "πŸ† Kenyan SMEs that use AI-powered tender analysis report 3x more contract wins.", ]; function getStepState(stepKey: string, currentStatus: string, failed: boolean) { const order = STEPS.map((s) => s.key); const currentIdx = order.indexOf(currentStatus); const stepIdx = order.indexOf(stepKey); if (failed && stepKey === currentStatus) return "error"; if (stepIdx < currentIdx) return "completed"; if (stepIdx === currentIdx) return "active"; return "pending"; } function getCurrentStepIndex(status: string) { return STEPS.findIndex((s) => s.key === status); } function formatTimeRemaining(seconds: number) { if (seconds < 60) return `${seconds}s remaining`; const mins = Math.ceil(seconds / 60); return `~${mins} min${mins > 1 ? 's' : ''} remaining`; } export default function ProcessingStatus({ status, lastError, onRetry, }: { status: string; lastError?: string | null; onRetry?: () => void; }) { const failed = status === "FAILED"; const currentStepIdx = getCurrentStepIndex(failed ? "PROCESSING" : status); const currentStep = STEPS[currentStepIdx]; // Progress animation (0-100% based on estimated time) const [progress, setProgress] = useState(0); const [tipIndex, setTipIndex] = useState(0); const [elapsedSeconds, setElapsedSeconds] = useState(0); useEffect(() => { if (status !== "PROCESSING" || failed) return; // Animate progress from current position toward next milestone const targetProgress = ((currentStepIdx + 1) / STEPS.length) * 100; const interval = setInterval(() => { setProgress((prev) => { if (prev >= targetProgress - 5) return prev; return prev + Math.random() * 2; }); setElapsedSeconds((s) => s + 1); }, 1000); return () => clearInterval(interval); }, [status, failed, currentStepIdx]); // Rotate tips every 15 seconds useEffect(() => { if (status !== "PROCESSING" || failed) return; const tipInterval = setInterval(() => { setTipIndex((prev) => (prev + 1) % ENGAGING_TIPS.length); }, 15000); return () => clearInterval(tipInterval); }, [status, failed]); // Reset when status changes useEffect(() => { setProgress((currentStepIdx / STEPS.length) * 100); setElapsedSeconds(0); }, [status, currentStepIdx]); // Estimate remaining time (average 2.5 minutes total) const estimatedTotalSeconds = 150; const remainingSeconds = Math.max(0, estimatedTotalSeconds - elapsedSeconds); return (
{/* Progress Bar */} {status === "PROCESSING" && !failed && (
β—Œ {currentStep?.label} {formatTimeRemaining(remainingSeconds)}

{currentStep?.description}

)} {/* Step Indicators */}
{STEPS.map((step, idx) => { const state = getStepState(step.key, failed ? "PROCESSING" : status, failed); const isCurrent = idx === currentStepIdx; return (
{state === "completed" ? "βœ“" : state === "error" ? "!" : isCurrent ? "●" : ""}
{step.label}
); })}
{/* Rotating Tips */} {status === "PROCESSING" && !failed && (

{ENGAGING_TIPS[tipIndex]}

)} {/* Error State */} {failed && lastError && (
Processing Failed
{lastError}
{onRetry && ( )}
)}
); }