/** * Assistant Chat Component * * Main chat interface for the project assistant. * Displays messages and handles user input. */ import { useState, useRef, useEffect, useCallback } from 'react' import { Send, Loader2, Wifi, WifiOff } from 'lucide-react' import { useAssistantChat } from '../hooks/useAssistantChat' import { ChatMessage } from './ChatMessage' interface AssistantChatProps { projectName: string } export function AssistantChat({ projectName }: AssistantChatProps) { const [inputValue, setInputValue] = useState('') const messagesEndRef = useRef(null) const inputRef = useRef(null) const hasStartedRef = useRef(false) // Memoize the error handler to prevent infinite re-renders const handleError = useCallback((error: string) => { console.error('Assistant error:', error) }, []) const { messages, isLoading, connectionStatus, start, sendMessage, } = useAssistantChat({ projectName, onError: handleError, }) // Auto-scroll to bottom on new messages useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [messages]) // Start the chat session when component mounts (only once) useEffect(() => { if (!hasStartedRef.current) { hasStartedRef.current = true start() } }, [start]) // Focus input when not loading useEffect(() => { if (!isLoading) { inputRef.current?.focus() } }, [isLoading]) const handleSend = () => { const content = inputValue.trim() if (!content || isLoading) return sendMessage(content) setInputValue('') } const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() handleSend() } } return (
{/* Connection status indicator */}
{connectionStatus === 'connected' ? ( <> Connected ) : connectionStatus === 'connecting' ? ( <> Connecting... ) : ( <> Disconnected )}
{/* Messages area */}
{messages.length === 0 ? (
{isLoading ? (
Connecting to assistant...
) : ( Ask me anything about the codebase )}
) : (
{messages.map((message) => ( ))}
)}
{/* Loading indicator */} {isLoading && messages.length > 0 && (
Thinking...
)} {/* Input area */}