import { createContext, useContext, useEffect, useRef, useState } from 'react'; type WebSocketContextType = { ws: WebSocket | null; sendMessage: (message: any) => void; messages: any[]; isConnected: boolean; }; const WebSocketContext = createContext(null); export const useWebSocket = () => { const context = useContext(WebSocketContext); if (!context) { throw new Error('useWebSocket must be used within a WebSocketProvider'); } return context; }; const useWebSocketProviderState = () => { const wsRef = useRef(null); const unmountedRef = useRef(false); const [messages, setMessages] = useState([]); const [isConnected, setIsConnected] = useState(false); const reconnectTimeoutRef = useRef(null); useEffect(() => { connect(); return () => { unmountedRef.current = true; if (reconnectTimeoutRef.current) { clearTimeout(reconnectTimeoutRef.current); } if (wsRef.current) { wsRef.current.close(); } }; }, []); // Keep dependency array but add proper cleanup const connect = () => { if (unmountedRef.current) return; // Prevent connection if unmounted try { const isPlatform = import.meta.env.VITE_IS_PLATFORM === 'true'; // Construct WebSocket URL let wsUrl: string; const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; if (isPlatform) { // Platform mode: Use same domain as the page (goes through proxy) wsUrl = `${protocol}//${window.location.host}/ws`; } else { // OSS mode: Connect to same host:port that served the page const token = localStorage.getItem('auth-token'); if (!token) { console.warn('No authentication token found for WebSocket connection'); return; } wsUrl = `${protocol}//${window.location.host}/ws?token=${encodeURIComponent(token)}`; } const websocket = new WebSocket(wsUrl); websocket.onopen = () => { setIsConnected(true); wsRef.current = websocket; }; websocket.onmessage = (event) => { try { const data = JSON.parse(event.data); setMessages(prev => [...prev, data]); } catch (error) { console.error('Error parsing WebSocket message:', error); } }; websocket.onclose = () => { setIsConnected(false); wsRef.current = null; // Attempt to reconnect after 3 seconds reconnectTimeoutRef.current = setTimeout(() => { if (unmountedRef.current) return; // Prevent reconnection if unmounted connect(); }, 3000); }; websocket.onerror = (error) => { console.error('WebSocket error:', error); }; } catch (error) { console.error('Error creating WebSocket connection:', error); } }; const sendMessage = (message: any) => { const socket = wsRef.current; if (socket && isConnected) { socket.send(JSON.stringify(message)); } else { console.warn('WebSocket not connected'); } }; return { ws: wsRef.current, sendMessage, messages, isConnected }; }; export const WebSocketProvider = ({ children }: { children: React.ReactNode }) => { const webSocketData = useWebSocketProviderState(); return ( {children} ); }; export default WebSocketContext;