import { type KeyboardEvent, useEffect, useRef, useState } from 'react'; import { AlertCircle, ArrowUp, Bot, Loader2, User } from 'lucide-react'; import type { PatternDefinition } from '@shared/domain/pattern'; import type { ProjectRecord } from '@shared/domain/project'; import type { SessionRecord } from '@shared/domain/session'; interface ChatPaneProps { project: ProjectRecord; pattern: PatternDefinition; session: SessionRecord; onSend: (content: string) => Promise; } export function ChatPane({ project, pattern, session, onSend }: ChatPaneProps) { const [input, setInput] = useState(''); const transcriptRef = useRef(null); const textareaRef = useRef(null); useEffect(() => { transcriptRef.current?.scrollTo({ top: transcriptRef.current.scrollHeight, behavior: 'smooth', }); }, [session.messages.length]); const isBusy = session.status === 'running'; async function handleSubmit() { const text = input.trim(); if (!text || isBusy) return; setInput(''); await onSend(text); } function handleKeyDown(e: KeyboardEvent) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); void handleSubmit(); } } return (
{/* Header */}

{session.title}

{project.name} · {pattern.name} · {pattern.mode}

{session.status === 'running' && (
Running
)} {session.status === 'error' && (
Error
)} {session.status === 'idle' && session.messages.length > 0 && ( {session.messages.length} message{session.messages.length === 1 ? '' : 's'} )}
{/* Messages */}
{session.messages.length === 0 ? (

Send a message to start the conversation

Using {pattern.name} in{' '} {project.name}

) : (
{session.messages.map((message) => { const isUser = message.role === 'user'; return (
{isUser ? : }
{message.authorName}
{message.content}
{message.pending && (
Generating...
)}
); })}
)}
{/* Input area */}
{session.lastError && (
{session.lastError}
)}