o2o-infinith-demo/src/pages/AnalysisLoadingPage.tsx

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>
);
}