Files
helix-engage/src/hooks/use-network-status.ts
saridsa2 daa2fbb0c2 fix: SIP driven by Agent entity, token refresh, network indicator
- SIP connection only for users with Agent entity (no env var fallback)
- Supervisor no longer intercepts CC agent calls
- Auth controller checks Agent entity for ALL roles, not just cc-agent
- Token refresh handles GraphQL UNAUTHENTICATED errors (200 with error body)
- Token refresh handles sidecar 400s from expired upstream tokens
- Network quality indicator in sidebar (offline/unstable/good)
- Ozonetel IDLE event mapped to ready state (fixes stuck calling after canceled call)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:44:48 +05:30

47 lines
1.5 KiB
TypeScript

import { useState, useEffect, useRef } from 'react';
export type NetworkQuality = 'good' | 'unstable' | 'offline';
export const useNetworkStatus = (): NetworkQuality => {
const [quality, setQuality] = useState<NetworkQuality>(navigator.onLine ? 'good' : 'offline');
const dropCountRef = useRef(0);
const resetTimerRef = useRef<number | null>(null);
useEffect(() => {
const handleOffline = () => {
console.log('[NETWORK] Offline');
setQuality('offline');
};
const handleOnline = () => {
console.log('[NETWORK] Back online');
dropCountRef.current++;
// 3+ drops in 2 minutes = unstable
if (dropCountRef.current >= 3) {
setQuality('unstable');
} else {
setQuality('good');
}
// Reset drop counter after 2 minutes of stability
if (resetTimerRef.current) clearTimeout(resetTimerRef.current);
resetTimerRef.current = window.setTimeout(() => {
dropCountRef.current = 0;
if (navigator.onLine) setQuality('good');
}, 120000);
};
window.addEventListener('offline', handleOffline);
window.addEventListener('online', handleOnline);
return () => {
window.removeEventListener('offline', handleOffline);
window.removeEventListener('online', handleOnline);
if (resetTimerRef.current) clearTimeout(resetTimerRef.current);
};
}, []);
return quality;
};