import React, { useState, useRef, useEffect } from 'react';
import { X, ClipboardList, Linkedin, Instagram, Mail, Layout, Edit3, MonitorPlay, Lightbulb, Image, Plus, Sparkles, Zap, AlertCircle, Video, Megaphone, Link as LinkIcon, Loader2, RefreshCw, CheckCircle2, MessageSquare } from 'lucide-react';
import { GradioService } from '../services/gradioService';
// --- Types ---
interface ChatPageProps {
onBack: () => void;
simulationResult: any;
setSimulationResult: (res: any) => void;
}
// --- Sub-components (Modular Structure) ---
const ChatButton: React.FC<{ label: string; primary?: boolean; icon?: React.ReactNode; onClick?: () => void; className?: string }> = ({ label, primary, icon, onClick, className = "" }) => (
);
const CategoryCard: React.FC<{
title: string;
options: { label: string; icon: React.ReactNode }[];
selectedVariation: string;
onSelect: (label: string) => void;
}> = ({ title, options, selectedVariation, onSelect }) => (
{title}
{options.map((option) => (
onSelect(option.label)}
className={`group flex items-center gap-3 p-3 rounded-xl cursor-pointer border transition-all duration-200
${selectedVariation === option.label
? 'bg-teal-900/20 border-teal-500/50 text-white'
: 'hover:bg-gray-900/80 border-transparent hover:border-gray-800'}`}
>
{option.icon}
{option.label}
))}
);
const ChatInput: React.FC<{ onSimulate: (msg: string) => void; onHelpMeCraft: (msg: string) => void; isSimulating: boolean }> = ({ onSimulate, onHelpMeCraft, isSimulating }) => {
const [message, setMessage] = useState('');
const [uploadedFiles, setUploadedFiles] = useState([]);
const fileInputRef = useRef(null);
const handleUploadClick = () => {
fileInputRef.current?.click();
};
const handleFileChange = (e: React.ChangeEvent) => {
const files = e.target.files;
if (files && files.length > 0) {
const newFiles = Array.from(files);
setUploadedFiles(prev => [...prev, ...newFiles]);
console.log("Selected files:", newFiles.map(f => f.name));
}
};
const removeFile = (index: number) => {
setUploadedFiles(prev => prev.filter((_, i) => i !== index));
};
return (
{uploadedFiles.length > 0 && (
{uploadedFiles.map((file, idx) => (
{file.name}
))}
)}
);
};
// --- Main Page Component ---
const ChatPage: React.FC = ({ onBack, simulationResult, setSimulationResult }) => {
const [showNotification, setShowNotification] = useState(false);
const [isSimulating, setIsSimulating] = useState(false);
const [simulationId, setSimulationId] = useState('User Group 1');
const [selectedVariation, setSelectedVariation] = useState('');
useEffect(() => {
const fetchSimulations = async () => {
try {
const sims = await GradioService.listSimulations();
if (Array.isArray(sims) && sims.length > 0) {
const firstSim = typeof sims[0] === 'string' ? sims[0] : (sims[0].id || sims[0].name || '');
if (firstSim) {
setSimulationId(firstSim);
}
}
} catch (e) {
console.error("Failed to fetch simulations:", e);
}
};
fetchSimulations();
}, []);
const handleSimulate = async (msg: string) => {
if (!msg.trim()) {
alert("Please enter some content to simulate.");
return;
}
setIsSimulating(true);
setShowNotification(true);
setSimulationResult(null);
try {
const result = await GradioService.startSimulationAsync(simulationId, msg);
setIsSimulating(false);
setSimulationResult({
status: "Initiated",
message: "Simulation started successfully. Please wait for the results.",
data: result
});
} catch (error) {
setIsSimulating(false);
setSimulationResult({
status: "Error",
message: "Failed to start simulation. Please try again."
});
}
};
const handleRefresh = async () => {
setIsSimulating(true);
try {
const status = await GradioService.getSimulationStatus(simulationId);
setIsSimulating(false);
setSimulationResult({
status: "Updated",
message: "Latest status gathered from API.",
data: status
});
} catch (error) {
setIsSimulating(false);
setSimulationResult({
status: "Error",
message: "Failed to gather results. The simulation might still be in progress."
});
}
};
const handleHelpMeCraft = async (msg: string) => {
if (!msg.trim()) {
alert("Please enter some content first.");
return;
}
setIsSimulating(true);
try {
const response = await fetch('/api/craft', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: msg,
variation: selectedVariation
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Failed to craft content');
}
alert(`Crafted variants for ${selectedVariation || 'general content'}:\n\n` + data.result);
} catch (e: any) {
console.error(e);
alert("Failed to craft content: " + e.message);
} finally {
setIsSimulating(false);
}
};
const categories = {
'Survey': [
{ label: 'Survey', icon: }
],
'Marketing Content': [
{ label: 'Article', icon: },
{ label: 'Website Link', icon: },
{ label: 'Advertisement', icon: }
],
'Social Media Posts': [
{ label: 'LinkedIn Post', icon: },
{ label: 'Instagram Post', icon: },
{ label: 'X Post', icon: },
{ label: 'TikTok Script', icon: }
],
'Communication': [
{ label: 'Email Subject Line', icon: },
{ label: 'Email', icon: }
],
'Product': [
{ label: 'Product Proposition', icon: }
]
};
return (
{/* Header / Nav */}
{/* Notification Banner */}
{showNotification && (
Simulation Status
Please wait, the results will show here. The simulation process can take up to 30 minutes. Click "Gather Results" to fetch the latest state.
{simulationResult && (
{simulationResult.message}
{simulationResult.data && (
{JSON.stringify(simulationResult.data, null, 2)}
)}
)}
)}
{/* Scrollable Content Area */}
What would you like to simulate?
{/* Column 1 */}
{/* Column 2 */}
{/* Column 3 */}
{/* Input Footer */}
);
};
export default ChatPage;