aegisai / frontend / src / App.tsx
App.tsx
Raw
/**
 * AegisAI Main Application Component
 * Refactored with custom hooks and modular architecture
 */

import React from 'react';
import { Shield, Settings, Bell, Lock } from 'lucide-react';
import { FEATURES } from './constants';

// Components
import { VideoFeed } from './components/VideoFeed';
import { Dashboard } from './components/Dashboard/Dashboard';
import { DiagnosticOverlay } from './components/DiagnosticOverlay';

// Custom Hooks
import { useMonitoring } from './hooks/useMonitoring';

const App: React.FC = () => {
  const {
    isMonitoring,
    events,
    currentAnalysis,
    stats,
    toggleMonitoring,
    handleFrameCapture,
    backendConnected
    // clearEvents and resetStats available but not used yet
  } = useMonitoring();

  return (
    <div className="min-h-screen bg-aegis-dark text-slate-200 font-sans selection:bg-aegis-accent selection:text-black flex flex-col">
      {/* Top Navbar */}
      <header className="h-14 border-b border-slate-800 bg-aegis-dark/95 backdrop-blur flex items-center justify-between px-6 sticky top-0 z-50">
        <div className="flex items-center gap-3">
          <Shield className="text-aegis-accent" />
          <h1 className="text-lg font-bold tracking-wider text-white">
            AEGIS<span className="text-aegis-accent">AI</span>
            <span className="text-xs text-slate-500 font-normal ml-2">
              v2.5.0-beta
            </span>
          </h1>
        </div>

        <div className="flex items-center gap-4">
          <SystemStatusIndicator isOnline={true} />
          {FEATURES.ENABLE_BACKEND_API && (
            <BackendStatusIndicator connected={backendConnected} />
          )}
          <Bell className="text-slate-500 w-5 h-5 hover:text-white cursor-pointer" />
          <Settings className="text-slate-500 w-5 h-5 hover:text-white cursor-pointer" />
        </div>
      </header>

      {/* Main Layout */}
      <main className="flex-1 p-4 grid grid-cols-1 lg:grid-cols-12 gap-4 max-h-[calc(100vh-3.5rem)] overflow-hidden">
        {/* Left Column: Video Feed & Action Panel */}
        <div className="lg:col-span-4 flex flex-col gap-4">
          {/* Video Feed */}
          <div className="flex-1 min-h-[300px] relative">
            <VideoFeed
              isMonitoring={isMonitoring}
              onFrameCapture={handleFrameCapture}
            />
            
            {/* High Threat Overlay */}
            {currentAnalysis?.incident && 
             (currentAnalysis.severity === 'high' || 
              currentAnalysis.severity === 'critical') && (
              <ThreatOverlay />
            )}
          </div>

          {/* Action Response Panel */}
          <ActionResponsePanel currentAnalysis={currentAnalysis} />
        </div>

        {/* Right Column: Dashboard */}
        <div className="lg:col-span-8 h-full min-h-0">
          <Dashboard
            events={events}
            stats={stats}
            isMonitoring={isMonitoring}
            toggleMonitoring={toggleMonitoring}
            lastAnalysis={currentAnalysis}
          />
        </div>
      </main>

      {/* Diagnostic Overlay - Press 'D' to toggle */}
      <DiagnosticOverlay
        isMonitoring={isMonitoring}
        stats={stats}
        events={events}
        currentAnalysis={currentAnalysis}
        backendConnected={backendConnected}
      />
    </div>
  );
};

/**
 * System Status Indicator Component
 */
const SystemStatusIndicator: React.FC<{ isOnline: boolean }> = ({ isOnline }) => (
  <div className="flex items-center gap-2 px-3 py-1 bg-slate-900 rounded border border-slate-700">
    <div
      className={`w-2 h-2 rounded-full ${
        isOnline ? 'bg-green-500 animate-pulse' : 'bg-red-500'
      }`}
    />
    <span className="text-xs font-mono text-slate-400">
      {isOnline ? 'SYSTEM ONLINE' : 'SYSTEM OFFLINE'}
    </span>
  </div>
);

/**
 * Backend Connection Indicator
 */
const BackendStatusIndicator: React.FC<{ connected: boolean }> = ({ connected }) => (
  <div className="flex items-center gap-2 px-3 py-1 bg-slate-900 rounded border border-slate-700">
    <div
      className={`w-2 h-2 rounded-full ${
        connected ? 'bg-blue-500 animate-pulse' : 'bg-orange-500'
      }`}
    />
    <span className="text-xs font-mono text-slate-400">
      {connected ? 'BACKEND' : 'CLIENT-SIDE'}
    </span>
  </div>
);

/**
 * Threat Overlay Component
 */
const ThreatOverlay: React.FC = () => (
  <div className="absolute inset-0 border-4 border-red-500 animate-pulse pointer-events-none rounded-lg z-10 flex items-center justify-center">
    <div className="bg-red-600 text-white px-6 py-2 font-bold text-2xl uppercase tracking-[0.2em] shadow-lg animate-bounce">
      THREAT DETECTED
    </div>
  </div>
);

/**
 * Action Response Panel Component
 */
interface ActionResponsePanelProps {
  currentAnalysis: any;
}

const ActionResponsePanel: React.FC<ActionResponsePanelProps> = ({
  currentAnalysis
}) => (
  <div className="h-64 bg-aegis-panel border border-slate-700 rounded-lg p-4 overflow-y-auto">
    <h3 className="text-xs font-bold text-slate-400 uppercase tracking-wider mb-2 flex items-center gap-2">
      <Lock size={12} /> Active Response Plan
    </h3>

    {currentAnalysis?.incident ? (
      <div className="space-y-2">
        {currentAnalysis.recommended_actions.map((action: string, i: number) => (
          <ActionItem
            key={i}
            stepNumber={i + 1}
            action={action}
            isActive={i === 0}
          />
        ))}
        <div className="mt-4 text-center">
          <div className="text-[10px] text-green-500 font-mono">
            &gt; RESPONSE PROTOCOL INITIATED...
          </div>
        </div>
      </div>
    ) : (
      <div className="h-full flex items-center justify-center text-slate-600 text-xs font-mono">
        NO ACTIVE THREATS. SYSTEM STANDBY.
      </div>
    )}
  </div>
);

/**
 * Action Item Component
 */
interface ActionItemProps {
  stepNumber: number;
  action: string;
  isActive: boolean;
}

const ActionItem: React.FC<ActionItemProps> = ({
  stepNumber,
  action,
  isActive
}) => (
  <div className="flex items-center gap-3 text-sm bg-black/40 p-2 rounded border-l-2 border-aegis-accent">
    <div className="w-5 h-5 rounded-full bg-slate-800 flex items-center justify-center text-xs text-aegis-accent font-mono border border-slate-600">
      {stepNumber}
    </div>
    <span className="text-slate-300">{action}</span>
    {isActive ? (
      <span className="ml-auto text-[10px] bg-blue-500/20 text-blue-400 px-1 rounded">
        EXEC
      </span>
    ) : (
      <span className="ml-auto text-[10px] text-gray-600">PEND</span>
    )}
  </div>
);

export default App;