174 lines
9.1 KiB
TypeScript
174 lines
9.1 KiB
TypeScript
"use client";
|
|
|
|
import { motion } from 'framer-motion';
|
|
import { Activity, Zap, ShieldAlert, Cpu, TrendingUp, CheckCircle2, Clock } from 'lucide-react';
|
|
|
|
const stats = [
|
|
{ title: 'Lots Scanned', value: '142,893', icon: Activity, color: 'text-blue-500', bg: 'bg-blue-500/10', border: 'border-blue-500/20' },
|
|
{ title: 'Active Targets', value: '84', icon: Zap, color: 'text-amber-500', bg: 'bg-amber-500/10', border: 'border-amber-500/20' },
|
|
{ title: 'Alerts Fired', value: '1,204', icon: TrendingUp, color: 'text-purple-500', bg: 'bg-purple-500/10', border: 'border-purple-500/20' },
|
|
{ title: 'AI Decisions', value: '89,430', icon: Cpu, color: 'text-green-500', bg: 'bg-green-500/10', border: 'border-green-500/20' },
|
|
];
|
|
|
|
const containerVariants = {
|
|
hidden: { opacity: 0 },
|
|
show: {
|
|
opacity: 1,
|
|
transition: {
|
|
staggerChildren: 0.1,
|
|
}
|
|
}
|
|
};
|
|
|
|
const itemVariants = {
|
|
hidden: { opacity: 0, y: 20, scale: 0.9 },
|
|
show: { opacity: 1, y: 0, scale: 1, transition: { type: "spring" as const, stiffness: 300, damping: 24 } }
|
|
};
|
|
|
|
export default function DashboardPage() {
|
|
return (
|
|
<div className="container mx-auto px-6 py-12 relative">
|
|
<div className="absolute top-0 right-0 w-[50%] h-[50%] bg-primary/5 rounded-full blur-[150px] pointer-events-none -z-10" />
|
|
|
|
<motion.div
|
|
initial={{ opacity: 0, y: -20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className="flex flex-col md:flex-row justify-between items-start md:items-end mb-12 gap-4"
|
|
>
|
|
<div>
|
|
<h1 className="text-5xl font-black tracking-tight mb-3 flex items-center gap-4 drop-shadow-sm">
|
|
System Overview <motion.span animate={{ y: [0, -10, 0] }} transition={{ duration: 2, repeat: Infinity }} className="text-4xl">🚀</motion.span>
|
|
</h1>
|
|
<p className="text-muted-foreground text-xl font-medium">Real-time status of all your autonomous AI agents.</p>
|
|
</div>
|
|
<motion.div
|
|
whileHover={{ scale: 1.05 }}
|
|
className="flex items-center gap-3 px-6 py-3 bg-green-500/10 text-green-500 border border-green-500/20 rounded-full font-black shadow-inner shadow-green-500/10 backdrop-blur-md"
|
|
>
|
|
<span className="relative flex h-3.5 w-3.5">
|
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
|
<span className="relative inline-flex rounded-full h-3.5 w-3.5 bg-green-500 shadow-[0_0_10px_rgba(34,197,94,1)]"></span>
|
|
</span>
|
|
All Systems Go
|
|
</motion.div>
|
|
</motion.div>
|
|
|
|
<motion.div
|
|
variants={containerVariants}
|
|
initial="hidden"
|
|
animate="show"
|
|
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-12"
|
|
>
|
|
{stats.map((stat, i) => (
|
|
<motion.div
|
|
key={i}
|
|
variants={itemVariants}
|
|
whileHover={{ y: -5, scale: 1.02 }}
|
|
className={`p-6 bg-card/80 backdrop-blur-xl border border-white/5 hover:${stat.border} rounded-[2rem] shadow-lg hover:shadow-xl transition-all relative overflow-hidden group`}
|
|
>
|
|
<div className={`absolute -right-10 -top-10 w-32 h-32 ${stat.bg} rounded-full blur-[40px] group-hover:scale-150 transition-transform duration-700`} />
|
|
<div className="flex justify-between items-start mb-6 relative z-10">
|
|
<div className="text-muted-foreground font-bold text-lg">{stat.title}</div>
|
|
<div className={`p-3 rounded-2xl ${stat.bg} shadow-inner`}>
|
|
<stat.icon className={`w-6 h-6 ${stat.color}`} />
|
|
</div>
|
|
</div>
|
|
<div className="text-5xl font-black text-foreground drop-shadow-md relative z-10">{stat.value}</div>
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
|
|
<div className="grid lg:grid-cols-3 gap-8">
|
|
<div className="col-span-2">
|
|
<motion.div
|
|
initial={{ opacity: 0, x: -30 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
transition={{ delay: 0.3, type: "spring" as const }}
|
|
className="p-8 bg-card/80 backdrop-blur-xl border border-white/5 rounded-[2.5rem] h-[500px] flex flex-col shadow-xl relative overflow-hidden"
|
|
>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 to-transparent pointer-events-none" />
|
|
<div className="flex items-center gap-4 mb-8 pb-6 border-b border-border/50 relative z-10">
|
|
<Clock className="w-8 h-8 text-primary" />
|
|
<h2 className="text-3xl font-black tracking-tight">Live Activity Log</h2>
|
|
</div>
|
|
<div className="flex-1 overflow-auto space-y-4 pr-4 custom-scrollbar relative z-10">
|
|
{[
|
|
{ time: '10:42:01 AM', msg: 'Scout Agent detected new items on eBay_UK...', type: 'normal' },
|
|
{ time: '10:41:55 AM', msg: 'Analyst Agent processing 14 lots for "RTX 4090"...', type: 'normal' },
|
|
{ time: '10:41:30 AM', msg: 'MATCH FOUND: "RTX 4090 Box Only" - Rejected by AI (Reason: Scam)', type: 'warning' },
|
|
{ time: '10:40:12 AM', msg: 'HIGH VALUE MATCH: "ThinkPad T14 Gen 3" - $450 (Est: $800). Alert Sent.', type: 'success' },
|
|
{ time: '10:39:45 AM', msg: 'Strategist Agent optimizing scrape timings for ShopGoodwill...', type: 'normal' },
|
|
].map((log, j) => (
|
|
<motion.div
|
|
key={j}
|
|
initial={{ opacity: 0, x: -20 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
transition={{ delay: 0.5 + (j * 0.1) }}
|
|
className={`flex gap-4 p-5 rounded-2xl ${
|
|
log.type === 'warning' ? 'bg-amber-500/10 border border-amber-500/20' :
|
|
log.type === 'success' ? 'bg-green-500/10 border border-green-500/20 shadow-[0_0_15px_rgba(34,197,94,0.15)]' :
|
|
'bg-secondary/40 border border-white/5'
|
|
} backdrop-blur-sm transition-all hover:scale-[1.01]`}
|
|
>
|
|
<span className={`whitespace-nowrap font-bold ${
|
|
log.type === 'warning' ? 'text-amber-500' :
|
|
log.type === 'success' ? 'text-green-500' :
|
|
'text-muted-foreground'
|
|
}`}>{log.time}</span>
|
|
<span className={`font-bold ${
|
|
log.type === 'warning' ? 'text-amber-600 dark:text-amber-400' :
|
|
log.type === 'success' ? 'text-green-600 dark:text-green-400 flex items-center gap-2' :
|
|
'text-foreground'
|
|
}`}>
|
|
{log.type === 'success' && <CheckCircle2 className="w-5 h-5" />}
|
|
{log.msg}
|
|
</span>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
<div>
|
|
<motion.div
|
|
initial={{ opacity: 0, x: 30 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
transition={{ delay: 0.4, type: "spring" as const }}
|
|
className="p-8 bg-card/80 backdrop-blur-xl border border-white/5 rounded-[2.5rem] h-[500px] shadow-xl relative overflow-hidden"
|
|
>
|
|
<div className="absolute inset-0 bg-gradient-to-bl from-accent/5 to-transparent pointer-events-none" />
|
|
<div className="flex items-center gap-4 mb-8 pb-6 border-b border-border/50 relative z-10">
|
|
<Activity className="w-8 h-8 text-primary" />
|
|
<h2 className="text-3xl font-black tracking-tight">Node Health</h2>
|
|
</div>
|
|
<div className="space-y-8 relative z-10">
|
|
{[
|
|
{ name: 'eBay US', health: 100, color: 'bg-green-500', shadow: 'shadow-[0_0_15px_rgba(34,197,94,0.5)]' },
|
|
{ name: 'eBay UK', health: 98, color: 'bg-blue-500', shadow: 'shadow-[0_0_15px_rgba(59,130,246,0.5)]' },
|
|
{ name: 'HiBid', health: 85, color: 'bg-amber-500', shadow: 'shadow-[0_0_15px_rgba(245,158,11,0.5)]' },
|
|
{ name: 'ShopGoodwill', health: 99, color: 'bg-purple-500', shadow: 'shadow-[0_0_15px_rgba(168,85,247,0.5)]' }
|
|
].map((node, i) => (
|
|
<div key={i} className="group">
|
|
<div className="flex justify-between text-lg font-black mb-3">
|
|
<span>{node.name}</span>
|
|
<span className={node.health < 90 ? "text-amber-500" : "text-green-500"}>{node.health}%</span>
|
|
</div>
|
|
<div className="w-full bg-secondary/50 rounded-full h-4 overflow-hidden border border-white/5">
|
|
<motion.div
|
|
initial={{ width: 0 }}
|
|
animate={{ width: `${node.health}%` }}
|
|
transition={{ duration: 1.5, delay: 0.6 + (i * 0.15), type: "spring" as const, bounce: 0.2 }}
|
|
className={`${node.color} h-full rounded-full ${node.shadow} relative`}
|
|
>
|
|
<div className="absolute top-0 right-0 bottom-0 w-20 bg-gradient-to-r from-transparent to-white/30" />
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|