feat: build CC Agent Call Desk with CTI simulation, AI insights, disposition form, and call log

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-16 18:30:34 +05:30
parent e9ac6e598a
commit 5efa22a35a
6 changed files with 659 additions and 5 deletions

View File

@@ -0,0 +1,77 @@
import { Badge } from '@/components/base/badges/badges';
import { Button } from '@/components/base/buttons/button';
import { ArrowRight } from '@untitledui/icons';
import { formatShortDate } from '@/lib/format';
import type { Call, CallDisposition } from '@/types/entities';
interface CallLogProps {
calls: Call[];
}
const dispositionConfig: Record<CallDisposition, { label: string; color: 'success' | 'brand' | 'blue-light' | 'warning' | 'gray' | 'error' }> = {
APPOINTMENT_BOOKED: { label: 'Booked', color: 'success' },
FOLLOW_UP_SCHEDULED: { label: 'Follow-up', color: 'brand' },
INFO_PROVIDED: { label: 'Info', color: 'blue-light' },
NO_ANSWER: { label: 'No Answer', color: 'warning' },
WRONG_NUMBER: { label: 'Wrong #', color: 'gray' },
CALLBACK_REQUESTED: { label: 'Not Interested', color: 'error' },
};
const formatDuration = (seconds: number | null): string => {
if (seconds === null || seconds === 0) return '0 min';
const minutes = Math.round(seconds / 60);
return `${minutes} min`;
};
export const CallLog = ({ calls }: CallLogProps) => {
return (
<div className="rounded-2xl border border-secondary bg-primary">
<div className="flex items-center justify-between border-b border-secondary px-5 py-4">
<div className="flex items-center gap-2">
<span className="text-sm font-bold text-primary">Today's Calls</span>
<Badge size="sm" color="gray">{calls.length}</Badge>
</div>
</div>
{calls.length > 0 ? (
<div className="divide-y divide-secondary">
{calls.map((call) => {
const config = call.disposition !== null
? dispositionConfig[call.disposition]
: null;
return (
<div
key={call.id}
className="flex items-center gap-3 px-5 py-3"
>
<span className="w-20 shrink-0 text-xs text-quaternary">
{call.startedAt !== null ? formatShortDate(call.startedAt) : ''}
</span>
<span className="min-w-0 flex-1 truncate text-sm font-medium text-primary">
{call.leadName ?? call.callerNumber?.[0]?.number ?? 'Unknown'}
</span>
{config !== null && (
<Badge size="sm" color={config.color}>{config.label}</Badge>
)}
<span className="w-12 shrink-0 text-right text-xs text-quaternary">
{formatDuration(call.durationSeconds)}
</span>
</div>
);
})}
</div>
) : (
<div className="flex items-center justify-center py-8">
<p className="text-sm text-quaternary">No calls handled today</p>
</div>
)}
<div className="border-t border-secondary px-5 py-3">
<Button href="/call-history" color="link-color" size="sm" iconTrailing={ArrowRight}>
View Full History
</Button>
</div>
</div>
);
};