import React, { useEffect, useRef, useState } from 'react'; import Plotly from 'plotly.js'; import { X, Linkedin, Globe, MapPin, User, Briefcase, Users } from 'lucide-react'; import Button from './ui/Button'; interface SimulationGraphProps { isBuilding: boolean; societyType: string; onStartChat?: () => void; } const SimulationGraph: React.FC = ({ isBuilding, societyType, onStartChat }) => { const graphDiv = useRef(null); const [selectedProfile, setSelectedProfile] = useState<{ x: number, y: number, data: any } | null>(null); // Close popup if building starts useEffect(() => { if (isBuilding) setSelectedProfile(null); }, [isBuilding]); useEffect(() => { if (!graphDiv.current || isBuilding) return; // --- Dynamic Data Generation based on Society Type --- const safeSocietyType = typeof societyType === 'string' ? societyType : ''; const isTech = safeSocietyType.includes('Tech') || safeSocietyType.includes('Founders'); const N = isTech ? 120 : 80; const radius = isTech ? 0.18 : 0.22; const nodes = []; // Create nodes for (let i = 0; i < N; i++) { nodes.push({ x: Math.random(), y: Math.random(), connections: 0, // Mock data for the popup role: isTech ? ['Founder', 'CTO', 'Product Lead', 'VC'][Math.floor(Math.random() * 4)] : ['Journalist', 'Reader', 'Editor', 'Subscriber'][Math.floor(Math.random() * 4)], location: ['New York, USA', 'London, UK', 'Berlin, DE', 'Paris, FR'][Math.floor(Math.random() * 4)] }); } // Create edges const edgeX: (number | null)[] = []; const edgeY: (number | null)[] = []; for (let i = 0; i < N; i++) { for (let j = i + 1; j < N; j++) { const dx = nodes[i].x - nodes[j].x; const dy = nodes[i].y - nodes[j].y; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < radius) { nodes[i].connections++; nodes[j].connections++; edgeX.push(nodes[i].x, nodes[j].x, null); edgeY.push(nodes[i].y, nodes[j].y, null); } } } const nodeX = nodes.map(n => n.x); const nodeY = nodes.map(n => n.y); const nodeColor = nodes.map(n => n.connections); // --- Plotly Config --- const edgeTrace = { x: edgeX, y: edgeY, mode: 'lines', line: { width: 0.5, color: '#4b5563' }, hoverinfo: 'none', type: 'scatter' }; const nodeTrace = { x: nodeX, y: nodeY, mode: 'markers', hoverinfo: 'none', marker: { showscale: false, colorscale: isTech ? 'Electric' : 'Viridis', color: nodeColor, size: 10, line: { width: 0 } }, type: 'scatter' }; const layout = { showlegend: false, hovermode: 'closest', margin: { b: 0, l: 0, r: 0, t: 0 }, xaxis: { showgrid: false, zeroline: false, showticklabels: false, range: [-0.05, 1.05], fixedrange: true }, yaxis: { showgrid: false, zeroline: false, showticklabels: false, range: [-0.05, 1.05], fixedrange: true }, paper_bgcolor: 'rgba(0,0,0,0)', plot_bgcolor: 'rgba(0,0,0,0)', autosize: true, dragmode: false }; const config = { staticPlot: false, displayModeBar: false, responsive: true }; // @ts-ignore Plotly.newPlot(graphDiv.current, [edgeTrace, nodeTrace], layout, config).then((gd) => { // @ts-ignore gd.on('plotly_click', (data) => { const point = data.points[0]; if (point) { const nodeIndex = point.pointNumber; const nodeData = nodes[nodeIndex]; setSelectedProfile({ x: point.x, y: point.y, data: nodeData }); } }); }); }, [isBuilding, societyType]); return (
{/* Loading Overlay */} {isBuilding && (

Constructing Focus Group Graph...

)} {/* The Graph */}
{/* Profile Popup */} {selectedProfile && !isBuilding && (
{/* Header */}
{selectedProfile.data.role[0]}

{selectedProfile.data.role}

Head of Product at BrightCore

{/* Body */}
Built from
{selectedProfile.data.location}
Millennial
Mid Level
Creative & Design
{/* Footer */}
)}
); }; export default SimulationGraph;