import React, { useEffect, useRef } from 'react';
import {
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer
} from 'recharts';
import type { SecurityEvent, SystemStats } from '../../types';
import { Activity, AlertTriangle, Eye, Cpu, Terminal } from 'lucide-react';
interface DashboardProps {
events: SecurityEvent[];
stats: SystemStats;
isMonitoring: boolean;
toggleMonitoring: () => void;
lastAnalysis: SecurityEvent | null;
}
export const Dashboard: React.FC<DashboardProps> = ({
events,
stats,
isMonitoring,
toggleMonitoring,
lastAnalysis
}) => {
const scrollRef = useRef<HTMLDivElement>(null);
// Auto-scroll terminal
useEffect(() => {
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
}, [events]);
const chartData = events.slice(-10).map((e) => ({
time: new Date(e.timestamp).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}),
confidence: e.confidence,
severity:
e.severity === 'high'
? 100
: e.severity === 'medium'
? 60
: 20
}));
const getSeverityColor = (severity: string) => {
switch (severity) {
case 'high':
return 'text-red-500';
case 'medium':
return 'text-orange-400';
case 'low':
return 'text-blue-400';
default:
return 'text-gray-400';
}
};
const getSeverityBg = (severity: string) => {
switch (severity) {
case 'high':
return 'bg-red-500/20 border-red-500';
case 'medium':
return 'bg-orange-500/20 border-orange-500';
case 'low':
return 'bg-blue-500/20 border-blue-500';
default:
return 'bg-gray-800 border-gray-700';
}
};
return (
<div className="flex flex-col h-full gap-4">
{/* HEADER STATS */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="bg-aegis-panel border border-slate-700 rounded-lg p-4 flex items-center gap-4 shadow-lg">
<div className="p-3 bg-blue-500/10 rounded-full text-blue-400">
<Eye size={24} />
</div>
<div>
<p className="text-slate-400 text-xs uppercase tracking-wider">
Scans Performed
</p>
<p className="text-2xl font-mono font-bold text-white">
{stats.scansPerformed}
</p>
</div>
</div>
<div className="bg-aegis-panel border border-slate-700 rounded-lg p-4 flex items-center gap-4 shadow-lg">
<div
className={`p-3 rounded-full ${
stats.incidentsDetected > 0
? 'bg-red-500/10 text-red-500'
: 'bg-green-500/10 text-green-500'
}`}
>
<AlertTriangle size={24} />
</div>
<div>
<p className="text-slate-400 text-xs uppercase tracking-wider">
Incidents
</p>
<p className="text-2xl font-mono font-bold text-white">
{stats.incidentsDetected}
</p>
</div>
</div>
<div className="bg-aegis-panel border border-slate-700 rounded-lg p-4 flex items-center gap-4 shadow-lg">
<div className="p-3 bg-purple-500/10 rounded-full text-purple-400">
<Cpu size={24} />
</div>
<div>
<p className="text-slate-400 text-xs uppercase tracking-wider">
System Load
</p>
<div className="flex items-end gap-2">
<p className="text-2xl font-mono font-bold text-white">
{stats.cpuUsage}%
</p>
<div className="h-1.5 w-16 bg-gray-700 rounded-full mb-2">
<div
className="h-full bg-purple-500 rounded-full transition-all duration-500"
style={{ width: `${stats.cpuUsage}%` }}
/>
</div>
</div>
</div>
</div>
<div className="bg-aegis-panel border border-slate-700 rounded-lg p-4 shadow-lg">
<button
onClick={toggleMonitoring}
className={`w-full h-full rounded flex flex-col items-center justify-center transition-all ${
isMonitoring
? 'bg-red-900/20 hover:bg-red-900/40 border border-red-500/50'
: 'bg-green-900/20 hover:bg-green-900/40 border border-green-500/50'
}`}
>
<div
className={`text-sm font-bold tracking-widest uppercase mb-1 ${
isMonitoring ? 'text-red-400' : 'text-green-400'
}`}
>
{isMonitoring ? 'STOP SURVEILLANCE' : 'ACTIVATE AEGIS'}
</div>
<div
className={`w-3 h-3 rounded-full ${
isMonitoring
? 'bg-red-500 animate-pulse'
: 'bg-green-500'
}`}
/>
</button>
</div>
</div>
{/* MAIN GRID */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 flex-1 min-h-0">
{/* LEFT */}
<div className="lg:col-span-2 flex flex-col gap-4">
<div className="bg-aegis-panel border border-slate-700 rounded-lg p-4 flex-1 shadow-lg flex flex-col min-w-0">
<h3 className="text-aegis-accent font-mono text-sm uppercase tracking-wider mb-4 flex items-center gap-2">
<Activity size={16} /> Real-time Threat Analysis
</h3>
<div className="w-full h-[250px] min-w-0">
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={chartData}>
<defs>
<linearGradient
id="colorConf"
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="5%"
stopColor="#38bdf8"
stopOpacity={0.3}
/>
<stop
offset="95%"
stopColor="#38bdf8"
stopOpacity={0}
/>
</linearGradient>
</defs>
<CartesianGrid
strokeDasharray="3 3"
stroke="#334155"
/>
<XAxis
dataKey="time"
stroke="#94a3b8"
fontSize={12}
/>
<YAxis
stroke="#94a3b8"
fontSize={12}
domain={[0, 100]}
/>
<Tooltip
contentStyle={{
backgroundColor: '#0f172a',
borderColor: '#334155',
color: '#f1f5f9'
}}
/>
<Area
type="monotone"
dataKey="confidence"
stroke="#38bdf8"
fill="url(#colorConf)"
/>
</AreaChart>
</ResponsiveContainer>
</div>
{/* LATEST */}
<div className="mt-4 border-t border-slate-700 pt-4 flex-1">
<h4 className="text-gray-400 text-xs uppercase mb-2">
Latest Inference
</h4>
{lastAnalysis ? (
<div
className={`border p-4 rounded bg-opacity-10 ${getSeverityBg(
lastAnalysis.severity
)}`}
>
<div className="flex justify-between mb-2">
<span
className={`font-mono text-lg font-bold uppercase ${getSeverityColor(
lastAnalysis.severity
)}`}
>
{lastAnalysis.incident
? '⚠ THREAT DETECTED'
: '✓ SECURE'}
</span>
<span className="font-mono text-xs text-gray-400">
{new Date(
lastAnalysis.timestamp
).toLocaleTimeString()}
</span>
</div>
<div className="grid grid-cols-2 gap-4 mb-3">
<div>
<p className="text-gray-500 text-xs uppercase">
Type
</p>
<p className="text-white font-medium">
{lastAnalysis.type}
</p>
</div>
<div>
<p className="text-gray-500 text-xs uppercase">
Confidence
</p>
<p className="text-white font-medium">
{lastAnalysis.confidence}%
</p>
</div>
</div>
<p className="text-slate-300 text-sm italic">
"{lastAnalysis.reasoning}"
</p>
</div>
) : (
<div className="text-center py-8 text-gray-600 font-mono text-sm">
Waiting for video stream analysis...
</div>
)}
</div>
</div>
</div>
{/* RIGHT TERMINAL */}
<div className="bg-black border border-slate-700 rounded-lg p-2 shadow-lg flex flex-col font-mono text-xs overflow-hidden">
<div className="flex justify-between px-2 py-2 border-b border-gray-800">
<span className="flex gap-2 text-gray-400">
<Terminal size={14} /> SYSTEM_LOG
</span>
<div className="flex gap-1">
<div className="w-2 h-2 rounded-full bg-red-500" />
<div className="w-2 h-2 rounded-full bg-yellow-500" />
<div className="w-2 h-2 rounded-full bg-green-500" />
</div>
</div>
<div
ref={scrollRef}
className="flex-1 overflow-y-auto space-y-2 p-2"
>
{events.map((e) => (
<div
key={e.id}
className="border-l-2 border-slate-700 pl-2"
>
<span className="text-gray-500">
[{new Date(e.timestamp).toLocaleTimeString()}]
</span>{' '}
<span
className={
e.incident
? 'text-red-400'
: 'text-green-400'
}
>
{e.incident ? 'ALRT' : 'INFO'}
</span>{' '}
<span className="text-blue-300">
@{e.type}
</span>
<p className="text-gray-300">
{e.reasoning}
</p>
</div>
))}
</div>
</div>
</div>
</div>
);
};
export default Dashboard;