import React, { useState, useEffect, useRef } from 'react'; import { Layout } from './components/Layout'; import { Phase, AppState, Phase1Data, Phase2Data, Phase3Data, Phase4Data, Phase6Data, Phase7Data, Phase8Data, Phase9Data, Language, Theme, ProjectHistoryItem } from './types'; import * as Gemini from './geminiService'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { AlertTriangle, ArrowRight, ArrowLeft, Check, Database, Globe, Search, ShieldAlert, Cpu, Building2, UserCircle, Briefcase, Zap, Terminal, Target, Crosshair, Loader2, Plus, X, Download, ShieldCheck, Image as ImageIcon, Copy, Sparkles, Upload, CheckCircle, PenTool, Eraser, Undo, Save, RefreshCw, Pencil, Trash2, LayoutTemplate, TrendingUp, Shield, Languages, Clock, History, FileText } from 'lucide-react'; const TRANSLATIONS = { en: { historyTitle: 'Recent Sessions', loadBtn: 'Load', noSessions: 'No history found.', phase1: 'Product & Constraints', phase2: 'ICP Discovery', phase3: 'Whale Hunting', phase4: 'Strategy Matrix', phase5: 'Asset Generation', phase6: 'Sales Enablement', phase7: 'Vertical Landing Page', phase8: 'Business Case (ROI)', phase9: 'Feature-to-Value Translator', initTitle: 'Initialize New Product Sequence', inputLabel: 'Product URL or Technical Specification', inputPlaceholder: 'Paste raw technical data, brochure text, or product URL here...', startBtn: 'Start Analysis', backBtn: 'Back', processing: 'Processing...', features: 'Detected Features', constraints: 'Hard Constraints', conflictTitle: 'Portfolio Conflict Detected', conflictPass: 'Portfolio Conflict Check Passed: Unique Value Proposition Identified.', confirmICP: 'Confirm & Proceed to ICP', targetId: 'Target Identification', dataProxies: 'Data Proxies (Digital Footprints)', method: 'Method', huntWhales: 'Lock Targets & Hunt Whales', region: 'Region: DACH (Germany, Austria, Switzerland)', whales: 'Key Accounts (Whales)', roles: 'Buying Center Roles', confirmStrat: 'Confirm Accounts & Strategize', stratAngles: 'Strategic Angles', segment: 'Segment', pain: 'Pain Point', angle: 'Our Angle', diff: 'Differentiation', writeCopy: 'Generate Assets', genAssets: 'Generated Strategy Report & Assets', complete: 'Process Complete. Strategy locked.', restart: 'Start New Session', addPlaceholder: 'Add item...', download: 'Download Full Report (.md)', downloadAsset: 'Download Asset', translateBtn: 'Translate Report to English', downloadEn: 'Download English Report (.md)', translating: 'Translating...', toPhase6: 'Proceed to Sales Enablement (Phase 6)', toPhase7: 'Proceed to Landing Pages (Phase 7)', toPhase8: 'Proceed to Business Case (Phase 8)', toPhase9: 'Proceed to Feature-to-Value (Phase 9)', phase6Title: 'Sales Enablement & Visuals', phase7Title: 'Vertical Landing Pages', phase8Title: 'Business Case Builder', phase9Title: 'Feature-to-Value Translator', battlecards: 'Kill-Critique Battlecards', visuals: 'Visual Briefings (Midjourney Prompts)', objection: 'Objection', response: 'Response Script', copyPrompt: 'Copy Prompt', copied: 'Copied!', genImage: 'Generate Concept', editImage: 'Edit & Iterate', regenerateSketch: 'Regenerate with Sketch', cancelEdit: 'Cancel Edit', generating: 'Generating...', uploadImage: 'Product Reference Images', uploadHint: 'Upload multiple photos (Front, Side, Detail) for better 3D understanding.', imageUploaded: 'Reference Images', canvasClear: 'Clear', canvasMode: 'Sketch Mode', addName: 'Name...', addRationale: 'Rationale...', addTarget: 'Target criteria...', addMethod: 'Method...', addAccount: 'Account name...', addRole: 'Job title...', loading: [ "Initializing quantum analysis engines...", "Parsing raw technical specifications...", "Simulating physical constraints & boundary conditions...", "Cross-referencing internal product matrix...", "Detecting potential portfolio conflicts...", "Synthesizing GTM parameters..." ] }, de: { historyTitle: 'Letzte Sitzungen', loadBtn: 'Laden', noSessions: 'Keine Historie gefunden.', phase1: 'Produkt & Constraints', phase2: 'ICP Entdeckung', phase3: 'Whale Hunting', phase4: 'Strategie-Matrix', phase5: 'Asset Generierung', phase6: 'Sales Enablement', phase7: 'Vertical Landing Page', phase8: 'Business Case (ROI)', phase9: 'Feature-to-Value Translator', initTitle: 'Neue Produktsequenz initialisieren', inputLabel: 'Produkt-URL oder Technische Spezifikation', inputPlaceholder: 'Füge hier rohe technische Daten, Broschürentexte oder Produkt-URL ein...', startBtn: 'Analyse starten', backBtn: 'Zurück', processing: 'Verarbeite...', features: 'Erkannte Features', constraints: 'Harte Constraints', conflictTitle: 'Portfolio-Konflikt erkannt', conflictPass: 'Portfolio-Konfliktprüfung bestanden: Alleinstellungsmerkmal identifiziert.', confirmICP: 'Bestätigen & weiter zu ICP', targetId: 'Zielgruppen-Identifikation', dataProxies: 'Data Proxies (Digitale Spuren)', method: 'Methode', huntWhales: 'Ziele fixieren & Whales jagen', region: 'Region: DACH (Deutschland, Österreich, Schweiz)', whales: 'Key Accounts (Whales)', roles: 'Buying Center Rollen', confirmStrat: 'Accounts bestätigen & Strategie', stratAngles: 'Strategische Angles', segment: 'Segment', pain: 'Pain Point', angle: 'Unser Angle', diff: 'Differenzierung', writeCopy: 'Report & Assets generieren', genAssets: 'Generierter Strategie-Report & Assets', complete: 'Prozess abgeschlossen. Strategie fixiert.', restart: 'Neue Session starten', addPlaceholder: 'Punkt hinzufügen...', download: 'Gesamtbericht herunterladen (.md)', downloadAsset: 'Bild speichern', translateBtn: 'Bericht ins Englische übersetzen', downloadEn: 'Englischen Bericht herunterladen (.md)', translating: 'Übersetze...', toPhase6: 'Weiter zu Sales Enablement (Phase 6)', toPhase7: 'Weiter zu Landing Pages (Phase 7)', toPhase8: 'Weiter zu Business Case (Phase 8)', toPhase9: 'Weiter zu Feature-to-Value (Phase 9)', phase6Title: 'Sales Enablement & Visuals', phase7Title: 'Vertical Landing Pages', phase8Title: 'Business Case Builder', phase9Title: 'Feature-to-Value Translator', battlecards: 'Kill-Critique Battlecards', visuals: 'Visual Briefings (Midjourney Prompts)', objection: 'Einwand', response: 'Antwort-Skript', copyPrompt: 'Prompt kopieren', copied: 'Kopiert!', genImage: 'Konzept erstellen', editImage: 'Zeichnen & Iterieren', regenerateSketch: 'Mit Skizze neu generieren', cancelEdit: 'Abbrechen', generating: 'Generiere...', uploadImage: 'Produkt-Referenzbilder', uploadHint: 'Lade mehrere Fotos hoch (Front, Seite, Detail), um das 3D-Verständnis zu verbessern.', imageUploaded: 'Referenzbilder', canvasClear: 'Leeren', canvasMode: 'Zeichenmodus', addName: 'Name...', addRationale: 'Begründung...', addTarget: 'Zielkriterium...', addMethod: 'Suchmethode...', addAccount: 'Firmenname...', addRole: 'Jobtitel...', loading: [ "Initialisiere Quanten-Analyse-Engines...", "Analysiere technische Spezifikationen...", "Simuliere physikalische Constraints...", "Prüfe interne Produkt-Matrix...", "Erkenne potenzielle Portfolio-Konflikte...", "Synthetisiere GTM-Parameter..." ] } }; const App: React.FC = () => { const [state, setState] = useState({ currentPhase: Phase.Input, isLoading: false, history: [], productInput: '', productImages: [], language: 'light', // temporary init, fix in useEffect theme: 'light' // Default to light }); // Fix initial state type matching const [language, setLanguage] = useState('de'); // Default to German per prompt const [theme, setTheme] = useState('light'); const [error, setError] = useState(null); const [loadingMessage, setLoadingMessage] = useState(""); const [isTranslating, setIsTranslating] = useState(false); // Session Management const [sessions, setSessions] = useState([]); // Local state for adding new items (Human in the Loop inputs) // Phase 1 const [newFeatureInput, setNewFeatureInput] = useState(""); const [newConstraintInput, setNewConstraintInput] = useState(""); // Phase 2 const [newICPName, setNewICPName] = useState(""); const [newICPRationale, setNewICPRationale] = useState(""); const [newProxyTarget, setNewProxyTarget] = useState(""); const [newProxyMethod, setNewProxyMethod] = useState(""); // Phase 3 // Changed to use a map to track input per group index const [newAccountInputs, setNewAccountInputs] = useState>({}); const [newRoleInput, setNewRoleInput] = useState(""); const [copiedPromptIndex, setCopiedPromptIndex] = useState(null); // Phase 6 Image Generation State const [generatingImages, setGeneratingImages] = useState>({}); const [generatedImages, setGeneratedImages] = useState>({}); // Phase 6 Editing State const [editingIndex, setEditingIndex] = useState(null); const canvasRef = useRef(null); const [isDrawing, setIsDrawing] = useState(false); const [brushColor, setBrushColor] = useState('#ef4444'); // Red for annotations const [brushSize, setBrushSize] = useState(4); const labels = TRANSLATIONS[language]; // Apply theme to body useEffect(() => { if (theme === 'dark') { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } }, [theme]); // Load Sessions on Mount useEffect(() => { const fetchSessions = async () => { try { const res = await Gemini.listSessions(); setSessions(res.projects); } catch (e) { console.error("Failed to load sessions", e); } }; fetchSessions(); }, []); useEffect(() => { if (!state.isLoading && !isTranslating) return; const messages = labels.loading; let i = 0; setLoadingMessage(messages[0]); const interval = setInterval(() => { i = (i + 1) % messages.length; setLoadingMessage(messages[i]); }, 2500); return () => clearInterval(interval); }, [state.isLoading, isTranslating, labels.loading]); // Canvas Initialization for Editing useEffect(() => { if (editingIndex !== null && canvasRef.current && generatedImages[editingIndex]) { const canvas = canvasRef.current; const ctx = canvas.getContext('2d'); const img = new Image(); img.crossOrigin = "anonymous"; img.onload = () => { canvas.width = img.width; canvas.height = img.height; ctx?.drawImage(img, 0, 0); }; img.src = generatedImages[editingIndex]; } }, [editingIndex, generatedImages]); const toggleTheme = () => { setTheme(prev => prev === 'light' ? 'dark' : 'light'); }; const goBack = () => { if (state.currentPhase > Phase.Input) { setState(s => ({ ...s, currentPhase: s.currentPhase - 1 })); } }; // Determine the highest phase the user has completed data for. // This allows navigation back and forth. const getMaxAllowedPhase = (): Phase => { if (state.phase9Result) return Phase.TechTranslator; if (state.phase8Result) return Phase.BusinessCase; if (state.phase7Result) return Phase.LandingPage; if (state.phase6Result) return Phase.SalesEnablement; if (state.phase5Result) return Phase.AssetGeneration; if (state.phase4Result) return Phase.Strategy; if (state.phase3Result) return Phase.WhaleHunting; if (state.phase2Result) return Phase.ICPDiscovery; if (state.phase1Result) return Phase.ProductAnalysis; return Phase.Input; }; const handlePhaseSelect = (phase: Phase) => { if (state.isLoading) return; // Prevent navigation while generating setState(s => ({ ...s, currentPhase: phase })); }; const handleLoadSession = async (projectId: string) => { setLoadingMessage("Loading Session..."); setState(s => ({ ...s, isLoading: true })); try { const data = await Gemini.loadSession(projectId); const phases = data.phases || {}; console.log("Raw Loaded Phases from DB:", phases); // Helper to safely parse potentially MULTIPLE times stringified JSON const parsePhaseData = (phaseData: any) => { if (!phaseData) return undefined; let parsed = phaseData; try { // Versuch 1 if (typeof parsed === 'string') parsed = JSON.parse(parsed); // Versuch 2 (falls double encoded) if (typeof parsed === 'string') parsed = JSON.parse(parsed); // Versuch 3 (extrem) if (typeof parsed === 'string') parsed = JSON.parse(parsed); } catch (e) { console.warn("Failed to parse phase data", e, phaseData); return null; } return parsed; }; const p1 = parsePhaseData(phases.phase1_result); const p2 = parsePhaseData(phases.phase2_result); const p3 = parsePhaseData(phases.phase3_result); const p4 = parsePhaseData(phases.phase4_result); const p5 = parsePhaseData(phases.phase5_result); const p6 = parsePhaseData(phases.phase6_result); const p7 = parsePhaseData(phases.phase7_result); const p8 = parsePhaseData(phases.phase8_result); const p9 = parsePhaseData(phases.phase9_result); console.log("Parsed Phase 2:", p2); // Debug // Determine the highest available phase to jump to let targetPhase = Phase.ProductAnalysis; if (p9) targetPhase = Phase.TechTranslator; else if (p8) targetPhase = Phase.BusinessCase; else if (p7) targetPhase = Phase.LandingPage; else if (p6) targetPhase = Phase.SalesEnablement; else if (p5) targetPhase = Phase.AssetGeneration; else if (p4) targetPhase = Phase.Strategy; else if (p3) targetPhase = Phase.WhaleHunting; else if (p2) targetPhase = Phase.ICPDiscovery; setState(s => ({ ...s, isLoading: false, currentPhase: targetPhase, projectId: projectId, productInput: p1?.rawAnalysis || "", phase1Result: p1, phase2Result: p2, phase3Result: p3, phase4Result: p4, phase5Result: p5, phase6Result: p6, phase7Result: p7, phase8Result: p8, phase9Result: p9, })); } catch (e: any) { setError("Failed to load session: " + e.message); setState(s => ({ ...s, isLoading: false })); } }; const handleDeleteSession = async (e: React.MouseEvent, projectId: string) => { e.stopPropagation(); if (!window.confirm("Delete this session permanently?")) return; try { await Gemini.deleteSession(projectId); setSessions(prev => prev.filter(s => s.id !== projectId)); } catch (e: any) { setError("Failed to delete session: " + e.message); } }; const handleLoadMarkdown = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = (event) => { const content = event.target?.result as string; if (content) { setState(s => ({ ...s, currentPhase: Phase.AssetGeneration, phase5Result: { report: content } })); } }; reader.readAsText(file); }; // --- Asset Generation Helpers --- const generateFullReportMarkdown = (): string => { if (!state.phase5Result || !state.phase5Result.report) return ""; let fullReport = state.phase5Result.report; if (state.phase6Result) { fullReport += `\n\n# SALES ENABLEMENT & VISUALS (PHASE 6)\n\n`; fullReport += `## Kill-Critique Battlecards\n\n`; state.phase6Result.battlecards.forEach(card => { fullReport += `### Persona: ${card.persona}\n`; fullReport += `> **Objection:** "${card.objection}"\n\n`; fullReport += `**Response:** ${card.responseScript}\n\n---\n\n`; }); fullReport += `## Visual Briefings (Prompts)\n\n`; state.phase6Result.visualPrompts.forEach(prompt => { fullReport += `### ${prompt.title}\n`; fullReport += `*Context: ${prompt.context}*\n\n`; fullReport += `\ \ ${prompt.prompt}\n\ \ `; }); } if (state.phase7Result) { fullReport += `\n\n# VERTICAL LANDING PAGES (PHASE 7)\n\n`; state.phase7Result.landingPages.forEach(lp => { fullReport += `## ${lp.industry}\n`; fullReport += `**Headline:** ${lp.headline}\n\n`; fullReport += `**Subline:** ${lp.subline}\n\n`; fullReport += `**Benefits:**\n`; lp.bullets.forEach(b => fullReport += `- ${b}\n`); fullReport += `\n**CTA:** ${lp.cta}\n\n---\n\n`; }); } if (state.phase8Result) { fullReport += `\n\n# BUSINESS CASE & ROI (PHASE 8)\n\n`; state.phase8Result.businessCases.forEach(bc => { fullReport += `## ${bc.industry}\n`; fullReport += `**Cost Driver:** ${bc.costDriver}\n\n`; fullReport += `**Efficiency Gain:** ${bc.efficiencyGain}\n\n`; fullReport += `**Risk Argument:** ${bc.riskArgument}\n\n---\n\n`; }); } if (state.phase9Result) { fullReport += `\n\n# FEATURE-TO-VALUE TRANSLATOR (PHASE 9)\n\n`; fullReport += `| Feature | The Story (Benefit) | Headline |\n`; fullReport += `| :--- | :--- | :--- |\n`; state.phase9Result.techTranslations.forEach(tt => { fullReport += `| ${tt.feature} | ${tt.story} | ${tt.headline} |\n`; }); } return fullReport; }; const downloadReport = (content?: string, filenamePrefix: string = "") => { const reportContent = content || generateFullReportMarkdown(); if (!reportContent) return; const element = document.createElement("a"); const file = new Blob([reportContent], {type: 'text/markdown'}); element.href = URL.createObjectURL(file); element.download = `roboplanet-gtm-strategy-${filenamePrefix}${new Date().toISOString().slice(0,10)}.md`; document.body.appendChild(element); element.click(); document.body.removeChild(element); }; const handleTranslateReport = async () => { const fullReport = generateFullReportMarkdown(); if (!fullReport) return; setIsTranslating(true); setError(null); try { const translated = await Gemini.translateReportToEnglish(fullReport); setState(s => ({ ...s, translatedReport: translated })); } catch (e: any) { setError("Translation failed: " + e.message); } finally { setIsTranslating(false); } }; const downloadAsset = (dataUrl: string, index: number) => { const element = document.createElement("a"); element.href = dataUrl; element.download = `roboplanet-visual-${index + 1}.png`; document.body.appendChild(element); element.click(); document.body.removeChild(element); }; const copyToClipboard = (text: string, index: number) => { navigator.clipboard.writeText(text); setCopiedPromptIndex(index); setTimeout(() => setCopiedPromptIndex(null), 2000); }; // --- Image Generation Handlers --- const handleGenerateImage = async (prompt: string, index: number, overrideReference?: string) => { setGeneratingImages(prev => ({ ...prev, [index]: true })); try { // If sketching, use only the sketch as the strong reference // If not sketching, use the array of uploaded product images const refImages = overrideReference ? [overrideReference] : state.productImages; const imageUrl = await Gemini.generateConceptImage(prompt, refImages, state.projectId); setGeneratedImages(prev => ({ ...prev, [index]: imageUrl })); // If we were editing, close edit mode if (editingIndex === index) { setEditingIndex(null); } } catch (e: any) { console.error("Failed to generate image", e); setError("Image generation failed: " + e.message); } finally { setGeneratingImages(prev => ({ ...prev, [index]: false })); } }; // ... (Upload handlers remain same) ... // --- Handlers --- const handlePhase1Submit = async () => { if (!state.productInput.trim()) return; setState(s => ({ ...s, isLoading: true })); setError(null); try { const result = await Gemini.analyzeProduct(state.productInput, language); setState(s => ({ ...s, currentPhase: Phase.ProductAnalysis, phase1Result: result, isLoading: false, projectId: result.projectId })); } catch (e: any) { setError(e.message || "Analysis failed"); setState(s => ({ ...s, isLoading: false })); } }; const handlePhase2Submit = async () => { if (!state.phase1Result || !state.projectId) return; setState(s => ({ ...s, isLoading: true })); try { const result = await Gemini.discoverICPs(state.phase1Result, language, state.projectId); setState(s => ({ ...s, currentPhase: Phase.ICPDiscovery, phase2Result: result, isLoading: false })); } catch (e: any) { setError(e.message); setState(s => ({ ...s, isLoading: false })); } }; const handlePhase3Submit = async () => { if (!state.phase2Result || !state.projectId) return; setState(s => ({ ...s, isLoading: true })); try { const result = await Gemini.huntWhales(state.phase2Result, language, state.projectId); setState(s => ({ ...s, currentPhase: Phase.WhaleHunting, phase3Result: result, isLoading: false })); } catch (e: any) { setError(e.message); setState(s => ({ ...s, isLoading: false })); } }; const handlePhase4Submit = async () => { if (!state.phase3Result || !state.phase1Result || !state.projectId) return; setState(s => ({ ...s, isLoading: true })); try { const result = await Gemini.developStrategy(state.phase3Result, state.phase1Result, language, state.projectId); setState(s => ({ ...s, currentPhase: Phase.Strategy, phase4Result: result, isLoading: false })); } catch (e: any) { setError(e.message); setState(s => ({ ...s, isLoading: false })); } }; const handlePhase5Submit = async () => { // Requires all previous data for the final report if (!state.phase4Result || !state.phase3Result || !state.phase2Result || !state.phase1Result || !state.projectId) return; setState(s => ({ ...s, isLoading: true })); try { const result = await Gemini.generateAssets( state.phase4Result, state.phase3Result, state.phase2Result, state.phase1Result, language, state.projectId ); setState(s => ({ ...s, currentPhase: Phase.AssetGeneration, phase5Result: result, isLoading: false })); } catch (e: any) { setError(e.message); setState(s => ({ ...s, isLoading: false })); } }; const handlePhase6Submit = async () => { if (!state.phase4Result || !state.phase3Result || !state.phase1Result || !state.projectId) return; setState(s => ({ ...s, isLoading: true })); try { const result = await Gemini.generateSalesEnablement( state.phase4Result, state.phase3Result, state.phase1Result, language, state.projectId ); setState(s => ({ ...s, currentPhase: Phase.SalesEnablement, phase6Result: result, isLoading: false })); } catch (e: any) { setError(e.message); setState(s => ({ ...s, isLoading: false })); } }; const handlePhase7Submit = async () => { if (!state.phase4Result || !state.phase2Result || !state.projectId) return; setState(s => ({ ...s, isLoading: true })); try { const result = await Gemini.generateLandingPageCopy( state.phase4Result, state.phase2Result, language, state.projectId ); setState(s => ({ ...s, currentPhase: Phase.LandingPage, phase7Result: result, isLoading: false })); } catch (e: any) { setError(e.message); setState(s => ({ ...s, isLoading: false })); } }; const handlePhase8Submit = async () => { if (!state.phase2Result || !state.phase1Result || !state.projectId) return; setState(s => ({ ...s, isLoading: true })); try { const result = await Gemini.buildBusinessCase( state.phase2Result, state.phase1Result, language, state.projectId ); setState(s => ({ ...s, currentPhase: Phase.BusinessCase, phase8Result: result, isLoading: false })); } catch (e: any) { setError(e.message); setState(s => ({ ...s, isLoading: false })); } }; const handlePhase9Submit = async () => { if (!state.phase1Result || !state.phase4Result || !state.projectId) return; setState(s => ({ ...s, isLoading: true })); try { const result = await Gemini.translateTech( state.phase1Result, state.phase4Result, language, state.projectId ); setState(s => ({ ...s, currentPhase: Phase.TechTranslator, phase9Result: result, isLoading: false })); } catch (e: any) { setError(e.message); setState(s => ({ ...s, isLoading: false })); } }; // --- List Mutation Handlers (Phase 1) --- const addFeature = () => { if (!newFeatureInput.trim() || !state.phase1Result) return; const newItem = newFeatureInput.trim(); setState(s => ({ ...s, phase1Result: s.phase1Result ? { ...s.phase1Result, features: [...s.phase1Result.features, newItem] } : undefined })); setNewFeatureInput(""); }; const removeFeature = (index: number) => { setState(s => ({ ...s, phase1Result: s.phase1Result ? { ...s.phase1Result, features: s.phase1Result.features.filter((_, i) => i !== index) } : undefined })); }; const addConstraint = () => { if (!newConstraintInput.trim() || !state.phase1Result) return; const newItem = newConstraintInput.trim(); setState(s => ({ ...s, phase1Result: s.phase1Result ? { ...s.phase1Result, constraints: [...s.phase1Result.constraints, newItem] } : undefined })); setNewConstraintInput(""); }; const removeConstraint = (index: number) => { setState(s => ({ ...s, phase1Result: s.phase1Result ? { ...s.phase1Result, constraints: s.phase1Result.constraints.filter((_, i) => i !== index) } : undefined })); }; // --- List Mutation Handlers (Phase 2) --- const addICP = () => { if (!newICPName.trim() || !newICPRationale.trim() || !state.phase2Result) return; const newItem = { name: newICPName.trim(), rationale: newICPRationale.trim() }; setState(s => ({ ...s, phase2Result: s.phase2Result ? { ...s.phase2Result, icps: [...s.phase2Result.icps, newItem] } : undefined })); setNewICPName(""); setNewICPRationale(""); }; const removeICP = (index: number) => { setState(s => ({ ...s, phase2Result: s.phase2Result ? { ...s.phase2Result, icps: s.phase2Result.icps.filter((_, i) => i !== index) } : undefined })); }; const addProxy = () => { if (!newProxyTarget.trim() || !newProxyMethod.trim() || !state.phase2Result) return; const newItem = { target: newProxyTarget.trim(), method: newProxyMethod.trim() }; setState(s => ({ ...s, phase2Result: s.phase2Result ? { ...s.phase2Result, dataProxies: [...s.phase2Result.dataProxies, newItem] } : undefined })); setNewProxyTarget(""); setNewProxyMethod(""); }; const removeProxy = (index: number) => { setState(s => ({ ...s, phase2Result: s.phase2Result ? { ...s.phase2Result, dataProxies: s.phase2Result.dataProxies.filter((_, i) => i !== index) } : undefined })); }; // --- List Mutation Handlers (Phase 3) --- const addAccount = (groupIndex: number) => { const inputValue = newAccountInputs[groupIndex]; if (!inputValue?.trim() || !state.phase3Result) return; const newItem = inputValue.trim(); const newWhales = [...state.phase3Result.whales]; newWhales[groupIndex] = { ...newWhales[groupIndex], accounts: [...newWhales[groupIndex].accounts, newItem] }; setState(s => ({ ...s, phase3Result: s.phase3Result ? { ...s.phase3Result, whales: newWhales } : undefined })); setNewAccountInputs(prev => ({...prev, [groupIndex]: ""})); }; const removeAccount = (groupIndex: number, accountIndex: number) => { if (!state.phase3Result) return; const newWhales = [...state.phase3Result.whales]; newWhales[groupIndex] = { ...newWhales[groupIndex], accounts: newWhales[groupIndex].accounts.filter((_, i) => i !== accountIndex) }; setState(s => ({ ...s, phase3Result: s.phase3Result ? { ...s.phase3Result, whales: newWhales } : undefined })); }; const addRole = () => { if (!newRoleInput.trim() || !state.phase3Result) return; const newItem = newRoleInput.trim(); setState(s => ({ ...s, phase3Result: s.phase3Result ? { ...s.phase3Result, roles: [...s.phase3Result.roles, newItem] } : undefined })); setNewRoleInput(""); }; const removeRole = (index: number) => { setState(s => ({ ...s, phase3Result: s.phase3Result ? { ...s.phase3Result, roles: s.phase3Result.roles.filter((_, i) => i !== index) } : undefined })); }; const handlePromptChange = (index: number, newText: string) => { if (!state.phase6Result) return; const newPrompts = [...state.phase6Result.visualPrompts]; newPrompts[index] = { ...newPrompts[index], prompt: newText }; setState(s => ({ ...s, phase6Result: s.phase6Result ? { ...s.phase6Result, visualPrompts: newPrompts } : undefined })); }; // --- Render Helpers --- const renderInputPhase = () => (
{/* LEFT COLUMN: Input */}

{labels.initTitle}