mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-05-18 20:08:19 +00:00
feat: call-desk refresh — disposition modal, active-call UI, worklist + perf updates
- Call-desk: active-call-card supervisor presence badges, incoming-call-card polish, transfer-dialog, call-log - Disposition modal: auto-lock based on actions taken, not-interested split - Forms: appointment-form + enquiry-form improvements (placeholder handling, phone format) - Worklist-panel: pagination awareness, filter chips - Pages: all-leads/patients/patient-360/missed-calls/team-performance/call-history/appointments polish - SIP: sip-client reconnect, sip-provider + sip-manager state, agent-status-toggle spinner - Hooks: use-agent-state supervisor SSE events, use-worklist, use-performance-alerts - Types: entities.ts extended Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faCircle, faChevronDown } from '@fortawesome/pro-duotone-svg-icons';
|
||||
import { faCircle, faChevronDown, faSpinnerThird } from '@fortawesome/pro-duotone-svg-icons';
|
||||
import { useAgentState } from '@/hooks/use-agent-state';
|
||||
import type { OzonetelState } from '@/hooks/use-agent-state';
|
||||
import { apiClient } from '@/lib/api-client';
|
||||
@@ -50,6 +50,15 @@ export const AgentStatusToggle = ({ isRegistered, connectionStatus }: AgentStatu
|
||||
console.log('[AGENT-STATE] Ready response:', JSON.stringify(res));
|
||||
} else {
|
||||
const pauseReason = newStatus === 'break' ? 'Break' : 'Training';
|
||||
// Ozonetel rejects Pause→Pause (Break↔Training) — the agent must
|
||||
// transit through Ready. Insert a Ready hop whenever we're
|
||||
// moving between two paused sub-states.
|
||||
const isPauseToPause = ozonetelState === 'break' || ozonetelState === 'training';
|
||||
if (isPauseToPause) {
|
||||
console.log(`[AGENT-STATE] ${ozonetelState}→${newStatus}: sending Ready first, then Pause(${pauseReason})`);
|
||||
await apiClient.post('/api/ozonetel/agent-state', { agentId, state: 'Ready' });
|
||||
await new Promise(resolve => setTimeout(resolve, 400));
|
||||
}
|
||||
console.log(`[AGENT-STATE] Changing to Pause: ${pauseReason}`);
|
||||
const res = await apiClient.post('/api/ozonetel/agent-state', { agentId, state: 'Pause', pauseReason });
|
||||
console.log('[AGENT-STATE] Pause response:', JSON.stringify(res));
|
||||
@@ -89,13 +98,18 @@ export const AgentStatusToggle = ({ isRegistered, connectionStatus }: AgentStatu
|
||||
disabled={changing || !canToggle}
|
||||
className={cx(
|
||||
'flex items-center gap-1.5 rounded-full bg-secondary px-3 py-1 transition duration-100 ease-linear',
|
||||
canToggle ? 'hover:bg-secondary_hover cursor-pointer' : 'cursor-default',
|
||||
changing && 'opacity-50',
|
||||
canToggle && !changing ? 'hover:bg-secondary_hover cursor-pointer' : 'cursor-default',
|
||||
)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faCircle} className={cx('size-2', current.dotColor)} />
|
||||
<span className={cx('text-xs font-medium', current.color)}>{current.label}</span>
|
||||
{canToggle && <FontAwesomeIcon icon={faChevronDown} className="size-2.5 text-fg-quaternary" />}
|
||||
{changing ? (
|
||||
<FontAwesomeIcon icon={faSpinnerThird} spin className="size-2.5 text-fg-brand-primary" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCircle} className={cx('size-2', current.dotColor)} />
|
||||
)}
|
||||
<span className={cx('text-xs font-medium', changing ? 'text-brand-secondary' : current.color)}>
|
||||
{changing ? 'Changing…' : current.label}
|
||||
</span>
|
||||
{canToggle && !changing && <FontAwesomeIcon icon={faChevronDown} className="size-2.5 text-fg-quaternary" />}
|
||||
</button>
|
||||
|
||||
{menuOpen && (
|
||||
|
||||
Reference in New Issue
Block a user