feat(team-performance): group calls by authoritative agent relation

Prefer call.agent.id (set by CDR enrichment) over call.agentName string
matching. Falls back to the raw agentName only when the row hasn't been
enriched yet. Eliminates the "RamaiahAdmin -> GlobalHealthX" transfer-chain
rows and the display-name collisions (two distinct AgentIDs with the same
Full Name).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 07:43:49 +05:30
parent 4590417536
commit d00b066806

View File

@@ -90,7 +90,7 @@ export const TeamPerformancePage = () => {
try { try {
const [callsData, apptsData, leadsData, followUpsData, teamData] = await Promise.all([ const [callsData, apptsData, leadsData, followUpsData, teamData] = await Promise.all([
apiClient.graphql<any>(`{ calls(first: 500, filter: { startedAt: { gte: "${gte}", lte: "${lte}" } }) { edges { node { id direction callStatus agentName startedAt } } } }`, undefined, { silent: true }), apiClient.graphql<any>(`{ calls(first: 500, filter: { startedAt: { gte: "${gte}", lte: "${lte}" } }) { edges { node { id direction callStatus agentName startedAt agentId agent { id name ozonetelAgentId } } } } }`, undefined, { silent: true }),
apiClient.graphql<any>(`{ appointments(first: 200, filter: { scheduledAt: { gte: "${gte}", lte: "${lte}" } }) { edges { node { id status } } } }`, undefined, { silent: true }), apiClient.graphql<any>(`{ appointments(first: 200, filter: { scheduledAt: { gte: "${gte}", lte: "${lte}" } }) { edges { node { id status } } } }`, undefined, { silent: true }),
apiClient.graphql<any>(`{ leads(first: 200) { edges { node { id assignedAgent status } } } }`, undefined, { silent: true }), apiClient.graphql<any>(`{ leads(first: 200) { edges { node { id assignedAgent status } } } }`, undefined, { silent: true }),
apiClient.graphql<any>(`{ followUps(first: 200) { edges { node { id assignedAgent } } } }`, undefined, { silent: true }), apiClient.graphql<any>(`{ followUps(first: 200) { edges { node { id assignedAgent } } } }`, undefined, { silent: true }),
@@ -110,9 +110,15 @@ export const TeamPerformancePage = () => {
let agentPerfs: AgentPerf[]; let agentPerfs: AgentPerf[];
if (teamAgents.length > 0) { if (teamAgents.length > 0) {
// Real Ozonetel data available // Real Ozonetel data available — prefer authoritative agent
// relation (set by CDR enrichment), fall back to agentName
// string for rows not yet enriched.
agentPerfs = teamAgents.map((agent: any) => { agentPerfs = teamAgents.map((agent: any) => {
const agentCalls = calls.filter((c: any) => c.agentName === agent.name || c.agentName === agent.ozonetelAgentId); const agentCalls = calls.filter((c: any) => {
if (c.agentId && c.agentId === agent.id) return true;
if (!c.agentId && (c.agentName === agent.name || c.agentName === agent.ozonetelAgentId)) return true;
return false;
});
const agentLeads = leads.filter((l: any) => l.assignedAgent === agent.name); const agentLeads = leads.filter((l: any) => l.assignedAgent === agent.name);
const agentFollowUps = followUps.filter((f: any) => f.assignedAgent === agent.name); const agentFollowUps = followUps.filter((f: any) => f.assignedAgent === agent.name);
const agentAppts = agentCalls.filter((c: any) => c.callStatus === 'COMPLETED').length; const agentAppts = agentCalls.filter((c: any) => c.callStatus === 'COMPLETED').length;
@@ -148,10 +154,23 @@ export const TeamPerformancePage = () => {
}; };
}); });
} else { } else {
// Fallback: build agent list from call records // Fallback: build agent list from call records. Prefer
const agentNames = [...new Set(calls.map((c: any) => c.agentName).filter(Boolean))] as string[]; // the authoritative agent relation; fall back to the raw
agentPerfs = agentNames.map((name) => { // agentName string (Ozonetel transfer chain) only when
const agentCalls = calls.filter((c: any) => c.agentName === name); // we have nothing better.
const byKey = new Map<string, { key: string; name: string; ozonetelAgentId: string }>();
for (const c of calls) {
if (c.agent?.id) {
byKey.set(c.agent.id, { key: c.agent.id, name: c.agent.name ?? c.agent.ozonetelAgentId, ozonetelAgentId: c.agent.ozonetelAgentId });
} else if (c.agentName) {
byKey.set(`legacy:${c.agentName}`, { key: `legacy:${c.agentName}`, name: c.agentName, ozonetelAgentId: c.agentName });
}
}
agentPerfs = Array.from(byKey.values()).map(({ key, name, ozonetelAgentId: _ozonetelAgentId }) => {
const agentCalls = calls.filter((c: any) => {
if (key.startsWith('legacy:')) return c.agentName === name && !c.agent?.id;
return c.agent?.id === key;
});
const agentLeads = leads.filter((l: any) => l.assignedAgent === name); const agentLeads = leads.filter((l: any) => l.assignedAgent === name);
const agentFollowUps = followUps.filter((f: any) => f.assignedAgent === name); const agentFollowUps = followUps.filter((f: any) => f.assignedAgent === name);
const completed = agentCalls.filter((c: any) => c.callStatus === 'COMPLETED').length; const completed = agentCalls.filter((c: any) => c.callStatus === 'COMPLETED').length;