anycoder-ea74d65e / components /ChatPanel.jsx
Kidizzz's picture
Upload components/ChatPanel.jsx with huggingface_hub
52bec35 verified
Raw
History Blame Contribute Delete
4.68 kB
import React, { useState, useRef, useEffect } from 'react'
export default function ChatPanel({ nodes, messages, onSendMessage, onClose }) {
const [input, setInput] = useState('')
const [selectedNode, setSelectedNode] = useState(null)
const messagesEndRef = useRef(null)
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
}
useEffect(() => {
scrollToBottom()
}, [messages])
const handleSend = () => {
if (!input.trim() || !selectedNode) return
onSendMessage(input, selectedNode)
setInput('')
}
const ceoNode = nodes.find(n => n.type === 'ceo')
return (
<div className="w-96 bg-slate-800 border-l border-slate-700 flex flex-col">
{/* Header */}
<div className="p-4 border-b border-slate-700 flex items-center justify-between">
<div>
<h2 className="font-bold text-white">Agent Chat</h2>
<p className="text-xs text-slate-400">Communicate with your agents</p>
</div>
<button
onClick={onClose}
className="w-8 h-8 bg-slate-700 hover:bg-slate-600 rounded-lg flex items-center justify-center text-slate-400 hover:text-white transition-colors"
>
</button>
</div>
{/* Node Selector */}
<div className="p-3 border-b border-slate-700">
<label className="block text-xs font-medium text-slate-400 mb-2">Send to Agent:</label>
<div className="flex flex-wrap gap-1">
{nodes.map((node) => (
<button
key={node.id}
onClick={() => setSelectedNode(node.id)}
className={`px-2 py-1 rounded text-xs font-medium transition-all ${
selectedNode === node.id
? 'bg-violet-600 text-white'
: 'bg-slate-700 text-slate-300 hover:bg-slate-600'
}`}
>
{node.type === 'ceo' ? '👑' : '🤖'} {node.name}
</button>
))}
</div>
</div>
{/* Messages */}
<div className="flex-1 overflow-y-auto p-4 space-y-3">
{messages.length === 0 ? (
<div className="text-center py-8">
<div className="w-16 h-16 mx-auto mb-3 bg-slate-700/50 rounded-xl flex items-center justify-center">
<span className="text-2xl">💬</span>
</div>
<p className="text-slate-400 text-sm">Select an agent and start chatting</p>
{ceoNode && (
<p className="text-slate-500 text-xs mt-2">
Tip: Use CEO to coordinate between agents
</p>
)}
</div>
) : (
messages.map((msg) => (
<div
key={msg.id}
className={`flex ${msg.sender === 'user' ? 'justify-end' : 'justify-start'}`}
>
<div
className={`max-w-[80%] rounded-xl px-3 py-2 ${
msg.sender === 'user'
? 'bg-violet-600 text-white'
: 'bg-slate-700 text-slate-200'
}`}
>
{msg.sender !== 'user' && (
<p className="text-xs font-medium text-slate-400 mb-1">{msg.senderName}</p>
)}
<p className="text-sm">{msg.content}</p>
<p className="text-xs opacity-50 mt-1">
{new Date(msg.timestamp).toLocaleTimeString()}
</p>
</div>
</div>
))
)}
<div ref={messagesEndRef} />
</div>
{/* Input */}
<div className="p-3 border-t border-slate-700">
<div className="flex gap-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSend()}
placeholder={selectedNode ? "Type your message..." : "Select an agent first..."}
disabled={!selectedNode}
className="flex-1 px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-violet-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed"
/>
<button
onClick={handleSend}
disabled={!selectedNode || !input.trim()}
className="px-4 py-2 bg-gradient-to-r from-violet-600 to-fuchsia-600 text-white rounded-lg font-medium transition-all disabled:opacity-50 disabled:cursor-not-allowed hover:from-violet-500 hover:to-fuchsia-500"
>
Send
</button>
</div>
</div>
</div>
)
}