diff --git a/frontend/src/hooks/useWebSocket.ts b/frontend/src/hooks/useWebSocket.ts new file mode 100644 index 0000000..688a0fe --- /dev/null +++ b/frontend/src/hooks/useWebSocket.ts @@ -0,0 +1,67 @@ +import { useEffect, useRef, useState, useCallback } from 'react'; +import { WebSocketMessage } from '../types'; + +export function useWebSocket(url: string) { + const [isConnected, setIsConnected] = useState(false); + const [lastMessage, setLastMessage] = useState(null); + const wsRef = useRef(null); + const reconnectTimer = useRef | null>(null); + + const connect = useCallback(() => { + try { + const ws = new WebSocket(url); + + ws.onopen = () => { + console.log('WebSocket connected'); + setIsConnected(true); + }; + + ws.onmessage = (event) => { + try { + const message: WebSocketMessage = JSON.parse(event.data); + setLastMessage(message); + } catch (error) { + console.error('Failed to parse WebSocket message:', error); + } + }; + + ws.onerror = (error) => { + console.error('WebSocket error:', error); + setIsConnected(false); + }; + + ws.onclose = () => { + console.log('WebSocket disconnected'); + setIsConnected(false); + // Schedule reconnect after 3000ms + reconnectTimer.current = setTimeout(() => { + console.log('Attempting to reconnect...'); + connect(); + }, 3000); + }; + + wsRef.current = ws; + } catch (error) { + console.error('Failed to create WebSocket:', error); + setIsConnected(false); + } + }, [url]); + + useEffect(() => { + connect(); + + return () => { + // Cleanup: close ws and clear reconnect timer + if (wsRef.current) { + wsRef.current.close(); + wsRef.current = null; + } + if (reconnectTimer.current) { + clearTimeout(reconnectTimer.current); + reconnectTimer.current = null; + } + }; + }, [connect]); + + return { isConnected, lastMessage }; +}