diff --git a/jam-ui/src/components/client/JKSessionScreen.js b/jam-ui/src/components/client/JKSessionScreen.js index 4879bd746..c9248a173 100644 --- a/jam-ui/src/components/client/JKSessionScreen.js +++ b/jam-ui/src/components/client/JKSessionScreen.js @@ -55,7 +55,7 @@ import { selectBackingTrackData, selectJamTrackData } from '../../store/features/activeSessionSlice'; -import { addMessageFromWebSocket, uploadAttachment, selectIsUploading, selectUploadError, selectUploadFileName, selectUploadStatus, clearUploadError } from '../../store/features/sessionChatSlice'; +import { addMessageFromWebSocket, uploadAttachment, selectIsUploading, selectUploadError, selectUploadFileName, selectUploadStatus, clearUploadError, fetchChatHistory } from '../../store/features/sessionChatSlice'; import { validateFile } from '../../services/attachmentValidation'; import { CLIENT_ROLE, RECORD_TYPE_AUDIO, RECORD_TYPE_BOTH } from '../../helpers/globals'; @@ -471,6 +471,19 @@ const JKSessionScreen = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [hasJoined, sessionId, mixersReady, dispatch]) + // Fetch chat history when session joins to populate unread badge + // This ensures unread count persists across page reloads + useEffect(() => { + if (!hasJoined || !sessionId) { + return; + } + + dispatch(fetchChatHistory({ + channel: sessionId, + sessionId: sessionId + })); + }, [hasJoined, sessionId, dispatch]); + const joinSession = async () => { await jamClient.SetVURefreshRate(150); diff --git a/jam-ui/src/store/features/sessionChatSlice.js b/jam-ui/src/store/features/sessionChatSlice.js index a71142e11..6090d7ab9 100644 --- a/jam-ui/src/store/features/sessionChatSlice.js +++ b/jam-ui/src/store/features/sessionChatSlice.js @@ -372,6 +372,24 @@ const sessionChatSlice = createSlice({ state.fetchStatus[channel] = 'succeeded'; state.nextCursors[channel] = next; + + // Calculate unread count based on lastReadAt (for page reload persistence) + // Only set unread count if chat window is NOT open for this channel + // (if window is open, user is viewing messages so they're not "unread") + if (!state.isWindowOpen || state.activeChannel !== channel) { + const lastRead = state.lastReadAt[channel]; + if (lastRead) { + // Count messages newer than lastReadAt + const lastReadDate = new Date(lastRead); + const unreadCount = state.messagesByChannel[channel].filter( + m => new Date(m.createdAt) > lastReadDate + ).length; + state.unreadCounts[channel] = unreadCount; + } else { + // No lastReadAt means user never opened chat - all messages are unread + state.unreadCounts[channel] = state.messagesByChannel[channel].length; + } + } }) // fetchChatHistory rejected .addCase(fetchChatHistory.rejected, (state, action) => {