AI_Manager_Dashboard / client /src /components /dashboard /InteractionTimeline.tsx
maitrang04's picture
Upload 91 files
d125a03 verified
import { ScrollArea } from "@/components/ui/scroll-area";
import { Phone, TrendingUp, Heart, ArrowRightLeft, PhoneOff } from "lucide-react";
import { cn } from "@/lib/utils";
import type { TimelineEvent } from "@shared/schema";
interface InteractionTimelineProps {
events: TimelineEvent[];
className?: string;
}
const eventConfig: Record<TimelineEvent["type"], { icon: React.ReactNode; color: string; bgColor: string }> = {
call_start: {
icon: <Phone className="h-3 w-3" />,
color: "text-emerald-600 dark:text-emerald-400",
bgColor: "bg-emerald-500/10",
},
upsell_attempt: {
icon: <TrendingUp className="h-3 w-3" />,
color: "text-amber-600 dark:text-amber-400",
bgColor: "bg-amber-500/10",
},
sentiment_change: {
icon: <Heart className="h-3 w-3" />,
color: "text-pink-600 dark:text-pink-400",
bgColor: "bg-pink-500/10",
},
transfer: {
icon: <ArrowRightLeft className="h-3 w-3" />,
color: "text-primary",
bgColor: "bg-primary/10",
},
call_end: {
icon: <PhoneOff className="h-3 w-3" />,
color: "text-muted-foreground",
bgColor: "bg-muted",
},
};
export function InteractionTimeline({ events, className }: InteractionTimelineProps) {
const formatTime = (date: Date | string): string => {
const d = new Date(date);
return d.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" });
};
return (
<div className={cn("flex flex-col", className)}>
<div className="flex items-center justify-between px-4 py-3 border-b border-border">
<h3 className="text-sm font-semibold">Interaction Timeline</h3>
<span className="text-xs text-muted-foreground">{events.length} events</span>
</div>
<ScrollArea className="flex-1 px-4">
<div className="relative py-4" role="list" aria-label="Call interaction timeline">
{events.length === 0 && (
<div className="text-center py-8 text-sm text-muted-foreground">
No events recorded yet
</div>
)}
{events.map((event, index) => {
const config = eventConfig[event.type];
const isLast = index === events.length - 1;
return (
<div key={event.id} className="relative flex gap-3 pb-4" role="listitem" data-testid={`timeline-event-${event.id}`}>
{!isLast && (
<div
className="absolute left-[11px] top-6 h-full w-px bg-border"
aria-hidden="true"
/>
)}
<div
className={cn(
"relative z-10 flex h-6 w-6 shrink-0 items-center justify-center rounded-full",
config.bgColor,
config.color
)}
>
{config.icon}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2">
<span className="text-sm font-medium truncate">{event.description}</span>
<span className="text-xs text-muted-foreground font-mono shrink-0">
{formatTime(event.timestamp)}
</span>
</div>
<span className="text-xs text-muted-foreground capitalize">
{event.type.replace(/_/g, " ")}
</span>
</div>
</div>
);
})}
</div>
</ScrollArea>
</div>
);
}