mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-12 02:38:15 +00:00
feat: SSE agent state, UCID fix, maint module, QA bug fixes
- Fix outbound disposition: store UCID from dial API response (root cause of silent disposition failure) - SSE agent state: real-time Ozonetel state drives status toggle (ready/break/calling/in-call/acw) - Maint module with OTP-protected endpoints (force-ready, unlock-agent, backfill, fix-timestamps) - Maint OTP modal with PinInput component, keyboard shortcuts (Ctrl+Shift+R/U/B/T) - Force-logout via SSE: admin unlock pushes force-logout to connected browsers - Silence JsSIP debug flood, add structured lifecycle logging ([SIP], [DIAL], [DISPOSE], [AGENT-STATE]) - Centralize date formatting with IST-aware formatters across 11 files - Fix call history: non-overlapping aggregates (completed/missed), correct timestamp display - Auto-dismiss CallWidget ended/failed state after 3 seconds - Remove floating "Helix Phone" idle badge from all pages - Fix dead code in agent-state endpoint (auto-assign was unreachable after return) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useRef } from 'react';
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faPhone, faPhoneHangup, faMicrophone, faMicrophoneSlash,
|
||||
@@ -52,6 +52,11 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
|
||||
// Track if the call was ever answered (reached 'active' state)
|
||||
const wasAnsweredRef = useRef(callState === 'active');
|
||||
|
||||
// Log mount so we can tell which component handled the call
|
||||
useEffect(() => {
|
||||
console.log(`[ACTIVE-CALL-CARD] Mounted: state=${callState} direction=${callDirectionRef.current} ucid=${callUcid ?? 'none'} lead=${lead?.id ?? 'none'} phone=${callerPhone}`);
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const firstName = lead?.contactName?.firstName ?? '';
|
||||
const lastName = lead?.contactName?.lastName ?? '';
|
||||
const fullName = `${firstName} ${lastName}`.trim();
|
||||
@@ -62,7 +67,7 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
|
||||
|
||||
// Submit disposition to sidecar — handles Ozonetel ACW release
|
||||
if (callUcid) {
|
||||
apiClient.post('/api/ozonetel/dispose', {
|
||||
const disposePayload = {
|
||||
ucid: callUcid,
|
||||
disposition,
|
||||
callerPhone,
|
||||
@@ -71,7 +76,13 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
|
||||
leadId: lead?.id ?? null,
|
||||
notes,
|
||||
missedCallId: missedCallId ?? undefined,
|
||||
}).catch((err) => console.warn('Disposition failed:', err));
|
||||
};
|
||||
console.log('[DISPOSE] Sending disposition:', JSON.stringify(disposePayload));
|
||||
apiClient.post('/api/ozonetel/dispose', disposePayload)
|
||||
.then((res) => console.log('[DISPOSE] Response:', JSON.stringify(res)))
|
||||
.catch((err) => console.error('[DISPOSE] Failed:', err));
|
||||
} else {
|
||||
console.warn('[DISPOSE] No callUcid — skipping disposition');
|
||||
}
|
||||
|
||||
// Side effects per disposition type
|
||||
|
||||
Reference in New Issue
Block a user