maitrang04's picture
Upload 91 files
d125a03 verified
import { useEffect, useRef } from "react";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Bot, User } from "lucide-react";
import { cn } from "@/lib/utils";
import type { TranscriptMessage } from "@shared/schema";
interface LiveTranscriptProps {
messages: TranscriptMessage[];
className?: string;
}
export function LiveTranscript({ messages, className }: LiveTranscriptProps) {
const scrollRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
}, [messages]);
const formatTime = (date: Date | string): string => {
const d = new Date(date);
return d.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", second: "2-digit" });
};
return (
<div className={cn("flex flex-col h-full", className)}>
<div className="flex items-center justify-between px-4 py-3 border-b border-border">
<h3 className="text-sm font-semibold">Live Transcript</h3>
<span className="text-xs text-muted-foreground">{messages.length} messages</span>
</div>
<ScrollArea className="flex-1 px-4" ref={scrollRef}>
<div className="space-y-3 py-4" role="log" aria-live="polite" aria-label="Live call transcript">
{messages.length === 0 && (
<div className="text-center py-8 text-sm text-muted-foreground">
Waiting for conversation to start...
</div>
)}
{messages.map((message) => (
<div
key={message.id}
className={cn(
"flex gap-3",
message.speaker === "ai" ? "flex-row" : "flex-row-reverse"
)}
data-testid={`transcript-message-${message.id}`}
>
<div
className={cn(
"flex h-8 w-8 shrink-0 items-center justify-center rounded-full",
message.speaker === "ai"
? "bg-primary/10"
: "bg-emerald-500/10"
)}
>
{message.speaker === "ai" ? (
<Bot className="h-4 w-4 text-primary" aria-hidden="true" />
) : (
<User className="h-4 w-4 text-emerald-600 dark:text-emerald-400" aria-hidden="true" />
)}
</div>
<div
className={cn(
"flex-1 max-w-[80%]",
message.speaker === "ai" ? "text-left" : "text-right"
)}
>
<div className="flex items-center gap-2 mb-1">
<span className={cn(
"text-xs font-medium",
message.speaker === "ai" ? "text-primary" : "text-emerald-600 dark:text-emerald-400"
)}>
{message.speaker === "ai" ? "AI Agent" : "Customer"}
</span>
<span className="text-xs text-muted-foreground font-mono">
{formatTime(message.timestamp)}
</span>
</div>
<div
className={cn(
"p-3 rounded-lg text-sm leading-relaxed",
message.speaker === "ai"
? "bg-primary/5 border border-primary/10"
: "bg-emerald-500/5 border border-emerald-500/10"
)}
>
{message.content}
</div>
</div>
</div>
))}
</div>
</ScrollArea>
</div>
);
}