diff --git a/src/components/dashboard/agent-table.tsx b/src/components/dashboard/agent-table.tsx index 506c363..e82fe75 100644 --- a/src/components/dashboard/agent-table.tsx +++ b/src/components/dashboard/agent-table.tsx @@ -26,14 +26,27 @@ interface AgentTableProps { export const AgentTable = ({ calls }: AgentTableProps) => { const agents = useMemo(() => { - const agentMap = new Map(); + // Bucket by authoritative agent.id when present (from CDR enrichment); + // fall back to raw agentName for legacy rows that haven't been + // enriched yet. Skips rows with no agent info at all. + const agentMap = new Map(); for (const call of calls) { - const agent = call.agentName ?? 'Unknown'; - if (!agentMap.has(agent)) agentMap.set(agent, []); - agentMap.get(agent)!.push(call); + let key: string; + let displayName: string; + if (call.agent?.id) { + key = call.agent.id; + displayName = call.agent.name ?? call.agent.ozonetelAgentId ?? 'Unknown'; + } else if (call.agentName) { + key = `legacy:${call.agentName}`; + displayName = call.agentName; + } else { + continue; + } + if (!agentMap.has(key)) agentMap.set(key, { displayName, calls: [] }); + agentMap.get(key)!.calls.push(call); } - return Array.from(agentMap.entries()).map(([name, agentCalls]) => { + return Array.from(agentMap.entries()).map(([key, { displayName, calls: agentCalls }]) => { const inbound = agentCalls.filter((c) => c.callDirection === 'INBOUND').length; const outbound = agentCalls.filter((c) => c.callDirection === 'OUTBOUND').length; const missed = agentCalls.filter((c) => c.callStatus === 'MISSED').length; @@ -43,11 +56,11 @@ export const AgentTable = ({ calls }: AgentTableProps) => { const avgHandle = completedCalls.length > 0 ? Math.round(totalDuration / completedCalls.length) : 0; const booked = agentCalls.filter((c) => c.disposition === 'APPOINTMENT_BOOKED').length; const conversion = total > 0 ? (booked / total) * 100 : 0; - const nameParts = name.split(' '); + const nameParts = displayName.split(' '); return { - id: name, - name, + id: key, + name: displayName, initials: getInitials(nameParts[0] ?? '', nameParts[1] ?? ''), inbound, outbound, missed, total, avgHandle, conversion, }; diff --git a/src/lib/queries.ts b/src/lib/queries.ts index 86ed50e..90ff5c5 100644 --- a/src/lib/queries.ts +++ b/src/lib/queries.ts @@ -54,6 +54,8 @@ export const CALLS_QUERY = `{ calls(first: 100, orderBy: [{ startedAt: DescNulls startedAt endedAt durationSec recording { primaryLinkUrl } disposition sla patientId appointmentId leadId + agentId agent { id name ozonetelAgentId } + transferredTo transferType } } } }`; export const DOCTORS_QUERY = `{ doctors(first: 20) { edges { node { diff --git a/src/lib/transforms.ts b/src/lib/transforms.ts index 6255c87..41e0035 100644 --- a/src/lib/transforms.ts +++ b/src/lib/transforms.ts @@ -150,6 +150,10 @@ export function transformCalls(data: any): Call[] { patientId: n.patientId, appointmentId: n.appointmentId, leadId: n.leadId, + agentId: n.agentId ?? null, + agent: n.agent ?? null, + transferredTo: n.transferredTo ?? null, + transferType: n.transferType ?? null, })); } diff --git a/src/types/entities.ts b/src/types/entities.ts index fd778ca..3261ee3 100644 --- a/src/types/entities.ts +++ b/src/types/entities.ts @@ -276,6 +276,12 @@ export type Call = { appointmentId: string | null; leadId: string | null; sla?: number | null; + // Authoritative agent link from CDR enrichment. agentName remains the + // raw Ozonetel string (may be a transfer chain) for display fallback. + agentId?: string | null; + agent?: { id: string; name: string | null; ozonetelAgentId: string | null } | null; + transferredTo?: string | null; + transferType?: string | null; // Denormalized for display leadName?: string; leadPhone?: string;