mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-05-18 20:08:19 +00:00
feat(frontend): supervisor presence indicator on agent call card
- useAgentState hook returns { state, supervisorPresence }
- SSE events: supervisor-whisper → "Supervisor coaching" (blue badge)
supervisor-barge → "Supervisor on call" (brand badge)
supervisor-left → badge disappears
- Listen mode is silent — no badge shown
- Updated call sites: sidebar.tsx, agent-status-toggle.tsx destructure
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ import { EnquiryForm } from './enquiry-form';
|
||||
import { formatPhone } from '@/lib/format';
|
||||
import { apiClient } from '@/lib/api-client';
|
||||
import { useAuth } from '@/providers/auth-provider';
|
||||
import { useAgentState } from '@/hooks/use-agent-state';
|
||||
import { cx } from '@/utils/cx';
|
||||
import { notify } from '@/lib/toast';
|
||||
import type { Lead, CallDisposition } from '@/types/entities';
|
||||
@@ -49,6 +50,10 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
|
||||
const [callerDisconnected, setCallerDisconnected] = useState(false);
|
||||
const [suggestedDisposition, setSuggestedDisposition] = useState<CallDisposition | null>(null);
|
||||
|
||||
const agentConfig = localStorage.getItem('helix_agent_config');
|
||||
const agentIdForState = agentConfig ? (() => { try { return JSON.parse(agentConfig).ozonetelAgentId; } catch { return null; } })() : null;
|
||||
const { supervisorPresence } = useAgentState(agentIdForState);
|
||||
|
||||
const callDirectionRef = useRef(callState === 'ringing-out' ? 'OUTBOUND' : 'INBOUND');
|
||||
const wasAnsweredRef = useRef(callState === 'active');
|
||||
|
||||
@@ -235,7 +240,15 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
|
||||
{fullName && <p className="text-xs text-tertiary">{phoneDisplay}</p>}
|
||||
</div>
|
||||
</div>
|
||||
<Badge size="md" color="success" type="pill-color">{formatDuration(callDuration)}</Badge>
|
||||
<div className="flex items-center gap-2">
|
||||
{supervisorPresence === 'whisper' && (
|
||||
<Badge size="sm" color="blue" type="pill-color">Supervisor coaching</Badge>
|
||||
)}
|
||||
{supervisorPresence === 'barge' && (
|
||||
<Badge size="sm" color="brand" type="pill-color">Supervisor on call</Badge>
|
||||
)}
|
||||
<Badge size="md" color="success" type="pill-color">{formatDuration(callDuration)}</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Call controls */}
|
||||
|
||||
@@ -33,7 +33,7 @@ type AgentStatusToggleProps = {
|
||||
export const AgentStatusToggle = ({ isRegistered, connectionStatus }: AgentStatusToggleProps) => {
|
||||
const agentConfig = localStorage.getItem('helix_agent_config');
|
||||
const agentId = agentConfig ? JSON.parse(agentConfig).ozonetelAgentId : null;
|
||||
const ozonetelState = useAgentState(agentId);
|
||||
const { state: ozonetelState } = useAgentState(agentId);
|
||||
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const [changing, setChanging] = useState(false);
|
||||
|
||||
@@ -132,7 +132,7 @@ export const Sidebar = ({ activeUrl = "/" }: SidebarProps) => {
|
||||
const [collapsed, setCollapsed] = useAtom(sidebarCollapsedAtom);
|
||||
const agentConfig = typeof window !== 'undefined' ? localStorage.getItem('helix_agent_config') : null;
|
||||
const agentId = agentConfig ? (() => { try { return JSON.parse(agentConfig).ozonetelAgentId; } catch { return null; } })() : null;
|
||||
const ozonetelState = useAgentState(agentId);
|
||||
const { state: ozonetelState } = useAgentState(agentId);
|
||||
const avatarStatus: 'online' | 'offline' = ozonetelState === 'ready' ? 'online' : 'offline';
|
||||
|
||||
const width = collapsed ? COLLAPSED_WIDTH : EXPANDED_WIDTH;
|
||||
|
||||
Reference in New Issue
Block a user