'use client'; import { useState, useEffect, useRef, useCallback, memo } from 'react'; import { Play, Pause, RotateCcw, Sliders, Zap } from 'lucide-react'; // Use environment variable or relative URL for production const API_URL = process.env.NEXT_PUBLIC_API_URL || ''; interface Transaction { id: number; amount: number; merchant: string; category: string; is_fraud: number; prediction: string; final_score: number; classical_score: number; quantum_score: number; quantum_details: { vqc: number; qaoa: number; qnn: number; }; } interface Metrics { total: number; flagged: number; actual_fraud: number; accuracy: number; precision: number; recall: number; f1: number; tp: number; fp: number; tn: number; fn: number; } interface SimulationEngineProps { onTransactionUpdate: (transaction: Transaction, metrics: Metrics) => void; onRunningChange: (isRunning: boolean) => void; onThresholdChange?: (threshold: number) => void; } // Completely isolated simulation engine const SimulationEngine = memo(function SimulationEngine({ onTransactionUpdate, onRunningChange, onThresholdChange }: SimulationEngineProps) { const [isRunning, setIsRunning] = useState(false); const [speed, setSpeed] = useState(1000); const [threshold, setThreshold] = useState(0.5); const [showSettings, setShowSettings] = useState(false); // All refs to prevent any re-render issues const intervalRef = useRef(null); const isRunningRef = useRef(false); const speedRef = useRef(speed); const thresholdRef = useRef(threshold); const isMountedRef = useRef(true); // Stable callback refs const onTransactionUpdateRef = useRef(onTransactionUpdate); const onRunningChangeRef = useRef(onRunningChange); useEffect(() => { onTransactionUpdateRef.current = onTransactionUpdate; onRunningChangeRef.current = onRunningChange; }, [onTransactionUpdate, onRunningChange]); useEffect(() => { speedRef.current = speed; }, [speed]); useEffect(() => { thresholdRef.current = threshold; onThresholdChange?.(threshold); }, [threshold, onThresholdChange]); useEffect(() => { isMountedRef.current = true; return () => { isMountedRef.current = false; if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; } }; }, []); const processTransaction = useCallback(async () => { if (!isMountedRef.current) return; try { const response = await fetch(`${API_URL}/api/process-random?threshold=${thresholdRef.current}`); if (response.ok && isMountedRef.current) { const data = await response.json(); onTransactionUpdateRef.current(data.transaction, data.metrics); } } catch (error) { console.error('Failed to process transaction:', error); } }, []); const clearIntervalSafely = useCallback(() => { if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; } }, []); const start = useCallback(() => { clearIntervalSafely(); isRunningRef.current = true; setIsRunning(true); onRunningChangeRef.current(true); // Process first one immediately processTransaction(); // Start interval intervalRef.current = setInterval(() => { if (isRunningRef.current && isMountedRef.current) { processTransaction(); } }, speedRef.current); }, [processTransaction, clearIntervalSafely]); const stop = useCallback(() => { isRunningRef.current = false; setIsRunning(false); onRunningChangeRef.current(false); clearIntervalSafely(); }, [clearIntervalSafely]); const reset = useCallback(async () => { stop(); try { await fetch(`${API_URL}/api/reset`, { method: 'POST' }); } catch (error) { console.error('Failed to reset:', error); } }, [stop]); const handleSpeedChange = useCallback((newSpeed: number) => { setSpeed(newSpeed); speedRef.current = newSpeed; if (isRunningRef.current) { clearIntervalSafely(); intervalRef.current = setInterval(() => { if (isRunningRef.current && isMountedRef.current) { processTransaction(); } }, newSpeed); } }, [processTransaction, clearIntervalSafely]); return (
Speed:
{isRunning ? 'Running' : 'Stopped'}
{/* Settings Panel */} {showSettings && (
{/* Threshold Control */}
0.6 ? 'text-green-600' : 'text-amber-600' }`}> {(threshold * 100).toFixed(0)}%
setThreshold(Number(e.target.value))} className="w-full h-2 bg-gradient-to-r from-green-400 via-amber-400 to-red-400 rounded-lg appearance-none cursor-pointer" />
More Sensitive Less Sensitive

{threshold < 0.4 ? '⚠️ Low threshold: More fraud flagged, higher false positives' : threshold > 0.6 ? '✅ High threshold: Fewer flags, may miss some fraud' : '⚖️ Balanced threshold: Good precision/recall trade-off'}

{/* Model Weights Info */}
Classical (XGBoost)
80%
Quantum Ensemble
20%

⚛️ VQC (40%) + QAOA (30%) + QNN (30%)

)}
); }); export default SimulationEngine;