feat: CC agent features, live call assist, worklist redesign, brand tokens

CC Agent:
- Call transfer (CONFERENCE + KICK_CALL) with inline transfer dialog
- Recording pause/resume during active calls
- Missed calls API (Ozonetel abandonCalls)
- Call history API (Ozonetel fetchCDRDetails)

Live Call Assist:
- Deepgram Nova STT via raw WebSocket
- OpenAI suggestions every 10s with lead context
- LiveTranscript component in sidebar during calls
- Browser audio capture from remote WebRTC stream

Worklist:
- Redesigned table: clickable phones, context menu (Call/SMS/WhatsApp)
- Last interaction sub-line, source column, improved SLA
- Filtered out rows without phone numbers
- New missed call notifications

Brand:
- Logo on login page
- Blue scale rebuilt from logo blue rgb(32, 96, 160)
- FontAwesome duotone CSS variables set globally
- Profile menu icons switched to duotone

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 10:36:10 +05:30
parent 99bca1e008
commit 3064eeb444
21 changed files with 2583 additions and 85 deletions

View File

@@ -2,6 +2,8 @@ import { useEffect, useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSparkles, faUser } from '@fortawesome/pro-duotone-svg-icons';
import { AiChatPanel } from './ai-chat-panel';
import { LiveTranscript } from './live-transcript';
import { useCallAssist } from '@/hooks/use-call-assist';
import { Badge } from '@/components/base/badges/badges';
import { formatPhone, formatShortDate } from '@/lib/format';
import { cx } from '@/utils/cx';
@@ -13,9 +15,11 @@ interface ContextPanelProps {
selectedLead: Lead | null;
activities: LeadActivity[];
callerPhone?: string;
isInCall?: boolean;
callUcid?: string | null;
}
export const ContextPanel = ({ selectedLead, activities, callerPhone }: ContextPanelProps) => {
export const ContextPanel = ({ selectedLead, activities, callerPhone, isInCall, callUcid }: ContextPanelProps) => {
const [activeTab, setActiveTab] = useState<ContextTab>('ai');
// Auto-switch to lead 360 when a lead is selected
@@ -25,6 +29,13 @@ export const ContextPanel = ({ selectedLead, activities, callerPhone }: ContextP
}
}, [selectedLead?.id]);
const { transcript, suggestions, connected: assistConnected } = useCallAssist(
isInCall ?? false,
callUcid ?? null,
selectedLead?.id ?? null,
callerPhone ?? null,
);
const callerContext = selectedLead ? {
callerPhone: selectedLead.contactPhone?.[0]?.number ?? callerPhone,
leadId: selectedLead.id,
@@ -64,9 +75,13 @@ export const ContextPanel = ({ selectedLead, activities, callerPhone }: ContextP
{/* Tab content */}
<div className="flex-1 overflow-y-auto">
{activeTab === 'ai' && (
<div className="flex h-full flex-col p-4">
<AiChatPanel callerContext={callerContext} />
</div>
isInCall ? (
<LiveTranscript transcript={transcript} suggestions={suggestions} connected={assistConnected} />
) : (
<div className="flex h-full flex-col p-4">
<AiChatPanel callerContext={callerContext} />
</div>
)
)}
{activeTab === 'lead360' && (
<Lead360Tab lead={selectedLead} activities={activities} />