| "use client"; |
|
|
| import { useEffect, useRef } from "react"; |
| import { useChatStore } from "@/lib/chatStore"; |
| import type { SourceDoc } from "@/lib/types"; |
| import { AssistantMessage, ErrorMessage, UserMessage } from "./Message"; |
| import { Thinking } from "./Thinking"; |
|
|
| export function Thread({ |
| onOpenSource, |
| }: { |
| onOpenSource?: (doc: SourceDoc, index: number) => void; |
| }) { |
| const conv = useChatStore((s) => |
| s.activeId ? s.conversations[s.activeId] : null |
| ); |
| const ref = useRef<HTMLDivElement | null>(null); |
|
|
| |
| const turns = conv?.turns ?? []; |
| const lastTurn = turns[turns.length - 1]; |
| useEffect(() => { |
| const el = ref.current; |
| if (!el) return; |
| el.scrollTo({ top: el.scrollHeight, behavior: "smooth" }); |
| }, [ |
| turns.length, |
| lastTurn?.pending, |
| lastTurn?.response?.answer?.length, |
| ]); |
|
|
| if (!conv || conv.turns.length === 0) return null; |
|
|
| return ( |
| <div ref={ref} className="flex-1 overflow-y-auto min-h-0"> |
| <div className="min-h-full flex flex-col justify-end max-w-[920px] mx-auto px-4 sm:px-6 py-8 space-y-6"> |
| {conv.turns.map((t) => { |
| const hasAnswer = Boolean(t.response?.answer); |
| const showThinking = t.pending && !hasAnswer && !t.error; |
| const showAnswer = !!t.response && (hasAnswer || !t.pending); |
| return ( |
| <div key={t.id} className="space-y-4"> |
| <UserMessage text={t.question} /> |
| {showThinking && <Thinking />} |
| {t.error && <ErrorMessage turn={t} />} |
| {showAnswer && ( |
| <AssistantMessage turn={t} onOpenSource={onOpenSource} /> |
| )} |
| </div> |
| ); |
| })} |
| </div> |
| </div> |
| ); |
| } |
|
|