feat: SSE-driven worklist + agent call history split + remove SOURCE column

Worklist:
- SSE stream replaces 30s poll — EventSource on /api/supervisor/worklist/stream
  triggers immediate fetchWorklist() on missed-call events
- Toast notification: 'Missed Call — {name} — needs callback'
- No polling fallback — SSE is the source of truth

Call History split by role:
- Agent: 'My Call History' — own calls only (matched by agent relation
  or chain-parsed agentName), missed calls excluded (they belong on
  the Call Desk queue), no Agent/Recording/SLA columns, phone clickable
  via PhoneActionCell instead of separate Call button
- Supervisor: 'Call History' — all calls, Agent + Recording columns visible

Worklist panel:
- SOURCE/BRANCH column removed from display (data stays on row)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 18:33:17 +05:30
parent 5c9e70da20
commit df08bcfc19
3 changed files with 94 additions and 126 deletions

View File

@@ -1,6 +1,7 @@
import { useState, useEffect, useCallback } from 'react';
import { apiClient } from '@/lib/api-client';
import { notify } from '@/lib/toast';
type MissedCall = {
id: string;
@@ -133,9 +134,30 @@ export const useWorklist = (): UseWorklistResult => {
useEffect(() => {
fetchWorklist();
// Refresh every 30 seconds
const interval = setInterval(fetchWorklist, 30000);
return () => clearInterval(interval);
// SSE stream for instant worklist updates. No polling fallback —
// if SSE breaks, the worklist stops updating and we fix the SSE,
// not paper over it with a poll.
const API_URL = import.meta.env.VITE_API_URL ?? 'http://localhost:4100';
let es: EventSource | null = null;
try {
es = new EventSource(`${API_URL}/api/supervisor/worklist/stream`);
es.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
console.log('[WORKLIST-SSE]', data);
fetchWorklist();
if (data.type === 'missed-call') {
const name = data.callerName ?? data.callerPhone ?? 'Unknown';
notify.warning('Missed Call', `${name} — needs callback`);
}
} catch {}
};
es.onerror = () => {
console.warn('[WORKLIST-SSE] Connection error — EventSource will auto-reconnect');
};
} catch {}
return () => { es?.close(); };
}, [fetchWorklist]);
return { ...data, loading, error, refresh: fetchWorklist };