Spaces:
Sleeping
Sleeping
| import React from "react"; | |
| import { motion } from "framer-motion"; | |
| import { | |
| FileSearch, | |
| Cpu, | |
| TableProperties, | |
| CheckCircle2, | |
| Loader2, | |
| } from "lucide-react"; | |
| import { cn } from "@/lib/utils"; | |
| const steps = [ | |
| { id: "upload", label: "Document Received", icon: FileSearch }, | |
| { id: "analyze", label: "AI Analysis", icon: Cpu }, | |
| { id: "extract", label: "Data Extraction", icon: TableProperties }, | |
| { id: "complete", label: "Complete", icon: CheckCircle2 }, | |
| ]; | |
| export default function ProcessingStatus({ isProcessing, isComplete }) { | |
| const getCurrentStep = () => { | |
| if (isComplete) return 4; | |
| if (isProcessing) return 2; | |
| return 0; | |
| }; | |
| const currentStep = getCurrentStep(); | |
| if (!isProcessing && !isComplete) return null; | |
| return ( | |
| <motion.div | |
| initial={{ opacity: 0, y: -10 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| className="bg-white rounded-2xl border border-slate-200 p-6" | |
| > | |
| <div className="flex items-center justify-between"> | |
| {steps.map((step, index) => { | |
| const isActive = index + 1 === currentStep; | |
| const isCompleted = index + 1 < currentStep; | |
| const Icon = step.icon; | |
| return ( | |
| <React.Fragment key={step.id}> | |
| <div className="flex flex-col items-center"> | |
| <motion.div | |
| initial={false} | |
| animate={{ | |
| scale: isActive ? 1.1 : 1, | |
| backgroundColor: isCompleted | |
| ? "rgb(16 185 129)" | |
| : isActive | |
| ? "rgb(99 102 241)" | |
| : "rgb(241 245 249)", | |
| }} | |
| className={cn( | |
| "h-12 w-12 rounded-xl flex items-center justify-center mb-2 transition-colors", | |
| (isCompleted || isActive) && "shadow-lg" | |
| )} | |
| style={{ | |
| boxShadow: isActive | |
| ? "0 8px 16px -4px rgba(99, 102, 241, 0.3)" | |
| : isCompleted | |
| ? "0 8px 16px -4px rgba(16, 185, 129, 0.3)" | |
| : "none", | |
| }} | |
| > | |
| {isActive ? ( | |
| <motion.div | |
| animate={{ rotate: 360 }} | |
| transition={{ | |
| duration: 1.5, | |
| repeat: Infinity, | |
| ease: "linear", | |
| }} | |
| > | |
| <Loader2 className="h-5 w-5 text-white" /> | |
| </motion.div> | |
| ) : ( | |
| <Icon | |
| className={cn( | |
| "h-5 w-5", | |
| isCompleted ? "text-white" : "text-slate-400" | |
| )} | |
| /> | |
| )} | |
| </motion.div> | |
| <span | |
| className={cn( | |
| "text-xs font-medium text-center", | |
| isActive | |
| ? "text-indigo-600" | |
| : isCompleted | |
| ? "text-emerald-600" | |
| : "text-slate-400" | |
| )} | |
| > | |
| {step.label} | |
| </span> | |
| </div> | |
| {index < steps.length - 1 && ( | |
| <div className="flex-1 h-0.5 mx-4 mb-6 relative overflow-hidden rounded-full bg-slate-100"> | |
| <motion.div | |
| initial={{ width: 0 }} | |
| animate={{ | |
| width: isCompleted ? "100%" : isActive ? "50%" : "0%", | |
| }} | |
| transition={{ duration: 0.5 }} | |
| className={cn( | |
| "absolute inset-y-0 left-0", | |
| isCompleted ? "bg-emerald-500" : "bg-indigo-500" | |
| )} | |
| /> | |
| </div> | |
| )} | |
| </React.Fragment> | |
| ); | |
| })} | |
| </div> | |
| </motion.div> | |
| ); | |
| } | |