From 416746c4a7f463c53eb63ad091480d291b81bc60 Mon Sep 17 00:00:00 2001 From: Aditya8369 Date: Sat, 6 Jun 2026 15:45:43 +0530 Subject: [PATCH] Real-time referral message updates in UI --- backend/utils/socket.js | 30 ++++++++++++++++ frontend/src/App.jsx | 9 +++-- frontend/src/SocketContext.jsx | 41 ++++++++++++++++++++++ frontend/src/components/ReferralDetail.jsx | 24 +++++++++++++ 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/backend/utils/socket.js b/backend/utils/socket.js index 994316b..eaa0fb6 100644 --- a/backend/utils/socket.js +++ b/backend/utils/socket.js @@ -316,6 +316,36 @@ const initializeSocket = (io) => { } }); + // ===== REFERRAL: JOIN/LEAVE ROOMS ===== + socket.on('joinReferral', (data) => { + try { + const { referralId } = data || {}; + if (!referralId) { + socket.emit('error', { message: 'referralId is required' }); + return; + } + + const roomId = `referral:${referralId}`; + socket.join(roomId); + console.log(`Socket ${socket.id} joined referral room ${roomId}`); + } catch (error) { + console.error('Error in joinReferral:', error); + } + }); + + socket.on('leaveReferral', (data) => { + try { + const { referralId } = data || {}; + if (!referralId) return; + + const roomId = `referral:${referralId}`; + socket.leave(roomId); + console.log(`Socket ${socket.id} left referral room ${roomId}`); + } catch (error) { + console.error('Error in leaveReferral:', error); + } + }); + // ===== DISCONNECT HANDLER ===== socket.on('disconnect', () => { try { diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 4765d0e..e2f8809 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -4,6 +4,7 @@ import { BrowserRouter, Routes, Route, useLocation } from "react-router-dom"; import { ToastContainer } from "react-toastify"; import { AuthProvider, useAuth } from "./AuthContext"; import { ThemeProvider } from "./ThemeContext"; +import { SocketProvider } from "./SocketContext"; import ScrollToTop from "./components/ScrollToTop"; import SmoothWheelScroll from "./components/SmoothWheelScroll"; import PrivateRoute from "./components/PrivateRoute"; @@ -77,9 +78,11 @@ function App() { - - - + + + + + diff --git a/frontend/src/SocketContext.jsx b/frontend/src/SocketContext.jsx index 334060b..f93edc1 100644 --- a/frontend/src/SocketContext.jsx +++ b/frontend/src/SocketContext.jsx @@ -98,6 +98,29 @@ export const SocketProvider = ({ children }) => { console.log(`Left conversation: ${conversationId}`); }, [socket]); + /** + * Join a referral room + */ + const joinReferral = useCallback((referralId) => { + if (!socket || !isConnected) { + console.warn('Socket not connected'); + return; + } + + socket.emit('joinReferral', { referralId }); + console.log(`Joined referral room: referral:${referralId}`); + }, [socket, isConnected]); + + /** + * Leave a referral room + */ + const leaveReferral = useCallback((referralId) => { + if (!socket) return; + + socket.emit('leaveReferral', { referralId }); + console.log(`Left referral room: referral:${referralId}`); + }, [socket]); + /** * Mark messages as read */ @@ -242,6 +265,8 @@ export const SocketProvider = ({ children }) => { typingUsers, joinConversation, leaveConversation, + joinReferral, + leaveReferral, markAsRead, addReaction, removeReaction, @@ -260,6 +285,8 @@ export const SocketProvider = ({ children }) => { typingUsers, joinConversation, leaveConversation, + joinReferral, + leaveReferral, markAsRead, addReaction, removeReaction, @@ -289,4 +316,18 @@ export const useSocket = () => { return context; }; +/** + * Hook to listen to a socket event + */ +export const useSocketListener = (event, callback) => { + const { on } = useSocket(); + + useEffect(() => { + const cleanup = on(event, callback); + return () => { + if (cleanup) cleanup(); + }; + }, [event, callback, on]); +}; + export default SocketContext; diff --git a/frontend/src/components/ReferralDetail.jsx b/frontend/src/components/ReferralDetail.jsx index 31c74f8..038fd47 100644 --- a/frontend/src/components/ReferralDetail.jsx +++ b/frontend/src/components/ReferralDetail.jsx @@ -3,12 +3,36 @@ import { useParams, Link, useNavigate } from 'react-router-dom'; import apiClient from '../api/client'; import { useAuth } from '../AuthContext'; import { toast } from 'react-toastify'; +import { useSocket, useSocketListener } from '../SocketContext'; const ReferralDetail = () => { const { id } = useParams(); const navigate = useNavigate(); const { isAuthReady, user: authUser } = useAuth(); const [referral, setReferral] = useState(null); + + const { joinReferral, leaveReferral } = useSocket(); + + useEffect(() => { + if (id) { + joinReferral(id); + return () => { + leaveReferral(id); + }; + } + }, [id, joinReferral, leaveReferral]); + + useSocketListener('referralMessageCreated', (payload) => { + if (payload && String(payload.referralId) === String(id)) { + setMessages((prevMessages) => { + const messageExists = prevMessages.some((msg) => msg._id === payload.message?._id); + if (messageExists) { + return prevMessages; + } + return [...prevMessages, payload.message]; + }); + } + }); const [timeline, setTimeline] = useState([]); const [messages, setMessages] = useState([]); const [messageBody, setMessageBody] = useState('');