feat(07-01): implement unread tracking reducers and complete slice

GREEN phase of TDD for Task 3:
- Implement markAsRead: resets unread count to 0, updates lastReadAt timestamp
- Implement incrementUnreadCount: safely handles missing channels
- Implement setWindowPosition: stores UI position for WindowPortal
- Export all 7 action creators from slice
- Complete sessionChatSlice with full reducer suite

All 40 tests pass including 3 integration tests:
- Complete flow validates message receiving, channel switching, window state
- Multi-channel flow validates independent unread counts per channel
- Deduplication test validates WebSocket + REST double-message scenario

Ready for async thunks in Phase 7 Plan 2.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-01-27 08:07:44 +05:30
parent 96d7188a4c
commit 7bafb3c697
1 changed files with 31 additions and 1 deletions

View File

@ -111,6 +111,33 @@ const sessionChatSlice = createSlice({
*/
closeChatWindow: (state) => {
state.isWindowOpen = false;
},
/**
* Mark channel as read
* Resets unread count and updates lastReadAt timestamp
*/
markAsRead: (state, action) => {
const { channel } = action.payload;
state.unreadCounts[channel] = 0;
state.lastReadAt[channel] = new Date().toISOString();
},
/**
* Increment unread count for a channel
* Initializes count to 1 if channel doesn't exist
*/
incrementUnreadCount: (state, action) => {
const { channel } = action.payload;
state.unreadCounts[channel] = (state.unreadCounts[channel] || 0) + 1;
},
/**
* Set window position for persistence
* Used by WindowPortal to save drag position
*/
setWindowPosition: (state, action) => {
state.windowPosition = action.payload;
}
}
});
@ -119,7 +146,10 @@ export const {
addMessageFromWebSocket,
setActiveChannel,
openChatWindow,
closeChatWindow
closeChatWindow,
markAsRead,
incrementUnreadCount,
setWindowPosition
} = sessionChatSlice.actions;
export default sessionChatSlice.reducer;