File size: 2,647 Bytes
b5c0df4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2befd58
b5c0df4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2befd58
b5c0df4
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/**
 * ChatThread — renders the scrollable list of chat messages with auto-scroll.
 *
 * - Renders each message as a <MessageBubble /> with appropriate props
 * - Renders an in-flight streaming bubble when streaming is active
 * - Auto-scrolls to bottom on new messages or streaming content updates
 *
 * Requirements: 4.3
 */

import { useEffect, useRef } from "react";
import { MessageBubble } from "./MessageBubble";
import type { Message, QueryResult } from "../types";

export interface ChatThreadProps {
  messages: Message[];
  results: Record<string, QueryResult>;
  streamingContent: string;
  streamingIndex: number | null;
  isStreaming: boolean;
  conversationId: string;
  isSaved: (index: number) => boolean;
  onSave: (index: number) => void;
  onExport: (index: number) => void;
}

/**
 * Renders the chat message thread with auto-scroll behaviour.
 *
 * Each message in the `messages` array is rendered as a <MessageBubble />.
 * When `isStreaming` is true and `streamingIndex` is not null, an additional
 * assistant bubble is rendered with the current `streamingContent` (flushed
 * by the rAF loop in useStream).
 *
 * Auto-scroll fires whenever messages change or streaming content updates,
 * keeping the latest content visible without manual scrolling.
 */
export function ChatThread({
  messages,
  results,
  streamingContent,
  streamingIndex,
  isStreaming,
  conversationId,
  isSaved,
  onSave,
  onExport,
}: ChatThreadProps) {
  const bottomRef = useRef<HTMLDivElement>(null);

  // Auto-scroll to bottom when messages change or streaming content updates
  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages, streamingContent]);

  return (
    <div className="flex-1 overflow-y-auto px-4 py-6">
      <div className="max-w-3xl mx-auto">
      {messages.map((message, index) => (
        <MessageBubble
          key={`${conversationId}-${index}`}
          message={message}
          index={index}
          conversationId={conversationId}
          result={results[String(index)]}
          isSaved={isSaved(index)}
          onSave={onSave}
          onExport={onExport}
        />
      ))}

      {/* In-flight streaming bubble */}
      {streamingIndex !== null && isStreaming && (
        <MessageBubble
          key={`${conversationId}-streaming`}
          message={{ role: "assistant", content: streamingContent }}
          index={streamingIndex}
          conversationId={conversationId}
          isStreaming={true}
        />
      )}

      {/* Scroll anchor */}
      <div ref={bottomRef} />
      </div>
    </div>
  );
}

export default ChatThread;