fix: pass client_id to exclude sender from WebSocket broadcast

The backend uses client_id to identify the sender and exclude them
from receiving their own message via WebSocket (avoiding duplication
with optimistic update).

Changes:
- rest.js: Add clientId parameter to sendChatMessage
- sessionChatSlice.js: Pass clientId to API call
- JKChatComposer.js: Get server.clientId from context and pass it

This fixes: Messages now broadcast to OTHER users in session, not
just the sender. The sender sees optimistic update immediately, other
users receive via WebSocket.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-02-01 22:16:01 +05:30
parent 939225a610
commit 5132c83458
3 changed files with 12 additions and 7 deletions

View File

@ -36,8 +36,8 @@ const JKChatComposer = ({ textareaRef }) => {
const sendStatus = useSelector(selectSendStatus);
const sendError = useSelector(selectSendError);
// WebSocket connection status
const { isConnected } = useJamServerContext();
// WebSocket connection status and client ID
const { isConnected, server } = useJamServerContext();
// Current user for optimistic updates
const { currentUser } = useAuth();
@ -86,13 +86,14 @@ const JKChatComposer = ({ textareaRef }) => {
message: trimmedText,
optimisticId: uuid(),
userId: currentUser.id,
userName: currentUser.name
userName: currentUser.name,
clientId: server?.clientId
})
);
// Clear input on success
setInputText('');
}, [canSend, dispatch, sessionId, trimmedText, currentUser]);
}, [canSend, dispatch, sessionId, trimmedText, currentUser, server?.clientId]);
const handleKeyDown = useCallback(
e => {

View File

@ -986,11 +986,13 @@ export const getChatMessages = async ({ channel, sessionId, before }) => {
* @param {string} params.channel - Channel type ('session', 'global', 'lesson')
* @param {string} [params.sessionId] - Session ID (required for session channel)
* @param {string} params.message - Message content
* @param {string} [params.clientId] - Client ID (used by backend to exclude sender from WebSocket broadcast)
* @returns {Promise<{message: Object}>} Created message object
*/
export const sendChatMessage = async ({ channel, sessionId, message }) => {
export const sendChatMessage = async ({ channel, sessionId, message, clientId }) => {
const body = { channel, message };
if (sessionId) body.music_session = sessionId;
if (clientId) body.client_id = clientId;
const baseUrl = process.env.REACT_APP_API_BASE_URL;
const response = await fetch(`${baseUrl}/chat`, {

View File

@ -30,14 +30,16 @@ export const fetchChatHistory = createAsyncThunk(
* @param {string} params.optimisticId - Temporary ID for optimistic update
* @param {string} params.userId - Current user ID
* @param {string} params.userName - Current user name
* @param {string} [params.clientId] - WebSocket client ID (used to exclude sender from broadcast)
*/
export const sendMessage = createAsyncThunk(
'sessionChat/sendMessage',
async ({ channel, sessionId, message }) => {
async ({ channel, sessionId, message, clientId }) => {
const response = await sendChatMessage({
channel: sessionId ? 'session' : 'global',
sessionId,
message
message,
clientId
});
return response;
}