maitrang04's picture
Upload 91 files
d125a03 verified
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { StatusIndicator } from "./StatusIndicator";
import { Phone, User } from "lucide-react";
import { cn } from "@/lib/utils";
import type { Agent, Call } from "@shared/schema";
interface AgentTileProps {
agent: Agent;
calls: Call[];
isSelected?: boolean;
onSelect: (agentId: string) => void;
onCallSelect: (callId: string) => void;
selectedCallId?: string;
}
export function AgentTile({
agent,
calls,
isSelected = false,
onSelect,
onCallSelect,
selectedCallId
}: AgentTileProps) {
const activeCalls = calls.filter(c => c.status === "active").slice(0, 5);
const status = agent.status as "active" | "waiting" | "issue";
return (
<Card
className={cn(
"hover-elevate cursor-pointer transition-all duration-200",
isSelected && "ring-2 ring-primary ring-offset-2"
)}
onClick={() => onSelect(agent.id)}
role="button"
tabIndex={0}
aria-label={`Agent ${agent.name}, ${agent.activeCallCount} active calls, status ${status}`}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onSelect(agent.id);
}
}}
data-testid={`agent-tile-${agent.id}`}
>
<CardHeader className="flex flex-row items-center justify-between gap-2 pb-2 space-y-0">
<div className="flex items-center gap-2">
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary/10">
<User className="h-4 w-4 text-primary" aria-hidden="true" />
</div>
<div>
<h3 className="text-sm font-semibold leading-none">{agent.name}</h3>
<p className="text-xs font-mono text-muted-foreground mt-0.5">ID: {agent.id.slice(0, 8)}</p>
</div>
</div>
<StatusIndicator status={status} size="md" />
</CardHeader>
<CardContent className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-xs text-muted-foreground">Active Calls</span>
<Badge variant="secondary" className="text-xs">
{agent.activeCallCount}
</Badge>
</div>
{activeCalls.length > 0 && (
<div className="space-y-2">
{activeCalls.map((call) => (
<div
key={call.id}
className={cn(
"flex items-center justify-between p-2 rounded-md bg-muted/50 hover-elevate cursor-pointer",
selectedCallId === call.id && "ring-1 ring-primary"
)}
onClick={(e) => {
e.stopPropagation();
onCallSelect(call.id);
}}
role="button"
tabIndex={0}
aria-label={`Call ${call.id.slice(0, 8)}, duration ${formatDuration(call.duration)}`}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.stopPropagation();
e.preventDefault();
onCallSelect(call.id);
}
}}
data-testid={`call-tile-${call.id}`}
>
<div className="flex items-center gap-2">
<Phone className="h-3 w-3 text-muted-foreground" aria-hidden="true" />
<span className="text-xs font-mono">{call.id.slice(0, 8)}</span>
</div>
<div className="flex items-center gap-2">
<span className="text-xs text-muted-foreground font-mono">
{formatDuration(call.duration)}
</span>
<StatusIndicator status={call.status === "active" ? "active" : "waiting"} size="sm" />
</div>
</div>
))}
</div>
)}
{activeCalls.length === 0 && (
<div className="text-center py-3 text-xs text-muted-foreground">
No active calls
</div>
)}
</CardContent>
</Card>
);
}
function formatDuration(seconds: number): string {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins}:${secs.toString().padStart(2, "0")}`;
}