/* eslint-disable @typescript-eslint/no-explicit-any */ import React, { createContext, useContext, ReactNode, useEffect, useState, useRef, useCallback, } from "react"; import { getChatConfig } from "../Chat.config"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; interface ChatProviderProps { userId: string; children: ReactNode; } interface ChatContextType { socket: WebSocket | null; userId: string; // onlineUsers: any[]; sendMessage: (data: any) => void; isConnected: boolean; onlineUsers: Set; // Change to Set for better performance isUserOnline: (userId: string) => boolean; // Add helper function } const ChatContext = createContext(null); const queryClient = new QueryClient(); export const ChatProvider: React.FC = ({ userId, children, }) => { const socketRef = useRef(null); const [socket, setSocket] = useState(null); // const [onlineUsers, setOnlineUsers] = useState([]); const [onlineUsers, setOnlineUsers] = useState>(new Set()); const [isConnected, setIsConnected] = useState(false); const reconnectAttempts = useRef(0); const maxReconnectAttempts = 5; const reconnectInterval = 5000; // 5 seconds const { webSocketUrl,role } = getChatConfig(); const connectWebSocket = useCallback(() => { // console.log("🔌 Creating new WebSocket connection..."); // Convert HTTP URL to WebSocket URL const wsUrl = webSocketUrl.replace(/^http:/, "ws:").replace(/^https:/, "wss:"); const socketInstance = new WebSocket( `${wsUrl}?userId=${encodeURIComponent(userId)}&role=${encodeURIComponent(role)}` ); socketInstance.onopen = () => { // console.log("✅ WebSocket connected"); setIsConnected(true); reconnectAttempts.current = 0; // Send initial handshake if needed socketInstance.send( JSON.stringify({ event: "handshake", userId: userId, role: role, }) ); }; socketInstance.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.event === "getOnlineUsers") { // console.log("Online users update:", data.data); setOnlineUsers(new Set(data.data)); } // Handle other message types here // console.log("Received message:", data); } catch (error) { console.error("Error parsing message:", error); } }; socketInstance.onerror = (error) => { console.error("❌ WebSocket error:", error); }; socketInstance.onclose = () => { // console.log("🔌 WebSocket connection closed", event); // console.log("❌ WebSocket disconnected:", event.code, event.reason); setIsConnected(false); // Attempt reconnection if (reconnectAttempts.current < maxReconnectAttempts) { reconnectAttempts.current += 1; // console.log( // `Attempting to reconnect (${reconnectAttempts.current}/${maxReconnectAttempts})...` // ); setTimeout(connectWebSocket, reconnectInterval); } }; socketRef.current = socketInstance; setSocket(socketInstance); }, [webSocketUrl, userId]); const sendMessage = useCallback((data: any) => { if (socketRef.current?.readyState === WebSocket.OPEN) { socketRef.current.send(JSON.stringify(data)); } else { console.error("Cannot send message - WebSocket not connected"); } }, []); // useEffect(() => { // connectWebSocket(); // return () => { // // console.log("❌ Closing WebSocket connection..."); // if (socketRef.current) { // socketRef.current.close(1000, "Component unmounted"); // socketRef.current = null; // } // }; // }, [connectWebSocket]); useEffect(() => { connectWebSocket(); return () => { // Gracefully notify backend before closing if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) { socketRef.current.send( JSON.stringify({ event: "disconnect", userId, role, }) ); socketRef.current.close(1000, "Component unmounted"); } socketRef.current = null; }; }, [connectWebSocket]); const isUserOnline = useCallback( (userId: string) => { return onlineUsers.has(userId); }, [onlineUsers] ); return ( {children} ); }; export const useChatContext = () => { const context = useContext(ChatContext); if (!context) { throw new Error("useChatContext must be used within a ChatProvider"); } return context; };