feat(07-01): implement sessionChatSlice with initial state structure

GREEN phase of TDD:
- Create sessionChatSlice.js with complete initial state
- All 12 state fields match CHAT_REDUX_DESIGN.md specification
- Multi-channel architecture: messagesByChannel keyed by channel ID
- Unread tracking: unreadCounts, lastReadAt per channel
- State machines: fetchStatus/error per channel, sendStatus/error global
- Pagination support: nextCursors per channel
- UI state: isWindowOpen, windowPosition
- Register slice in store.js as sessionChat reducer

All 13 tests pass. Ready for reducers in Task 2.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-01-27 08:04:51 +05:30
parent fd44d1255f
commit e98504ebad
2 changed files with 45 additions and 0 deletions

View File

@ -0,0 +1,43 @@
import { createSlice } from '@reduxjs/toolkit';
/**
* Initial state for session chat
* @type {Object}
* @property {Object.<string, Array>} messagesByChannel - Messages organized by channel ID
* @property {string|null} activeChannel - Currently active channel ID
* @property {string|null} channelType - Type of active channel ('global', 'session', 'lesson')
* @property {Object.<string, number>} unreadCounts - Unread message count per channel
* @property {Object.<string, string|null>} lastReadAt - ISO timestamp of last read per channel
* @property {Object.<string, string>} fetchStatus - Fetch status per channel ('idle', 'loading', 'succeeded', 'failed')
* @property {Object.<string, string|null>} fetchError - Fetch error message per channel
* @property {string} sendStatus - Send status ('idle', 'loading', 'succeeded', 'failed')
* @property {string|null} sendError - Send error message
* @property {Object.<string, number|null>} nextCursors - Pagination cursors per channel
* @property {boolean} isWindowOpen - Whether chat window is open
* @property {Object|null} windowPosition - Window position {x, y}
*/
const initialState = {
messagesByChannel: {},
activeChannel: null,
channelType: null,
unreadCounts: {},
lastReadAt: {},
fetchStatus: {},
fetchError: {},
sendStatus: 'idle',
sendError: null,
nextCursors: {},
isWindowOpen: false,
windowPosition: null
};
const sessionChatSlice = createSlice({
name: 'sessionChat',
initialState,
reducers: {
// Reducers will be added in Tasks 2-3
}
});
export const {} = sessionChatSlice.actions;
export default sessionChatSlice.reducer;

View File

@ -15,6 +15,7 @@ import activeSessionReducer from "./features/activeSessionSlice"
import sessionUIReducer from "./features/sessionUISlice"
import mixersReducer from "./features/mixersSlice"
import mediaReducer from "./features/mediaSlice"
import sessionChatReducer from "./features/sessionChatSlice"
export default configureStore({
reducer: {
@ -25,6 +26,7 @@ export default configureStore({
session: sessionReducer, // this is the slice that holds the session lists
activeSession: activeSessionReducer, // this is the slice that holds the currently active session
sessionUI: sessionUIReducer, // this is the slice that holds the session UI state (modals, panels)
sessionChat: sessionChatReducer, // Phase 7: session chat state (messages, channels, unread tracking)
mixers: mixersReducer, // Phase 5: mixer state (chat, broadcast, track mixers, metronome, media summary)
media: mediaReducer, // Phase 5: media data (backing tracks, jam tracks, recorded tracks)
latency: latencyReducer,