From a895a3ab18c12851355edf14ae225c8ff0f2b983 Mon Sep 17 00:00:00 2001 From: nutcas3 Date: Sun, 19 Apr 2026 05:04:11 +0300 Subject: [PATCH] feat: Add WebSocket React hooks with typed message subscriptions and connection management - Add useWebSocket generic hook with message type subscription, connection status monitoring, error handling, and automatic cleanup - Add useServiceUpdates, useSystemMetrics, useAlertUpdates hooks for typed WebSocket message subscriptions - Add useWebSocketConnection hook with connection status monitoring, manual reconnect capability, and reconnect attempt tracking - Add 1s interval connection status polling --- apps/web-dashboard/src/hooks/use-websocket.ts | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 apps/web-dashboard/src/hooks/use-websocket.ts diff --git a/apps/web-dashboard/src/hooks/use-websocket.ts b/apps/web-dashboard/src/hooks/use-websocket.ts new file mode 100644 index 0000000..eb60129 --- /dev/null +++ b/apps/web-dashboard/src/hooks/use-websocket.ts @@ -0,0 +1,80 @@ +import { useEffect, useState, useRef, useCallback } from "react"; +import { getWebSocketService, WebSocketMessage, ServiceUpdate, SystemMetrics, AlertUpdate } from "@/lib/websocket"; + +export function useWebSocket(messageType: string) { + const [data, setData] = useState(null); + const [isConnected, setIsConnected] = useState(false); + const [error, setError] = useState(null); + const unsubscribeRef = useRef<(() => void) | null>(null); + + useEffect(() => { + const wsService = getWebSocketService(); + + // Subscribe to the specific message type + const unsubscribe = wsService.subscribe(messageType, (messageData: T) => { + setData(messageData); + setError(null); + }); + + unsubscribeRef.current = unsubscribe; + + // Set up connection status monitoring + const checkConnection = () => { + setIsConnected(wsService.isConnected()); + }; + + const interval = setInterval(checkConnection, 1000); + + return () => { + if (unsubscribeRef.current) { + unsubscribeRef.current(); + } + clearInterval(interval); + }; + }, [messageType]); + + return { data, isConnected, error }; +} + +export function useServiceUpdates() { + return useWebSocket('service_update'); +} + +export function useSystemMetrics() { + return useWebSocket('system_metrics'); +} + +export function useAlertUpdates() { + return useWebSocket('alert_update'); +} + +export function useWebSocketConnection() { + const [isConnected, setIsConnected] = useState(false); + const [reconnectAttempts, setReconnectAttempts] = useState(0); + + useEffect(() => { + const wsService = getWebSocketService(); + + const checkConnection = () => { + setIsConnected(wsService.isConnected()); + }; + + const interval = setInterval(checkConnection, 1000); + + return () => { + clearInterval(interval); + }; + }, []); + + const reconnect = useCallback(() => { + // Force reconnection by disconnecting and reconnecting + const wsService = getWebSocketService(); + wsService.disconnect(); + setTimeout(() => { + const newService = getWebSocketService(); + setReconnectAttempts(prev => prev + 1); + }, 1000); + }, []); + + return { isConnected, reconnect, reconnectAttempts }; +}