// ─── Dashboard Page ────────────────────────────────────────────────────────── const STATUS_MAP = { booked: { color: 'green', label: 'Booked' }, completed: { color: 'blue', label: 'Completed' }, failed: { color: 'red', label: 'Failed' }, unknown: { color: 'gray', label: 'Unknown' }, }; function fmtDuration(seconds) { if (!seconds && seconds !== 0) return '—'; const m = Math.floor(seconds / 60); const s = Math.round(seconds % 60); return `${m}m ${s}s`; } function fmtRelative(isoStr) { if (!isoStr) return '—'; const diff = Date.now() - new Date(isoStr).getTime(); const mins = Math.floor(diff / 60000); if (mins < 60) return `${mins}m ago`; const hrs = Math.floor(mins / 60); if (hrs < 24) return `${hrs} hr${hrs > 1 ? 's' : ''} ago`; const days = Math.floor(hrs / 24); return `${days} day${days > 1 ? 's' : ''} ago`; } function fmtFull(isoStr) { if (!isoStr) return '—'; return new Date(isoStr).toLocaleString('en-IN', { month: 'short', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: true, }); } function TranscriptModal({ call, onClose }) { if (!call) return null; const lines = (call.transcript || '').split('\n').filter(Boolean); const parsed = lines.map(l => { if (l.startsWith('Agent:') || l.startsWith('AI:')) return { role: 'agent', text: l.replace(/^(Agent:|AI:)\s*/, '') }; if (l.startsWith('User:')) return { role: 'user', text: l.replace(/^User:\s*/, '') }; return { role: 'agent', text: l }; }); return (
e.stopPropagation()}>
{call.caller_name || 'Unknown'} · {call.phone_number}
{fmtFull(call.created_at)} · {fmtDuration(call.duration_seconds)}
{call.summary && <>
AI SUMMARY
{call.summary}
}
TRANSCRIPT
{parsed.length > 0 ? (
{parsed.map((t, i) => (
{t.role === 'agent' ? 'AI' : 'User'}
{t.text}
))}
) : (
No transcript available.
)}
window.open(`/api/logs/${call.id}/transcript`, '_blank')}>Download .txt
); } function DashboardPage() { const [logs, setLogs] = React.useState([]); const [stats, setStats] = React.useState(null); const [loading, setLoading] = React.useState(true); const [selected, setSelected] = React.useState(null); React.useEffect(() => { Promise.all([ fetch('/api/stats').then(r => r.json()).catch(() => null), fetch('/api/logs').then(r => r.json()).catch(() => []), ]).then(([s, l]) => { setStats(s); setLogs(Array.isArray(l) ? l.slice(0, 10) : []); setLoading(false); }); }, []); const avgDurSec = stats?.avg_duration ?? 0; const activeSessions = stats?.active_sessions ?? 1; return (
{loading ? : ( <>
{}}>View All Logs}> { const sm = STATUS_MAP[call.status] || STATUS_MAP.unknown; return [
{fmtRelative(call.created_at)}
{fmtFull(call.created_at)}
,
{call.phone_number}
{call.caller_name || 'Unknown'}
, {fmtDuration(call.duration_seconds)}, {sm.label},
setSelected(call)}>Transcript
, ]; })} />
)} setSelected(null)} />
); } Object.assign(window, { DashboardPage });