File size: 4,207 Bytes
84820a1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
import React, { useState, useEffect } from "react";
import { Loader2, CheckCircle2, Circle, Activity, Cpu, Scan, ShieldCheck, Binary, RefreshCw } from "lucide-react";
import GlassCard from "./GlassCard";
interface Step {
label: string;
icon: React.ReactNode;
}
interface ProcessingOverlayProps {
isOpen: boolean;
type: "diagnosis" | "segmentation";
}
const DIAGNOSIS_STEPS: Step[] = [
{ label: "Resizing Image", icon: <Scan className="w-5 h-5" /> },
{ label: "Input to Diagnosis mode", icon: <Cpu className="w-5 h-5" /> },
{ label: "Region identified", icon: <Activity className="w-5 h-5" /> },
{ label: "Status determined", icon: <ShieldCheck className="w-5 h-5" /> },
{ label: "Stage diagnosed", icon: <Binary className="w-5 h-5" /> },
];
const SEGMENTATION_STEPS: Step[] = [
{ label: "Image resizing", icon: <Scan className="w-5 h-5" /> },
{ label: "Input to model", icon: <Cpu className="w-5 h-5" /> },
{ label: "Reconstructing image and then segmenting cells", icon: <Activity className="w-5 h-5" /> },
{ label: "Lastly cleaning the mask", icon: <Binary className="w-5 h-5" /> },
];
const ProcessingOverlay: React.FC<ProcessingOverlayProps> = ({ isOpen, type }) => {
const [currentStep, setCurrentStep] = useState(0);
const steps = type === "diagnosis" ? DIAGNOSIS_STEPS : SEGMENTATION_STEPS;
useEffect(() => {
if (!isOpen) {
setCurrentStep(0);
return;
}
const interval = setInterval(() => {
setCurrentStep((prev) => {
if (prev < steps.length - 1) return prev + 1;
return prev;
});
}, 2000); // Change step every 2 seconds
return () => clearInterval(interval);
}, [isOpen, steps.length]);
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-md animate-in fade-in duration-300">
<GlassCard variant="bordered" className="w-full max-w-md p-8 flex flex-col items-center gap-8 shadow-2xl border-primary/20 bg-card/50">
{/* Main Loader Icon */}
<div className="relative">
<div className="absolute inset-0 rounded-full bg-primary/20 animate-ping" />
<div className="relative w-20 h-20 rounded-full bg-primary/10 flex items-center justify-center border border-primary/30">
<Loader2 className="w-10 h-10 text-primary animate-spin" />
</div>
</div>
<div className="text-center">
<h2 className="text-2xl font-bold text-foreground mb-2">
{type === "diagnosis" ? "Running Diagnosis" : "Generating Segmentation"}
</h2>
<p className="text-muted-foreground text-sm">
Please wait while our AI models process your sample...
</p>
</div>
{/* Steps List */}
<div className="w-full flex flex-col gap-4">
{steps.map((step, index) => {
const isCompleted = index < currentStep;
const isCurrent = index === currentStep;
return (
<div
key={index}
className={`flex items-center gap-4 p-3 rounded-lg transition-all duration-500 ${
isCurrent ? "bg-primary/10 border border-primary/20 scale-105" : "opacity-50"
} ${isCompleted ? "opacity-80" : ""}`}
>
<div className={`flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center ${
isCompleted ? "bg-success/20 text-success" :
isCurrent ? "bg-primary/20 text-primary" : "bg-muted text-muted-foreground"
}`}>
{isCompleted ? <CheckCircle2 className="w-5 h-5" /> : step.icon}
</div>
<div className="flex-1 text-left">
<p className={`font-medium ${isCurrent ? "text-primary" : "text-foreground"}`}>
{step.label}
</p>
</div>
{isCurrent && <Loader2 className="w-4 h-4 text-primary animate-spin" />}
</div>
);
})}
</div>
</GlassCard>
</div>
);
};
export default ProcessingOverlay;
|