import React, { useState, useEffect, useRef } from 'react'; const ChatInterface = ({ socket, roomId }) => { const [messages, setMessages] = useState([ { text: "Hello! I'm your AI Tutor. Ask me things like \"Why does this step work?\" or \"What happens if the token expires?\"", sender: "ai" } ]); const [input, setInput] = useState(""); const [isMinimized, setIsMinimized] = useState(false); const [currentStep, setCurrentStep] = useState(0); const [protocol, setProtocol] = useState("JWT"); const messagesEndRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; useEffect(() => { scrollToBottom(); }, [messages, isMinimized]); useEffect(() => { const handleStepChanged = (e) => setCurrentStep(e.detail); window.addEventListener("stepChanged", handleStepChanged); return () => window.removeEventListener("stepChanged", handleStepChanged); }, []); // Listen for WebSocket Broadcasts useEffect(() => { const handleWsMessage = (e) => { const data = e.detail; if (data.type === "chat_ai") { setMessages(prev => [...prev, { text: data.message, sender: "ai" }]); } else if (data.type === "chat_user") { setMessages(prev => [...prev, { text: data.message, sender: "user" }]); } }; window.addEventListener("wsMessage", handleWsMessage); return () => window.removeEventListener("wsMessage", handleWsMessage); }, []); const toggleProtocol = () => { const newProtocol = protocol === "JWT" ? "OAuth2" : "JWT"; setProtocol(newProtocol); window.dispatchEvent(new CustomEvent("protocolChanged", { detail: newProtocol })); // Broadcast protocol change so others see it (if we want global sync) if (socket && socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify({ type: "sync_state", protocol: newProtocol })); } }; const handleSend = (e) => { e.preventDefault(); if (!input.trim()) return; // We don't append immediately, we wait for the broadcast bounce-back so everyone is synced. // Prepare history payload for backend const historyPayload = messages .filter(m => m.sender === "user" || m.sender === "ai") .map(m => ({ role: m.sender === "ai" ? "assistant" : "user", content: m.text })); if (socket && socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify({ type: "chat", message: input, currentStep: currentStep, topic: protocol, history: historyPayload })); } setInput(""); }; const handleShare = () => { const url = window.location.href; navigator.clipboard.writeText(url) .then(() => alert(`Room URL copied to clipboard!\n${url}`)) .catch(console.error); }; if (isMinimized) { return (
setIsMinimized(false)} style={{ position: 'fixed', top: '20px', left: '20px', background: 'rgba(17, 17, 17, 0.95)', borderRadius: '50px', padding: '10px 20px', color: 'white', cursor: 'pointer', zIndex: 1000, boxShadow: '0 4px 6px rgba(0,0,0,0.5)', fontFamily: 'sans-serif', fontWeight: 'bold', border: '1px solid rgba(255,255,255,0.1)' }} > 💬 Open Chat
); } return ( <>
{/* Header Top */}
Bhishaj AI
{/* Header Bottom (Room Info) */}
Room: {roomId}
{messages.map((msg, index) => (
{msg.text}
))}
setInput(e.target.value)} placeholder="Ask why this step works..." className="chat-input" />
); }; export default ChatInterface;