import { useEffect, useState } from 'react'; import { Empty, Card, Button, Statistic, Row, Col, Typography, Space, Badge, Collapse, Checkbox, Radio, } from 'antd'; import { SwapOutlined, CheckCircleOutlined, ReloadOutlined, UnorderedListOutlined, TableOutlined, } from '@ant-design/icons'; import type { AttributeDAG, CrossoverPair, ExpertMode } from '../types'; import { useAttributeCrossover } from '../hooks/useAttributeCrossover'; import { CrossoverCard } from './crossover/CrossoverCard'; import { CrossoverMatrix } from './crossover/CrossoverMatrix'; import { CrossoverPreview } from './crossover/CrossoverPreview'; const { Text } = Typography; interface CrossoverPanelProps { pathAResult: AttributeDAG | null; pathBResult: AttributeDAG | null; isDark: boolean; expertMode: ExpertMode; onExpertModeChange: (mode: ExpertMode) => void; onCrossoverReady?: (selectedPairs: CrossoverPair[]) => void; } type ViewMode = 'list' | 'matrix'; export function CrossoverPanel({ pathAResult, pathBResult, isDark, expertMode, onExpertModeChange, onCrossoverReady, }: CrossoverPanelProps) { const [viewMode, setViewMode] = useState('list'); const { pairs, selectedPairs, pairsByType, crossTypeStats, applyPairs, togglePairSelection, selectPairsByType, selectAll, clearPairs, } = useAttributeCrossover(); // Generate pairs when both results are available useEffect(() => { if (pathAResult && pathBResult) { applyPairs(pathAResult, pathBResult); } else { clearPairs(); } }, [pathAResult, pathBResult, applyPairs, clearPairs]); // Notify parent when selection changes useEffect(() => { onCrossoverReady?.(selectedPairs); }, [selectedPairs, onCrossoverReady]); // Render when no data if (!pathAResult || !pathBResult) { return (
Complete both Path A and Path B analysis first {!pathAResult && !pathBResult ? 'Neither path has been analyzed' : !pathAResult ? 'Path A has not been analyzed' : 'Path B has not been analyzed'} } />
); } // Generate cross type labels dynamically const getCrossTypeLabel = (crossType: string): string => { if (crossType.startsWith('same-')) { const category = crossType.replace('same-', ''); return `Same Category: ${category}`; } if (crossType.startsWith('cross-')) { const parts = crossType.replace('cross-', '').split('-'); if (parts.length >= 2) { return `Cross: ${parts[0]} × ${parts.slice(1).join('-')}`; } } return crossType; }; const renderListView = () => { const crossTypes = Object.keys(pairsByType); if (crossTypes.length === 0) { return ; } const collapseItems = crossTypes.map(type => { const typePairs = pairsByType[type]; const stats = crossTypeStats[type]; const label = getCrossTypeLabel(type); return { key: type, label: (
0 && stats.selected < stats.total} onClick={(e) => e.stopPropagation()} onChange={(e) => selectPairsByType(type, e.target.checked)} /> {label} 0 ? '#52c41a' : '#d9d9d9', }} />
), children: (
{typePairs.map(pair => ( ))}
), }; }); return ( t.startsWith('same-'))} /> ); }; const renderMatrixView = () => { return ( ); }; return (
{/* Statistics Header */} } /> } valueStyle={{ color: '#52c41a' }} /> {/* Selection Preview */} {/* Expert Mode Selection */} Expert Team Mode onExpertModeChange(e.target.value)} buttonStyle="solid" > Shared Experts Independent Experts {expertMode === 'shared' ? 'Both paths use the same expert team for crossover transformation' : 'Each path uses its own expert team, combined for crossover'} {/* Actions */}
setViewMode(e.target.value)} buttonStyle="solid" size="small" > List Matrix
{/* Content */}
{viewMode === 'list' ? renderListView() : renderMatrixView()}
); }