Files
resolutionflow/frontend/src/components/ai-chat/ChatPanel.tsx
chihlasm 596153085a feat: add AI chat builder frontend — types, API client, store, components, page, routing
- TypeScript types for chat session, messages, and responses
- API client module with all 6 endpoints
- Zustand store with session management, message sending, tree generation, import, resume
- 7 chat components: ChatMessage, ChatInput, ChatPanel, PhaseIndicator, ChatToolbar, EmptyPreview, StaticTreePreview
- AIChatBuilderPage with split-panel layout (60% chat / 40% preview)
- Route at /ai/chat with lazy loading
- "Build with AI" button on TreeLibraryPage
- Session resume via URL search params

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 07:20:04 -05:00

48 lines
1.4 KiB
TypeScript

import { useEffect, useRef } from 'react'
import { ChatMessage } from './ChatMessage'
import { ChatInput } from './ChatInput'
import { Spinner } from '@/components/common/Spinner'
import type { ChatMessage as ChatMessageType } from '@/types'
interface ChatPanelProps {
messages: ChatMessageType[]
isResponding: boolean
onSendMessage: (content: string) => void
disabled?: boolean
}
export function ChatPanel({ messages, isResponding, onSendMessage, disabled }: ChatPanelProps) {
const scrollRef = useRef<HTMLDivElement>(null)
// Auto-scroll to bottom on new messages
useEffect(() => {
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight
}
}, [messages, isResponding])
return (
<div className="flex h-full flex-col">
{/* Messages */}
<div ref={scrollRef} className="flex-1 overflow-y-auto px-4 py-4 space-y-4">
{messages.map((msg, i) => (
<ChatMessage key={i} message={msg} />
))}
{isResponding && (
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Spinner size="sm" />
<span>Thinking...</span>
</div>
)}
</div>
{/* Input */}
<ChatInput
onSend={onSendMessage}
disabled={disabled || isResponding}
placeholder={isResponding ? 'Waiting for response...' : 'Type a message...'}
/>
</div>
)
}