// ============================================================================ // public/screens/analytics.jsx — Analytics Dashboard (Phase 7A) // ============================================================================ function AnalyticsScreen() { const [overview, setOverview] = React.useState(null); const [callData, setCallData] = React.useState([]); const [agents, setAgents] = React.useState([]); const [intents, setIntents] = React.useState([]); const [quality, setQuality] = React.useState([]); const [range, setRange] = React.useState("30d"); const load = React.useCallback(async () => { const [ov, cd, ag, it, ql] = await Promise.all([ VoaisAPI.get("/api/analytics/overview"), VoaisAPI.get("/api/analytics/calls?range=" + range), VoaisAPI.get("/api/analytics/agents"), VoaisAPI.get("/api/analytics/intents"), VoaisAPI.get("/api/analytics/quality"), ]); if (ov.ok) setOverview(ov.data.overview); if (cd.ok) setCallData(cd.data.data); if (ag.ok) setAgents(ag.data.agents); if (it.ok) setIntents(it.data.intents); if (ql.ok) setQuality(ql.data.quality); }, [range]); React.useEffect(() => { load(); }, [load]); if (!overview) return ; const intentColors = { interested: "var(--ok)", not_interested: "var(--err)", unclear: "var(--warn)", callback: "var(--accent)", unknown: "var(--ink-3)" }; const qualColors = { hot: "#E24B4A", warm: "#EF9F27", cold: "#378ADD", unscored: "var(--ink-3)" }; return (
{/* KPI row */}
{/* Range selector + Call volume chart */}
Call volume
{callData.length > 0 ? ( ({ label: String(d.period).slice(-5), value: +d.total }))} height={200}/> ) :
No data for this period.
}
{/* Intent breakdown */}
Intent breakdown (30d)
{intents.length > 0 ? ( ({ value: +i.count, color: intentColors[i.interest] || "var(--ink-3)" }))} center={
{intents.reduce((a,b)=>a+(+b.count),0)}
calls
}/> ) : null}
{intents.map(i => (
{i.interest} {i.count}
))}
{/* Lead quality */}
Lead quality (30d)
{quality.map(q => { const total = quality.reduce((a,b)=>a+(+b.count),0) || 1; const pct = Math.round((+q.count / total) * 100); return (
{q.quality} {q.count} {pct}%
); })}
{/* Agent leaderboard */}
Agent performance (30d)
{agents.map(a => ( ))}
AgentCallsAnsweredHot leadsAvg scoreMinutes
{a.avatar_gradient &&
}
{a.name}
{a.code}
{+a.total_calls} {+a.answered} 0 ? "var(--err)" : undefined }}>{+a.hot_leads} {a.avg_score} {Math.round(+a.total_seconds/60)}m
); } function AKpi({ label, value, color }) { return (
{label}
{value}
); } window.AnalyticsScreen = AnalyticsScreen;