import { useState, useEffect, useRef } from "react"; import { streamChat } from "../api"; import MessageBubble from "./MessageBubble"; export default function ChatArea({ onEvalEntry, hasDocuments, suggestedQuestion, onSuggestedQuestionUsed, currentWorkspace = "default", filterDocs = [], onFilterClear, }) { const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const [loading, setLoading] = useState(false); const bottomRef = useRef(null); useEffect(() => { if (suggestedQuestion) { setInput(suggestedQuestion); onSuggestedQuestionUsed?.(); } }, [suggestedQuestion, onSuggestedQuestionUsed]); useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]); async function handleSend(e) { e.preventDefault(); if (!input.trim() || loading || !hasDocuments) return; const question = input.trim(); setInput(""); const msgId = crypto.randomUUID(); const tokenBuffer = []; setMessages((prev) => [ ...prev, { role: "user", content: question }, { id: msgId, role: "assistant", content: "", sources: [], loading: true }, ]); setLoading(true); try { await streamChat( question, currentWorkspace, { onToken: (token) => { tokenBuffer.push(token); setMessages((prev) => prev.map((m) => m.id === msgId ? { ...m, content: m.content + token } : m ) ); }, onDone: (event) => { setMessages((prev) => prev.map((m) => m.id === msgId ? { ...m, sources: event.sources ?? [], retrieval_method: event.retrieval_method, loading: false, } : m ) ); onEvalEntry?.({ query: question, answer: tokenBuffer.join("") }); }, onError: (message) => { setMessages((prev) => prev.map((m) => m.id === msgId ? { ...m, content: `Error: ${message}`, loading: false } : m ) ); }, }, filterDocs.length > 0 ? filterDocs : null ); } finally { setLoading(false); } } return (
{/* Messages */}
{messages.length === 0 && (

{hasDocuments ? "Ask a question about your documents" : "Upload documents to get started"}

{hasDocuments ? "Prism will find answers and cite sources" : "Drop PDF, TXT, CSV files or paste a URL in the sidebar"}

)} {messages.map((msg, i) => ( ))}
{/* Filter badge */} {filterDocs.length > 0 && (
Scoped to: {filterDocs.join(", ")}
)} {/* Input */}
setInput(e.target.value)} placeholder={ filterDocs.length > 0 ? `Searching ${filterDocs.length} selected doc${filterDocs.length > 1 ? "s" : ""}...` : hasDocuments ? "Ask anything — searching docs + web..." : "Upload documents first to start chatting" } className="flex-1 px-4 py-3 border border-gray-200 rounded-xl text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent disabled:bg-gray-50 disabled:text-gray-400 transition-shadow" disabled={loading || !hasDocuments} />
); }