import React from "react"; export type ChatTurnBase = { role: "user" | "assistant"; created_at?: string; }; type ChatTranscriptProps = { turns: TTurn[]; busy: boolean; bottomRef: React.RefObject; getTimeLabel?: (turn: TTurn) => string; renderMessage: (turn: TTurn, isUser: boolean) => React.ReactNode; busyLabel?: string; ariaLabel?: string; showToolbar?: boolean; initialVisibleCount?: number; }; export default function ChatTranscript(props: ChatTranscriptProps) { const { turns, busy, bottomRef, getTimeLabel, renderMessage, busyLabel = "Thinking…", ariaLabel = "Conversation transcript", showToolbar = true, initialVisibleCount = 120, } = props; const minVisible = Math.max(24, Number(initialVisibleCount || 120)); const [visibleCount, setVisibleCount] = React.useState(minVisible); React.useEffect(() => { setVisibleCount((prev) => { if (prev < minVisible) return minVisible; if (prev > turns.length) return Math.max(minVisible, turns.length); return prev; }); }, [turns.length, minVisible]); const hiddenCount = Math.max(0, turns.length - visibleCount); const visibleTurns = hiddenCount > 0 ? turns.slice(-visibleCount) : turns; return (
{showToolbar ? (
{turns.length} messages {hiddenCount > 0 ? ( ) : null}
) : null} {visibleTurns.map((turn, index) => { const isUser = turn.role === "user"; const timeText = getTimeLabel ? getTimeLabel(turn) : ""; const globalIndex = hiddenCount + index; return (
{isUser ? "You" : "Assistant"} {timeText ? {timeText} : null}
{renderMessage(turn, isUser)}
); })} {busy ? (
Assistant
{busyLabel}
) : null}
); }