diff --git a/src/providers/sip-provider.tsx b/src/providers/sip-provider.tsx index 467279b..29b6076 100644 --- a/src/providers/sip-provider.tsx +++ b/src/providers/sip-provider.tsx @@ -1,25 +1,106 @@ -import { createContext, useContext, useEffect, useRef, type PropsWithChildren } from 'react'; +import { createContext, useContext, useEffect, useRef, useState, type PropsWithChildren } from 'react'; import { useSipPhone } from '@/hooks/use-sip-phone'; -type SipContextType = ReturnType; +const SIDECAR_URL = import.meta.env.VITE_SIDECAR_URL ?? 'http://localhost:4100'; + +type SipContextType = ReturnType & { + ozonetelStatus: 'idle' | 'logging-in' | 'logged-in' | 'error'; + ozonetelError: string | null; +}; const SipContext = createContext(null); export const SipProvider = ({ children }: PropsWithChildren) => { const sipPhone = useSipPhone(); const hasConnected = useRef(false); + const [ozonetelStatus, setOzonetelStatus] = useState<'idle' | 'logging-in' | 'logged-in' | 'error'>('idle'); + const [ozonetelError, setOzonetelError] = useState(null); - // Auto-connect on mount — skip StrictMode double-fire + // Auto-connect SIP + login to Ozonetel on mount useEffect(() => { if (!hasConnected.current) { hasConnected.current = true; + + // 1. Connect SIP (WebSocket → Ozonetel SIP server) sipPhone.connect(); + + // 2. Login agent to Ozonetel's routing system + // Try sidecar first, fallback to direct Ozonetel API call + const sipId = (import.meta.env.VITE_SIP_URI ?? '').replace('sip:', '').split('@')[0]; + const agentId = import.meta.env.VITE_OZONETEL_AGENT_ID ?? 'Agent3'; + const agentPassword = import.meta.env.VITE_OZONETEL_AGENT_PASSWORD ?? 'Test123$'; + const accountId = import.meta.env.VITE_OZONETEL_ACCOUNT_ID ?? 'global_demo'; + const apiKey = import.meta.env.VITE_OZONETEL_API_KEY ?? ''; + + if (sipId) { + setOzonetelStatus('logging-in'); + + const loginViaOzonetelDirect = async () => { + const params = new URLSearchParams({ + userName: accountId, + apiKey: apiKey, + phoneNumber: sipId, + action: 'login', + mode: 'blended', + state: 'Ready', + }); + + const response = await fetch( + `https://in1-ccaas-api.ozonetel.com/CAServices/AgentAuthenticationV2/index.php`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization': 'Basic ' + btoa(`${agentId}:${agentPassword}`), + }, + body: params.toString(), + }, + ); + return response.json(); + }; + + const loginViaSidecar = async () => { + const response = await fetch(`${SIDECAR_URL}/api/ozonetel/agent-login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + agentId, + password: agentPassword, + phoneNumber: sipId, + mode: 'blended', + }), + }); + return response.json(); + }; + + // Try sidecar first, fallback to direct + loginViaSidecar() + .catch(() => loginViaOzonetelDirect()) + .then(data => { + if (data.status === 'success' || data.message?.includes('logged in')) { + setOzonetelStatus('logged-in'); + console.log('Ozonetel agent login:', data.message); + } else { + setOzonetelStatus('error'); + setOzonetelError(data.message ?? 'Unknown error'); + console.warn('Ozonetel agent login issue:', data); + } + }) + .catch(err => { + setOzonetelStatus('error'); + setOzonetelError(err.message); + console.error('Ozonetel agent login failed:', err); + }); + } } - // Do NOT disconnect on cleanup — the SIP connection should persist // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - return {children}; + return ( + + {children} + + ); }; export const useSip = (): SipContextType => {