Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | import { type UIMessage } from "ai";
import { type RefObject } from "react";
import { LoadingIndicator } from "@/components/chat/loading-indicator";
import { ChatEmptyState } from "@/components/chat/empty-state";
import { CHAT_TRANSCRIPT_COPY } from "@/constants/chat";
import type { QuickAction } from "@/types/chat";
import { ChatMessage } from "./message";
type ChatTranscriptProps = {
containerRef: RefObject<HTMLDivElement | null>;
messages: UIMessage[];
isLoading: boolean;
userAvatarUrl?: string;
userAvatarLabel?: string;
userInitials?: string;
quickActions: QuickAction[];
onSelectPrompt: (prompt: string) => void;
onToolApproval: (id: string, approved: boolean) => void;
};
export function ChatTranscript({
containerRef,
messages,
isLoading,
userAvatarUrl,
userAvatarLabel = "User avatar",
userInitials = CHAT_TRANSCRIPT_COPY.userBadge,
quickActions,
onSelectPrompt,
onToolApproval,
}: ChatTranscriptProps) {
const lastMessage = messages.at(-1);
return (
<div ref={containerRef} className="min-h-0 flex-1 overflow-y-auto px-4 py-6 sm:px-6 lg:px-8">
{messages.length === 0 ? (
<ChatEmptyState quickActions={quickActions} onSelectPrompt={onSelectPrompt} />
) : (
<div className="mx-auto flex w-full max-w-3xl flex-col gap-8">
{messages.map((message) => (
<ChatMessage
key={message.id}
message={message}
isLastMessage={message.id === lastMessage?.id}
isLoading={isLoading}
userAvatarUrl={userAvatarUrl}
userAvatarLabel={userAvatarLabel}
userInitials={userInitials}
onSelectPrompt={onSelectPrompt}
onToolApproval={onToolApproval}
/>
))}
{isLoading && lastMessage?.role === "user" ? (
<LoadingIndicator label="Thinking" />
) : null}
</div>
)}
</div>
);
}
|