133 lines
4.6 KiB
TypeScript
133 lines
4.6 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { useNavigate, useLocation } from 'react-router';
|
|
import { motion } from 'motion/react';
|
|
import { Check } from 'lucide-react';
|
|
|
|
const steps = [
|
|
'Scanning website...',
|
|
'Capturing channel screenshots...',
|
|
'Analyzing social media presence...',
|
|
'Evaluating brand consistency...',
|
|
'Generating intelligence report...',
|
|
];
|
|
|
|
export default function AnalysisLoadingPage() {
|
|
const [currentStep, setCurrentStep] = useState(0);
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const url = (location.state as { url?: string })?.url;
|
|
|
|
useEffect(() => {
|
|
const timers: ReturnType<typeof setTimeout>[] = [];
|
|
|
|
steps.forEach((_, index) => {
|
|
timers.push(
|
|
setTimeout(() => {
|
|
setCurrentStep(index + 1);
|
|
}, (index + 1) * 1250)
|
|
);
|
|
});
|
|
|
|
timers.push(
|
|
setTimeout(() => {
|
|
navigate('/report/view-clinic', { replace: true });
|
|
}, 5500)
|
|
);
|
|
|
|
return () => timers.forEach(clearTimeout);
|
|
}, [navigate]);
|
|
|
|
return (
|
|
<div className="relative min-h-screen bg-primary-900 flex flex-col items-center justify-center px-6 overflow-hidden">
|
|
{/* Radial gradient overlay */}
|
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,_rgba(79,29,161,0.25)_0%,_transparent_70%)]" />
|
|
|
|
{/* Purple glow blob */}
|
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[500px] h-[500px] bg-purple-600/20 rounded-full blur-[120px] pointer-events-none" />
|
|
|
|
<div className="relative z-10 flex flex-col items-center w-full max-w-lg">
|
|
{/* INFINITH logo text */}
|
|
<motion.h1
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6 }}
|
|
className="text-4xl md:text-5xl font-serif font-bold text-gradient mb-4"
|
|
>
|
|
INFINITH
|
|
</motion.h1>
|
|
|
|
{/* Entered URL */}
|
|
{url && (
|
|
<motion.p
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.1 }}
|
|
className="text-purple-300/80 text-sm font-mono mb-12 truncate max-w-full"
|
|
>
|
|
{url}
|
|
</motion.p>
|
|
)}
|
|
|
|
{/* Analysis steps */}
|
|
<div className="w-full space-y-5 mb-14">
|
|
{steps.map((step, index) => {
|
|
const isCompleted = currentStep > index;
|
|
const isActive = currentStep === index;
|
|
|
|
return (
|
|
<motion.div
|
|
key={step}
|
|
initial={{ opacity: 0, x: -20 }}
|
|
animate={{ opacity: isActive || isCompleted ? 1 : 0.3, x: 0 }}
|
|
transition={{ duration: 0.4, delay: index * 0.15 }}
|
|
className="flex items-center gap-4"
|
|
>
|
|
{/* Status icon */}
|
|
<div className="w-7 h-7 flex-shrink-0 flex items-center justify-center">
|
|
{isCompleted ? (
|
|
<motion.div
|
|
initial={{ scale: 0 }}
|
|
animate={{ scale: 1 }}
|
|
transition={{ type: 'spring', stiffness: 300, damping: 20 }}
|
|
className="w-7 h-7 rounded-full bg-gradient-to-r from-[#4F1DA1] to-[#6C5CE7] flex items-center justify-center"
|
|
>
|
|
<Check className="w-4 h-4 text-white" strokeWidth={3} />
|
|
</motion.div>
|
|
) : isActive ? (
|
|
<div className="w-7 h-7 rounded-full border-2 border-purple-400 border-t-transparent animate-spin" />
|
|
) : (
|
|
<div className="w-7 h-7 rounded-full border-2 border-white/10" />
|
|
)}
|
|
</div>
|
|
|
|
{/* Step text */}
|
|
<span
|
|
className={`text-base font-sans transition-colors duration-300 ${
|
|
isCompleted
|
|
? 'text-white'
|
|
: isActive
|
|
? 'text-purple-200'
|
|
: 'text-white/30'
|
|
}`}
|
|
>
|
|
{step}
|
|
</span>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* Progress bar */}
|
|
<div className="w-full h-2 bg-white/10 rounded-full overflow-hidden">
|
|
<motion.div
|
|
initial={{ width: '0%' }}
|
|
animate={{ width: '100%' }}
|
|
transition={{ duration: 5, ease: 'linear' }}
|
|
className="h-full bg-gradient-to-r from-[#4F1DA1] to-[#6C5CE7] rounded-full"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|