fix: correct message format handling and add optimistic update params

Two P0 bugs fixed:

1. "Unknown" sender name bug:
   - Root cause: Redux slice expected action.payload.message, but API
     returns message object directly as action.payload
   - Fix: Changed sessionChatSlice.js sendMessage.fulfilled to use
     action.payload instead of action.payload.message

2. First message not appearing bug:
   - Root cause: JKChatComposer wasn't passing optimisticId, userId,
     userName parameters needed for optimistic updates
   - Fix: Added uuid import, useAuth hook, and pass required params
     to sendMessage thunk

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-01-31 20:31:38 +05:30
parent ec5427b48f
commit 99f9d4b898
2 changed files with 13 additions and 5 deletions

View File

@ -1,9 +1,11 @@
import React, { useState, useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import uuid from 'uuid/v1';
import { sendMessage, selectSendStatus, selectSendError, clearSendError } from '../../../store/features/sessionChatSlice';
import { selectSessionId } from '../../../store/features/activeSessionSlice';
import { useJamServerContext } from '../../../context/JamServerContext';
import { useAuth } from '../../../context/UserAuth';
/**
* JKChatComposer - Message composition component
@ -37,6 +39,9 @@ const JKChatComposer = ({ textareaRef }) => {
// WebSocket connection status
const { isConnected } = useJamServerContext();
// Current user for optimistic updates
const { currentUser } = useAuth();
// Validation and state calculations
const trimmedText = useMemo(() => inputText.trim(), [inputText]);
const charCount = inputText.length;
@ -71,20 +76,23 @@ const JKChatComposer = ({ textareaRef }) => {
}, []);
const handleSend = useCallback(async () => {
if (!canSend) return;
if (!canSend || !currentUser) return;
// Send message via Redux thunk
// Send message via Redux thunk with optimistic update parameters
await dispatch(
sendMessage({
channel: sessionId,
sessionId,
message: trimmedText
message: trimmedText,
optimisticId: uuid(),
userId: currentUser.id,
userName: currentUser.name
})
);
// Clear input on success
setInputText('');
}, [canSend, dispatch, sessionId, trimmedText]);
}, [canSend, dispatch, sessionId, trimmedText, currentUser]);
const handleKeyDown = useCallback(
e => {

View File

@ -289,7 +289,7 @@ const sessionChatSlice = createSlice({
// Replace optimistic message with real one
const { channel, optimisticId } = action.meta.arg;
const realMessage = action.payload.message;
const realMessage = action.payload; // API returns message directly, not wrapped
const messages = state.messagesByChannel[channel];
if (messages) {