import { useEffect, type ReactNode } from 'react'; import { useLocation } from 'react-router'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faWifi, faWifiSlash } from '@fortawesome/pro-duotone-svg-icons'; import { Sidebar } from './sidebar'; import { SipProvider } from '@/providers/sip-provider'; import { useSip } from '@/providers/sip-provider'; import { CallWidget } from '@/components/call-desk/call-widget'; import { MaintOtpModal } from '@/components/modals/maint-otp-modal'; import { ClearCampaignLeadsModal } from '@/components/modals/clear-campaign-leads-modal'; import { AgentStatusToggle } from '@/components/call-desk/agent-status-toggle'; import { NotificationBell } from './notification-bell'; import { useAuth } from '@/providers/auth-provider'; import { useMaintShortcuts } from '@/hooks/use-maint-shortcuts'; import { useNetworkStatus } from '@/hooks/use-network-status'; import { cx } from '@/utils/cx'; interface AppShellProps { children: ReactNode; } export const AppShell = ({ children }: AppShellProps) => { const { pathname } = useLocation(); const { isCCAgent, isAdmin } = useAuth(); const { isOpen, activeAction, close } = useMaintShortcuts(); const { connectionStatus, isRegistered } = useSip(); const networkQuality = useNetworkStatus(); const hasAgentConfig = !!localStorage.getItem('helix_agent_config'); // Heartbeat: keep agent session alive in Redis (CC agents only) useEffect(() => { if (!isCCAgent) return; const beat = () => { const token = localStorage.getItem('helix_access_token'); if (token) { const apiUrl = import.meta.env.VITE_API_URL ?? 'http://localhost:4100'; fetch(`${apiUrl}/auth/heartbeat`, { method: 'POST', headers: { Authorization: `Bearer ${token}` }, }).catch(() => {}); } }; const interval = setInterval(beat, 5 * 60 * 1000); return () => clearInterval(interval); }, [isCCAgent]); return (
{/* Persistent top bar — visible on all pages */} {(hasAgentConfig || isAdmin) && (
{isAdmin && } {hasAgentConfig && ( <>
{networkQuality === 'good' ? 'Connected' : networkQuality === 'offline' ? 'No connection' : 'Unstable'}
)}
)}
{children}
{isCCAgent && pathname !== '/' && pathname !== '/call-desk' && }
!open && close()} action={activeAction} /> !open && close()} />
); };