Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions backend/utils/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -77,9 +78,11 @@ function App() {
<BrowserRouter>
<ThemeProvider>
<AuthProvider>
<ScrollToTop />
<SmoothWheelScroll />
<AppRouter />
<SocketProvider>
<ScrollToTop />
<SmoothWheelScroll />
<AppRouter />
</SocketProvider>
</AuthProvider>
</ThemeProvider>
</BrowserRouter>
Expand Down
41 changes: 41 additions & 0 deletions frontend/src/SocketContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -242,6 +265,8 @@ export const SocketProvider = ({ children }) => {
typingUsers,
joinConversation,
leaveConversation,
joinReferral,
leaveReferral,
markAsRead,
addReaction,
removeReaction,
Expand All @@ -260,6 +285,8 @@ export const SocketProvider = ({ children }) => {
typingUsers,
joinConversation,
leaveConversation,
joinReferral,
leaveReferral,
markAsRead,
addReaction,
removeReaction,
Expand Down Expand Up @@ -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;
24 changes: 24 additions & 0 deletions frontend/src/components/ReferralDetail.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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('');
Expand Down
Loading