From 4d166f7d3933c46e9220ed8bfc179953b37ba6e3 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Tue, 27 Jan 2026 12:43:45 +0530 Subject: [PATCH] refactor(07-03): enhance JSDoc comments for memoized selectors - Add comprehensive JSDoc with usage descriptions for all 8 selectors - Document memoization behavior (when selectors recompute) - Add @private tags to input selectors - Document return value types and defaults (empty arrays, 0, idle states) - Clarify channel ID parameter (session ID, lesson ID, or 'global') - All 68 tests still passing after refactoring Part of Phase 7 Plan 3 (WebSocket Integration & Selectors) Co-Authored-By: Claude Sonnet 4.5 --- jam-ui/src/store/features/sessionChatSlice.js | 72 +++++++++++++++---- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/jam-ui/src/store/features/sessionChatSlice.js b/jam-ui/src/store/features/sessionChatSlice.js index 9830a3d10..cde27677d 100644 --- a/jam-ui/src/store/features/sessionChatSlice.js +++ b/jam-ui/src/store/features/sessionChatSlice.js @@ -311,17 +311,32 @@ export const { // Phase 7 Plan 3: Memoized selectors using createSelector from Redux Toolkit import { createSelector } from '@reduxjs/toolkit'; -// Input selectors (direct state access) +/** + * Input selectors for memoized selectors + * These directly access state and are used as inputs to createSelector + */ + +/** @private */ const selectSessionChatState = (state) => state.sessionChat; + +/** @private */ const selectMessagesByChannel = (state) => state.sessionChat.messagesByChannel; + +/** @private */ const selectUnreadCounts = (state) => state.sessionChat.unreadCounts; + +/** @private */ const selectFetchStatusMap = (state) => state.sessionChat.fetchStatus; /** * Select messages for a specific channel + * + * Returns array of messages for the given channel, or empty array if channel doesn't exist. + * Memoized with createSelector - only recomputes when messagesByChannel or channel changes. + * * @param {Object} state - Redux state - * @param {string} channel - Channel ID - * @returns {Array} Messages for the channel + * @param {string} channel - Channel ID (session ID, lesson ID, or 'global') + * @returns {Array} Messages for the channel, sorted chronologically */ export const selectChatMessages = createSelector( [selectMessagesByChannel, (state, channel) => channel], @@ -330,9 +345,13 @@ export const selectChatMessages = createSelector( /** * Select unread count for a specific channel + * + * Returns unread count for the given channel, or 0 if channel doesn't exist. + * Memoized with createSelector - only recomputes when unreadCounts or channel changes. + * * @param {Object} state - Redux state - * @param {string} channel - Channel ID - * @returns {number} Unread count for the channel + * @param {string} channel - Channel ID (session ID, lesson ID, or 'global') + * @returns {number} Unread count for the channel (0 if none) */ export const selectUnreadCount = createSelector( [selectUnreadCounts, (state, channel) => channel], @@ -341,8 +360,12 @@ export const selectUnreadCount = createSelector( /** * Select total unread count across all channels + * + * Sums unread counts from all channels for badge display. + * Memoized with createSelector - only recomputes when unreadCounts changes. + * * @param {Object} state - Redux state - * @returns {number} Total unread count + * @returns {number} Total unread count across all channels */ export const selectTotalUnreadCount = createSelector( [selectUnreadCounts], @@ -350,9 +373,13 @@ export const selectTotalUnreadCount = createSelector( ); /** - * Select whether chat window is open + * Select whether chat window is currently open + * + * Used to control chat window visibility and unread increment logic. + * Memoized with createSelector - only recomputes when sessionChat state changes. + * * @param {Object} state - Redux state - * @returns {boolean} Is window open + * @returns {boolean} True if chat window is open */ export const selectIsChatWindowOpen = createSelector( [selectSessionChatState], @@ -360,9 +387,13 @@ export const selectIsChatWindowOpen = createSelector( ); /** - * Select active channel ID + * Select currently active channel ID + * + * Identifies which channel is currently being viewed in the chat window. + * Memoized with createSelector - only recomputes when sessionChat state changes. + * * @param {Object} state - Redux state - * @returns {string|null} Active channel ID + * @returns {string|null} Active channel ID, or null if none selected */ export const selectActiveChannel = createSelector( [selectSessionChatState], @@ -371,9 +402,14 @@ export const selectActiveChannel = createSelector( /** * Select fetch status for a specific channel + * + * Returns loading state for message history fetch operations. + * Defaults to 'idle' if channel has never been fetched. + * Memoized with createSelector - only recomputes when fetchStatus or channel changes. + * * @param {Object} state - Redux state * @param {string} channel - Channel ID - * @returns {string} Fetch status ('idle', 'loading', 'succeeded', 'failed') + * @returns {string} Fetch status: 'idle' | 'loading' | 'succeeded' | 'failed' */ export const selectFetchStatus = createSelector( [selectFetchStatusMap, (state, channel) => channel], @@ -381,9 +417,13 @@ export const selectFetchStatus = createSelector( ); /** - * Select send status + * Select send message status + * + * Returns loading state for the current message send operation. + * Memoized with createSelector - only recomputes when sessionChat state changes. + * * @param {Object} state - Redux state - * @returns {string} Send status ('idle', 'loading', 'succeeded', 'failed') + * @returns {string} Send status: 'idle' | 'loading' | 'succeeded' | 'failed' */ export const selectSendStatus = createSelector( [selectSessionChatState], @@ -392,8 +432,12 @@ export const selectSendStatus = createSelector( /** * Select send error message + * + * Returns error message if the last send operation failed. + * Memoized with createSelector - only recomputes when sessionChat state changes. + * * @param {Object} state - Redux state - * @returns {string|null} Send error message + * @returns {string|null} Error message, or null if no error */ export const selectSendError = createSelector( [selectSessionChatState],