Feature/state machine challenges - #224
Conversation
…nent structure - Simplified error handling and response processing in chat flow API functions. - Refactored MainPage component to enhance readability and maintainability. - Introduced StateMachineDefineChallenge component for better separation of concerns. - Updated ChatWindow and ChatMessage components for improved functionality and performance. - Added utility functions for sorting data.
- Added DEFAULT_COMPANY_SLUG constant for improved company slug management. - Integrated useChatDataSessionStore and useSiteDataLocalStore in MainPage for better state management. - Implemented WebSocket connection handling in StateMachineDefineChallenge for real-time chat updates. - Refactored message handling logic to streamline user and bot interactions. - Updated session management to ensure proper state resets and error handling.
…hini-app-frontend into feature/state-machine-challenges
…ohini-app-frontend into feature/state-machine-challenges
…/VishnuKrishnathu/mohini-app-frontend into feature/state-machine-challenges
- Reorganized imports and removed unnecessary comments for clarity. - Streamlined state management and effect hooks in MainPage for better performance. - Enhanced message handling and WebSocket connection logic in InitialSwitch. - Updated loading states and conditional rendering in StateMachineDefineChallenge and ChatWindow components. - Improved overall code readability and maintainability.
📝 WalkthroughWalkthroughThis PR adds a new StateMachineDefineChallenge React component (chat state machine with WebSocket, TTS, and session orchestration), replaces DefineChallenge with it in MainPage, tightens ChatWindow/ChatMessage props, adds sort utilities and chatData accessors, removes websocket.close() from the hook cleanup, and adds a new DEFAULT_COMPANY_SLUG constant. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as StateMachineDefineChallenge (React)
participant API as Backend API
participant WS as WebSocket
participant Store as Zustand Store
UI->>API: Fetch user profile, company bot, session, intro
API-->>UI: Profile, bot info, session, intro
UI->>Store: Initialize session & language state
UI->>WS: Open WebSocket connection & authenticate
WS-->>UI: Auth confirmed
UI->>UI: Render intro message (optional TTS)
Note over UI: User sends a message
UI->>WS: Send user message
WS-->>UI: Stream BOT response (chunks)
UI->>UI: Append streamed BOT messages to chat history
UI->>Store: Update strand step / should_move_forward
UI->>API: Persist or fetch additional session data as needed
Note over UI: Repeat until flow completion
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (5)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
🧰 Additional context used🧠 Learnings (2)📚 Learning: 2025-12-23T16:55:04.450ZApplied to files:
📚 Learning: 2026-01-14T02:51:09.584ZApplied to files:
🧬 Code graph analysis (1)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx (9)
🔇 Additional comments (5)
✏️ Tip: You can disable this entire section by setting Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…functions - Updated all API functions in chat_flow.js to use consistent formatting and error handling. - Improved readability by aligning try-catch blocks and ensuring uniform return statements. - Removed unnecessary comments and streamlined the code for better maintainability.
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx (1)
124-144: Passing unused props to ChatMessage.Several props passed to
ChatMessage(name,recording,hasAppendix,appendixURL,isTalking,validation,isAnyPlaying,setNotMute) are not accepted by the simplifiedChatMessagecomponent signature. These will be silently ignored.Remove unused props for clarity, or update
ChatMessageif these props are needed.Suggested fix - remove unused props
<ChatMessage userType={chat?.source} message={`${chat?.msg}`} - name={"You"} - recording={chat?.recording} - hasAppendix={chat?.recording} - appendixURL={chat?.appendixURL} - isTalking={chat.source === "bot" && !isStreamingComplete && i === chatHistory.length - 1} handleOnStopSpeaking={() => handleOnStopSpeaking()} handleOnSpeaking={() => { setNotMute(false) handleOnSpeaking(`${chat?.msg}`, chat?.updated_at) }} - isAnyPlaying={!!hasOverRideId || isTalking} isPlaying={hasOverRideId === chat?.updated_at} isStreamingComplete={isStreamingComplete} - setNotMute={setNotMute} chatId={chat?.updated_at} - validation={chat?.validation} userDetail={userDetail} />
🤖 Fix all issues with AI agents
In @src/constants/session.js:
- Line 8: StateMachineDefineChallenge.jsx currently uses the hardcoded
DEFAULT_COMPANY_SLUG when calling getCompanyBotApi; update it to use the company
slug fetched into state (the value set by setCompanyStore / profile data) and
only fall back to DEFAULT_COMPANY_SLUG if that state/profile value is missing.
Locate the getCompanyBotApi call in StateMachineDefineChallenge.jsx (around
where setCompanyStore(data?.company?.slug) is used) and pass the
profile/companyStore slug instead of DEFAULT_COMPANY_SLUG, ensuring the same
fallback semantics as in DefineChallenge.jsx.
In
@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx:
- Around line 31-37: The code in ChatWindow.jsx has two identical if (errorText)
{ showLoader = false } blocks; remove the duplicate so there is only one check
that sets showLoader to false when errorText is truthy (keep the first
occurrence and delete the repeated block), ensuring no other logic around
showLoader or errorText is altered.
- Line 53: The return expression can throw when chatHistory is empty; guard
access before reading .source by checking length and using optional chaining:
ensure chatHistory?.length > 0 (or chatHistory?.[chatHistory.length -
1]?.source) before comparing to "user" so the expression becomes something like:
!hasStartedListening && chatHistory?.length > 0 &&
chatHistory[chatHistory.length - 1]?.source === "user" && indexNumber ===
chatHistory.length - 1 && showLoader.
In
@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx:
- Around line 349-360: The effect is mutating chat_history in place when setting
the last item; instead, build a new array copy and replace the last element
immutably before calling setChatHistory. In the useEffect that reads recordings
and chatHistory (and uses getChatHistory()), create a shallow copy (e.g.,
[...chat_history]) or map over chat_history, replace the last element with
{...chat_history[lastIndex], recording: recordings[recordings.length-1]} and
then call setChatHistory(newArray) so React sees a new reference; keep the same
guard (recordings?.length && chatHistory[last]?.source !== BOT).
- Around line 551-561: Guard against empty chatHistory before accessing its last
element: in the useEffect that checks appendix and chatHistory, ensure
chatHistory has at least one item (e.g., chatHistory?.length > 0) before reading
chatHistory[chatHistory.length - 1].source or use optional chaining on the last
element (e.g., chatHistory[chatHistory.length - 1]?.source === BOT). Update the
condition surrounding appendix handling in the useEffect (symbols: useEffect,
appendix, chatHistory, BOT, getChatHistory, lastMessage, setChatHistory,
setAppendix) so you only mutate lastMessage when it exists, then proceed to
setChatHistory and setAppendix as before; keep the
isDefineChallengeSection/handleScrollIntoView logic unchanged.
- Around line 243-250: The three async calls createUserProfile(),
fetchCompanyBotInfo(), and getSessionId() are fired in parallel and can cause
state updates after unmount; coordinate them and add an abort/cleanup flag in
the useEffect so no setState or navigation happens if the effect is cleaned up.
Make createUserProfile, fetchCompanyBotInfo, and getSessionId return Promises
(if they don't already), then either await them sequentially or use
Promise.allSettled to observe results, wrap their state-setting calls
(setShouldFetchIntro, setIsStreamingComplete, any navigation) behind a check of
a local cancelled/isMounted flag, and implement the effect cleanup to set that
flag to true; also add try/catch around awaits to handle errors and avoid
unguarded state updates.
- Around line 132-135: The onWebSocketMessage callback passed into
useChatWebhook can close over a stale stateMachineLength; update it to read the
latest value (e.g., create a stateMachineLengthRef via useRef, keep it in sync
by assigning stateMachineLengthRef.current = stateMachineLength in an effect or
immediately after state updates, and then inside onWebSocketMessage call
getStrandStep() and compare against stateMachineLengthRef.current before calling
setShouldMoveForward("yes")). Alternatively, instead of the ref approach, read
stateMachineLength from the store inside onWebSocketMessage to ensure the latest
value is used; ensure you update references to stateMachineLength in that
callback (and keep setShouldMoveForward usage unchanged).
In @src/utils/sorts.js:
- Around line 5-8: The quickSort function currently uses optional chaining so
when arr is null/undefined it returns undefined; change it to explicitly handle
null/undefined by adding a guard at the top of quickSort (e.g., if (arr == null)
return []) before the length check, then keep the existing behavior for arrays
(if (arr.length <= 1) return arr). Reference quickSort to locate where to add
the null/undefined guard so callers always receive an array rather than
undefined.
🧹 Nitpick comments (4)
src/utils/sorts.js (1)
5-23: Consider using the built-inArray.prototype.sort()instead.The custom quicksort implementation works, but JavaScript's built-in
sort()is typically more performant (uses optimized algorithms like Timsort in V8) and handles edge cases more robustly. The first-element pivot selection can also degrade to O(n²) on already-sorted arrays.♻️ Simpler alternative using built-in sort
export function quickSort(arr, compare) { if (!arr || arr.length <= 1) { return arr || [] } return [...arr].sort(compare) }This creates a shallow copy to preserve immutability (like the current implementation) and leverages the optimized native sort.
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx (2)
30-30: Avoid usingletfor variables that aren't reassigned.
access_tokenis declared withletbut never reassigned. Useconstfor consistency.Suggested fix
- let access_token = sessionStorage.getItem(URL_PARAMS.ACCESS_TOKEN) + const access_token = sessionStorage.getItem(URL_PARAMS.ACCESS_TOKEN)
347-347: Remove empty useEffect.This
useEffecthas no side effects and serves no purpose.Suggested fix
- useEffect(() => {}, [])src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx (1)
56-68: Consider using a cleaner approach for filtering.The current implementation uses
forEachwith a flag to stop pushing. A more functional approach would be clearer.Alternative implementation
const chatsToShow = useMemo(() => { - const data = [] - let shouldPush = true - chatHistory?.forEach(chat => { - if (shouldPush) { - data.push(chat) - if (chat?.shouldMoveForward === "yes" && chat?.source === "user") { - shouldPush = false - } - } - }) - return data + const stopIndex = chatHistory?.findIndex( + chat => chat?.shouldMoveForward === "yes" && chat?.source === "user" + ) + return stopIndex === -1 + ? chatHistory ?? [] + : chatHistory?.slice(0, stopIndex + 1) ?? [] }, [chatHistory])
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/configure.jssrc/constants/session.jssrc/hooks/useChatWebhook.jssrc/pages/ai-creation/pages/shikshalokam-mitra/MainPage.jsxsrc/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsxsrc/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsxsrc/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/chat-message/ChatMessage.jsxsrc/store/slices/chatData/state.jssrc/utils/sorts.js
💤 Files with no reviewable changes (1)
- src/hooks/useChatWebhook.js
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2026-01-11T21:04:07.741Z
Learnt from: pinkman7009
Repo: ELEVATE-Project/mohini-app-frontend PR: 223
File: src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx:124-140
Timestamp: 2026-01-11T21:04:07.741Z
Learning: In CommonFlow.jsx (src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx), the WebSocket URL intentionally uses `sessionFlowName.Creation` for all common flows (LFA, LCF, FREE_FLOW) in the `buildWebSocketUrl` call. The derived `storageFlow` (from `flowConfig.flow_name`) is used in the authentication message sent via `onWebSocketOpen`, not in the WebSocket URL construction. This is the expected design.
Applied to files:
src/configure.js
📚 Learning: 2025-12-23T16:55:04.450Z
Learnt from: pinkman7009
Repo: ELEVATE-Project/mohini-app-frontend PR: 218
File: src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/ActionItems.jsx:318-320
Timestamp: 2025-12-23T16:55:04.450Z
Learning: In ActionItems.jsx (src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/ActionItems.jsx), the action list is intentionally refetched every time the objective changes. The commented-out guard and the useEffect dependency on `objective` are part of the expected design for handling objective regeneration flows.
Applied to files:
src/pages/ai-creation/pages/shikshalokam-mitra/MainPage.jsx
📚 Learning: 2026-01-11T21:08:05.729Z
Learnt from: pinkman7009
Repo: ELEVATE-Project/mohini-app-frontend PR: 223
File: src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx:416-439
Timestamp: 2026-01-11T21:08:05.729Z
Learning: In the SelectObjective.jsx component (src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx), objectives are guaranteed to have unique text values, so text-based equality comparison is safe for determining objective selection without risk of duplicate matches.
Applied to files:
src/pages/ai-creation/pages/shikshalokam-mitra/MainPage.jsx
🧬 Code graph analysis (5)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx (8)
src/configure.js (2)
bot_routes(22-42)bot_routes(22-42)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/chat-message/ChatMessage.jsx (1)
CONVERSATION_USER_TYPES(7-7)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/InitialSwitch.jsx (1)
setSessionStore(41-46)src/api/endpoints/chat.js (1)
data(31-31)src/pages/shikshalokamChat.js (1)
setProfileId(38-38)src/constants/session.js (2)
DEFAULT_COMPANY_SLUG(8-8)DEFAULT_COMPANY_SLUG(8-8)src/components/ToastMessage/TotastMessage.jsx (1)
Notification(6-23)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/LoadingChat.jsx (1)
LoadingChat(1-8)
src/configure.js (2)
src/url.js (1)
ROUTES(1-26)src/utils/index.js (2)
result(13-17)getDomainDetail(3-22)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/chat-message/ChatMessage.jsx (3)
src/pages/ai-creation/constants/mitra.constants.js (2)
CONVERSATION_USER_TYPES(7-10)CONVERSATION_USER_TYPES(7-10)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/chat-message/BotMessage.jsx (1)
BotMessage(7-57)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/chat-message/UserMessage.jsx (1)
UserMessage(6-24)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx (3)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/DefineChallenge.jsx (1)
chatHistory(54-56)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ConversationWrapperCard.jsx (1)
containerRef(4-4)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/LoadingChat.jsx (1)
LoadingChat(1-8)
src/pages/ai-creation/pages/shikshalokam-mitra/MainPage.jsx (5)
src/pages/ai-creation/constants/mitra.constants.js (2)
ACTIVE_TABS(1-5)ACTIVE_TABS(1-5)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx (1)
CommonFlow(14-219)src/pages/ai-creation/constants/common.js (2)
LOADER_KEYS(1-11)LOADER_KEYS(1-11)src/configure.js (4)
bot_routes(22-42)bot_routes(22-42)FLOW_TYPES(45-50)FLOW_TYPES(45-50)src/i18n.js (2)
setLanguage(29-34)setLanguage(29-34)
🔇 Additional comments (13)
src/configure.js (1)
1-159: LGTM!The changes are purely stylistic (semicolon removal and quote consistency) with no functional impact on the configuration logic.
src/store/slices/chatData/state.js (1)
39-40: LGTM!The new
getStrandStepaccessor follows the established pattern for state accessors in this slice and correctly exposes the existingstrandStepstate.src/pages/ai-creation/pages/shikshalokam-mitra/MainPage.jsx (5)
1-28: LGTM!The imports are well-organized, with the new
StateMachineDefineChallengecomponent replacing the previousDefineChallenge, and the additional store imports (useChatDataSessionStore,useSiteDataLocalStore) are correctly added to support the new reset functionality.
100-114: LGTM!The useEffect hooks correctly sync local state to the Zustand store. The store functions obtained from
getState()are stable references (a standard Zustand pattern), so omitting them from dependency arrays is intentional and correct.
294-298: LGTM!The
StateMachineDefineChallengecomponent is correctly integrated with appropriate props for handling loader states, navigation, and scroll behavior.
453-463: LGTM!The additional store reset calls for
useChatDataSessionStoreanduseSiteDataLocalStoreproperly extend the session cleanup to include the new stores, following the established pattern.
30-98: Formatting changes look good.State initialization and effect hooks have been reformatted for consistency without altering functionality.
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx (4)
174-178: LGTM!Proper cleanup of WebSocket connection on component unmount.
609-614: LGTM!Clean utility function with sensible defaults for message creation.
494-494: The hardcodedbot_routes.mitra_createis intentional and correct. All TTS calls throughout the mitra creation flow (DefineChallenge.jsx, ai4bharat_services.js, and StateMachineDefineChallenge.jsx) consistently usebot_routes.mitra_createas the designated TTS endpoint, whilestate_machine_bot_route(define_challenges) is reserved for bot conversation. These routes serve different purposes and should not be interchangeable.
399-414: No changes needed. The code handles this correctly through message queuing.When
connectToWebSocket()is called, the WebSocket enters a CONNECTING state. ThesendMessage()function has built-in logic (useChatWebhook.js line 76-78) that queues messages when the socket is in CONNECTING state. Once the connection opens, all queued messages are flushed in order (lines 25-29), preserving message sequence. Both the authenticate and text messages will be queued and sent in the correct order automatically.Likely an incorrect or invalid review comment.
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/chat-message/ChatMessage.jsx (1)
9-20: LGTM!The component has been cleanly refactored with a reduced prop surface. The sanitization with DOMPurify is properly applied, and the conditional rendering based on user type is straightforward.
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx (1)
100-109: LGTM!Good use of the callback ref pattern to handle both internal
containerRefand the forwardedscrollRef, with proper handling for both function and object ref types.
| }; No newline at end of file | ||
| } | ||
|
|
||
| export const DEFAULT_COMPANY_SLUG = "shikshalokamstaging" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "DEFAULT_COMPANY_SLUG" --type=js --type=jsx -A 3 -B 1Repository: ELEVATE-Project/mohini-app-frontend
Length of output: 106
🏁 Script executed:
rg -n "DEFAULT_COMPANY_SLUG" -A 3 -B 1Repository: ELEVATE-Project/mohini-app-frontend
Length of output: 1722
🏁 Script executed:
rg -n "company.*slug|COMPANY.*SLUG" --type js -iRepository: ELEVATE-Project/mohini-app-frontend
Length of output: 1615
🏁 Script executed:
sed -n '185,210p' src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsxRepository: ELEVATE-Project/mohini-app-frontend
Length of output: 877
🏁 Script executed:
rg -n "companyStore" src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsxRepository: ELEVATE-Project/mohini-app-frontend
Length of output: 61
🏁 Script executed:
sed -n '150,160p' src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/DefineChallenge.jsxRepository: ELEVATE-Project/mohini-app-frontend
Length of output: 547
🏁 Script executed:
sed -n '395,435p' src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/DefineChallenge.jsxRepository: ELEVATE-Project/mohini-app-frontend
Length of output: 1368
🏁 Script executed:
# Check if there are environment config files that might explain this
fd -e ".env" -e "*.config" | head -20Repository: ELEVATE-Project/mohini-app-frontend
Length of output: 89
🏁 Script executed:
cat sample.envRepository: ELEVATE-Project/mohini-app-frontend
Length of output: 164
🏁 Script executed:
# Check for any production or environment-specific config
find . -name ".env*" -o -name "*production*" -o -name "*staging*" | grep -v node_modules | head -20Repository: ELEVATE-Project/mohini-app-frontend
Length of output: 61
🏁 Script executed:
# Check README and package.json for context about the project
head -50 README.md 2>/dev/null || echo "No README"
cat package.json | head -30Repository: ELEVATE-Project/mohini-app-frontend
Length of output: 3263
Use the user's company slug instead of hardcoded staging value.
DEFAULT_COMPANY_SLUG is hardcoded to "shikshalokamstaging" and used unconditionally in StateMachineDefineChallenge.jsx (line 200) via getCompanyBotApi, even though the user's actual company slug is already fetched and available from the profile (line 187: setCompanyStore(data?.company?.slug)). This differs from similar code in DefineChallenge.jsx, which properly uses the staging slug only as a fallback when no profile exists. Update StateMachineDefineChallenge.jsx to use the company slug from the user profile instead of the hardcoded constant.
🤖 Prompt for AI Agents
In @src/constants/session.js at line 8, StateMachineDefineChallenge.jsx
currently uses the hardcoded DEFAULT_COMPANY_SLUG when calling getCompanyBotApi;
update it to use the company slug fetched into state (the value set by
setCompanyStore / profile data) and only fall back to DEFAULT_COMPANY_SLUG if
that state/profile value is missing. Locate the getCompanyBotApi call in
StateMachineDefineChallenge.jsx (around where
setCompanyStore(data?.company?.slug) is used) and pass the profile/companyStore
slug instead of DEFAULT_COMPANY_SLUG, ensuring the same fallback semantics as in
DefineChallenge.jsx.
There was a problem hiding this comment.
For SGCommon we have hardcoded the Company SLUG
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for SGCommon references in the codebase
rg -n "SGCommon" -C 3
# Also search for variations
rg -n -i "sg.common|sg_common" -C 2
Length of output: 4044
@VishnuKrishnathu, thank you for clarifying! I understand now that for the SG-Commons product, the company slug is intentionally hardcoded to "shikshalokamstaging" as part of the architectural design. I'll note this for future reference.
| if (!profileId && access_token) { | ||
| createUserProfile() | ||
| setShouldFetchIntro(true) | ||
| setIsStreamingComplete(true) | ||
| } | ||
| fetchCompanyBotInfo() | ||
| getSessionId() | ||
| }, [access_token, profileId]) |
There was a problem hiding this comment.
Uncoordinated async operations may cause race conditions.
createUserProfile, fetchCompanyBotInfo, and getSessionId run in parallel without coordination. If one fails and navigates away while others are still running, they may attempt state updates on an unmounted component.
Consider using an abort pattern or coordinating these calls.
Suggested fix with cleanup flag
useEffect(() => {
+ let isMounted = true
+
async function createUserProfile() {
try {
setIsLocalLoading(true)
const data = await createUserProfileApi({ access_token }).then(resp => resp.profile_details)
+ if (!isMounted) return
setProfileId(data?.id)
setFirstName(data?.first_name)
setCompanyStore(data?.company?.slug)
} catch (error) {
console.error(error?.response?.data || error)
+ if (!isMounted) return
navigate(-1)
clearMitraSessionStorage()
} finally {
+ if (isMounted) setIsLocalLoading(false)
- setIsLocalLoading(false)
}
}
// ... similar changes for other async functions
+
+ return () => { isMounted = false }
}, [access_token, profileId])🤖 Prompt for AI Agents
In
@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx
around lines 243 - 250, The three async calls createUserProfile(),
fetchCompanyBotInfo(), and getSessionId() are fired in parallel and can cause
state updates after unmount; coordinate them and add an abort/cleanup flag in
the useEffect so no setState or navigation happens if the effect is cleaned up.
Make createUserProfile, fetchCompanyBotInfo, and getSessionId return Promises
(if they don't already), then either await them sequentially or use
Promise.allSettled to observe results, wrap their state-setting calls
(setShouldFetchIntro, setIsStreamingComplete, any navigation) behind a check of
a local cancelled/isMounted flag, and implement the effect cleanup to set that
flag to true; also add try/catch around awaits to handle errors and avoid
unguarded state updates.
There was a problem hiding this comment.
This is existing code that already works. We'll note the issue and try once from our side, if valid we'll change the code in the next PR.
There was a problem hiding this comment.
@VishnuKrishnathu, understood! I appreciate you noting the feedback. If you'd like, I can create a GitHub issue to track this for the future PR—just let me know. Otherwise, feel free to revisit it when convenient.
🧠 Learnings used
Learnt from: pinkman7009
Repo: ELEVATE-Project/mohini-app-frontend PR: 225
File: src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/InitialSwitch.jsx:79-89
Timestamp: 2026-01-14T02:51:09.584Z
Learning: In the AI creation flow components (InitialSwitch.jsx, CommonFlow.jsx), the pattern of using `pendingMessageRef` with a 100ms `setTimeout` after WebSocket authentication is intentionally used to ensure the authenticate message is sent before any user messages. This is an accepted implementation pattern for these flows.
Learnt from: pinkman7009
Repo: ELEVATE-Project/mohini-app-frontend PR: 218
File: src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/ActionItems.jsx:318-320
Timestamp: 2025-12-23T16:55:04.450Z
Learning: In ActionItems.jsx (src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/ActionItems.jsx), the action list is intentionally refetched every time the objective changes. The commented-out guard and the useEffect dependency on `objective` are part of the expected design for handling objective regeneration flows.
- Updated StateMachineDefineChallenge to ensure chat history is always an array before accessing its properties. - Improved ChatWindow component to handle chat history checks more robustly. - Added a safeguard in quickSort utility to return an empty array if the input is not an array, enhancing error handling.
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Fix all issues with AI agents
In
@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx:
- Around line 7-14: Several selectors use useAICreationSessionStore.getState()
which reads once and won't subscribe to updates, causing stale UI (e.g.,
objectiveList, allObjectiveChatHistory, selectedWeek, selectedFlowType,
errorText); change these to use the reactive selector form
useAICreationSessionStore(state => state.<property>) so the component subscribes
and re-renders on changes, and ensure derived getters return stable references
or use shallow equality if needed to avoid unnecessary re-renders (apply this to
objectiveList, allObjectiveChatHistory, selectedWeek, selectedFlowType,
errorText to match selectedObjective/selectedAction).
In
@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx:
- Line 347: Remove the dead empty useEffect call by deleting the line containing
useEffect(() => {}, []) in StateMachineDefineChallenge (remove the no-op import
usage if it leaves useEffect unused); ensure no other logic depends on that hook
and run linter/tests to confirm no unused-import warnings.
- Around line 93-108: The code mutates an object from state by shallow-copying
the array via getChatHistory() then directly updating
chat_history[chat_history.length - 1].msg; instead, create a new array and
replace the last element with a new object to avoid mutating the original
reference: when the last item source === BOT and message?.msg exists, build a
newLast = { ...oldLast, msg: (oldLast.msg || "") + (message?.msg || ""),
updated_at: Date.now() } and produce newChatHistory = [...oldArray.slice(0, -1),
newLast] (or use map to return a new object for the last index), then call
setChatHistory(newChatHistory); keep the existing fields problemStatement,
shouldMoveForward, validation unchanged when constructing newLast.
- Around line 349-360: The useEffect in StateMachineDefineChallenge risks a
render loop because it depends on chatHistory and calls setChatHistory; modify
it to only call setChatHistory when the latest recording actually differs from
the existing recording on the last chat entry: compute const latestRecording =
recordings?.[recordings.length-1] and const currentLast =
getChatHistory()?.[getChatHistory().length-1], then if recordings?.length &&
currentLast?.source !== BOT && currentLast?.recording !== latestRecording,
create the updated array and call setChatHistory; remove the empty cleanup
return and narrow the dependency array to [recordings] (or [recordings,
getChatHistory] if getChatHistory is not stable) to avoid unnecessary triggers.
- Around line 551-559: The current useEffect mutates the last message object
directly after shallow-copying the array (chat_history) which risks shared-state
bugs; instead, locate the last index (e.g., const i = chat_history.length - 1),
create a new object for lastMessage via shallow copy and updated fields
(appendixURL and hasAppendix), assign that new object into chat_history[i], then
call setChatHistory(chat_history) and setAppendix([]); update references in the
useEffect block (appendix, chatHistory, getChatHistory, lastMessage,
setChatHistory, setAppendix) to follow this immutable update pattern.
- Around line 132-135: The callback uses the render-time stateMachineLength
value which can be stale; instead create a ref (e.g., stateMachineLengthRef)
that you update whenever stateMachineLength changes (via useEffect or inside the
setter) and read stateMachineLengthRef.current inside onWebSocketMessage when
calling getStrandStep and comparing to it; alternatively read the latest value
directly from the store inside the callback; then keep the same Number.isInteger
and setShouldMoveForward("yes") logic but use the fresh ref/store value instead
of the captured stateMachineLength.
- Around line 444-455: The code mutates the last message object via
lastMessage.msg += " " + sentence; instead, create immutable copies: build a new
message object (copying properties and updating msg) and replace the last
element in a new chat array before calling setChatHistory; reference the
variables/functions chat_history, getChatHistory(), chatHistory, BOT,
lastMessage, setChatHistory and mirror the non-mutating approach used in
onWebSocketMessage to avoid shallow-copy mutation.
🧹 Nitpick comments (7)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx (2)
118-118: Consider using a stable unique identifier as the list key.Using array index
ias a key can cause issues with component state and reconciliation if chat messages are ever reordered, inserted, or removed from the middle of the list. Since each chat has anupdated_atproperty used elsewhere as an identifier, consider using it as the key.Suggested change
- <li key={i} className={`div35 ${chat?.source === "user" ? "label1" : "label1"}`}> + <li key={chat?.updated_at ?? i} className={`div35 ${chat?.source === "user" ? "label1" : "label1"}`}>
127-127: Add optional chaining forchatHistory.lengthaccess.
chatHistoryis accessed without optional chaining here. WhilechatsToShowguards its own iteration, ifchatHistorybecomesundefinedbetween renders, this line would throw. For consistency with the defensive patterns used elsewhere in this component:Suggested fix
- isTalking={chat.source === "bot" && !isStreamingComplete && i === chatHistory.length - 1} + isTalking={chat.source === "bot" && !isStreamingComplete && i === chatHistory?.length - 1}src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx (5)
30-30: Moveaccess_tokenretrieval into auseMemoor store it in state.Reading from
sessionStorageon every render is inefficient. Additionally,letshould beconstsince the variable is never reassigned.Suggested improvement
- let access_token = sessionStorage.getItem(URL_PARAMS.ACCESS_TOKEN) + const access_token = useMemo(() => sessionStorage.getItem(URL_PARAMS.ACCESS_TOKEN), [])Or store it in state if it needs to be reactive to changes.
49-49: Confusing state setter name.The state variable is
isMutebut the setter issetNotMute, which inverts the expected naming convention. Consider renaming for clarity.Suggested fix
- const [isMute, setNotMute] = useState(true) + const [isMute, setIsMute] = useState(true)Then update all usages of
setNotMutetosetIsMute.
159-172: Redundant nested try-catch.The inner try-catch block at lines 161-165 is redundant since the outer catch block at lines 169-171 will handle any errors. This can be simplified.
Suggested simplification
const handleOnStopSpeaking = async () => { try { - try { - if (audioRef.current) await audioRef.current.pause() - } catch (error) { - console.error({ error }) - } + if (audioRef.current) await audioRef.current.pause() setHasOverRideId(null) setSentences([]) setIsNextAllowed(true) } catch (error) { console.error({ error }) } }
563-585: Same redundant nested try-catch pattern.Apply the same simplification suggested for
handleOnStopSpeaking.
399-414: WebSocket message ordering relies on implicit queueing behavior.The code calls
connectToWebSocket()followed bysendMessage()calls. When the socket is inCONNECTINGstate, messages are automatically queued insocketQueue(seeuseChatWebhook.jslines 76-78) and flushed in order when the connection opens (lines 25-29). This works correctly but the behavior is not obvious from the code. Consider adding a comment explaining that messages are queued during connection establishment.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsxsrc/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsxsrc/utils/sorts.js
🚧 Files skipped from review as they are similar to previous changes (1)
- src/utils/sorts.js
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-23T16:55:04.450Z
Learnt from: pinkman7009
Repo: ELEVATE-Project/mohini-app-frontend PR: 218
File: src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/ActionItems.jsx:318-320
Timestamp: 2025-12-23T16:55:04.450Z
Learning: In ActionItems.jsx (src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/ActionItems.jsx), the action list is intentionally refetched every time the objective changes. The commented-out guard and the useEffect dependency on `objective` are part of the expected design for handling objective regeneration flows.
Applied to files:
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsxsrc/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx
📚 Learning: 2026-01-11T21:08:05.729Z
Learnt from: pinkman7009
Repo: ELEVATE-Project/mohini-app-frontend PR: 223
File: src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx:416-439
Timestamp: 2026-01-11T21:08:05.729Z
Learning: In the SelectObjective.jsx component (src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx), objectives are guaranteed to have unique text values, so text-based equality comparison is safe for determining objective selection without risk of duplicate matches.
Applied to files:
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx
🧬 Code graph analysis (2)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx (10)
src/configure.js (2)
bot_routes(22-42)bot_routes(22-42)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/chat-message/ChatMessage.jsx (1)
CONVERSATION_USER_TYPES(7-7)src/pages/ai-creation/pages/shikshalokam-mitra/MainPage.jsx (2)
chatHistory(56-56)audioRef(87-87)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/InitialSwitch.jsx (1)
setSessionStore(41-46)src/hooks/useChatWebhook.js (3)
useChatWebhook(3-99)useChatWebhook(3-99)sendMessage(72-80)src/api/endpoints/chat.js (1)
data(31-31)src/pages/shikshalokamChat.js (1)
setProfileId(38-38)src/constants/session.js (2)
DEFAULT_COMPANY_SLUG(8-8)DEFAULT_COMPANY_SLUG(8-8)src/components/ToastMessage/TotastMessage.jsx (1)
Notification(6-23)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/LoadingChat.jsx (1)
LoadingChat(1-8)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx (4)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx (3)
chatHistory(32-32)hasStartedListening(46-46)isStreamingComplete(44-44)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/DefineChallenge.jsx (3)
chatHistory(54-56)hasStartedListening(62-62)isStreamingComplete(60-60)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ConversationWrapperCard.jsx (1)
containerRef(4-4)src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/LoadingChat.jsx (1)
LoadingChat(1-8)
🔇 Additional comments (2)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx (1)
16-50: LGTM on the defensive array check.The
Array.isArray(chatHistory)guard at line 49 properly handles cases wherechatHistorymight not be an array, aligning with the PR's robustness improvements. The optional chaining throughout the function provides good defensive coding.src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx (1)
587-614: LGTM - Clean render logic and well-designed helper.The conditional rendering with loading states is appropriate. The
createMessagehelper with sensible defaults is a good pattern for consistent message creation.
| const objectiveList = useAICreationSessionStore.getState().getObjective() | ||
| const allObjectiveChatHistory = useAICreationSessionStore.getState().getObjectiveChatHistory() | ||
| const allActionListChatHistory = useAICreationSessionStore.getState().getActionListChatHistory() | ||
| const selectedObjective = useAICreationSessionStore(state => state.selectedObjective) | ||
| const selectedAction = useAICreationSessionStore(state => state.selectedAction) | ||
| const selectedWeek = useAICreationSessionStore.getState().getSelectedWeek() | ||
| const selectedFlowType = useAICreationSessionStore.getState().getSelectedFlowType() | ||
| const errorText = useAICreationSessionStore.getState().getErrorText() |
There was a problem hiding this comment.
Inconsistent store subscriptions may cause stale UI.
Lines 7-9 and 12-14 use getState() which reads state once without subscribing to changes. If objectiveList, allObjectiveChatHistory, selectedWeek, selectedFlowType, or errorText change in the store, this component won't re-render, causing the loading indicator logic in getShowLoadingChat to use stale values.
Lines 10-11 correctly use the subscription pattern. Apply the same pattern to the other selectors:
Suggested fix
- const objectiveList = useAICreationSessionStore.getState().getObjective()
- const allObjectiveChatHistory = useAICreationSessionStore.getState().getObjectiveChatHistory()
- const allActionListChatHistory = useAICreationSessionStore.getState().getActionListChatHistory()
+ const objectiveList = useAICreationSessionStore(state => state.getObjective())
+ const allObjectiveChatHistory = useAICreationSessionStore(state => state.getObjectiveChatHistory())
+ const allActionListChatHistory = useAICreationSessionStore(state => state.getActionListChatHistory())
const selectedObjective = useAICreationSessionStore(state => state.selectedObjective)
const selectedAction = useAICreationSessionStore(state => state.selectedAction)
- const selectedWeek = useAICreationSessionStore.getState().getSelectedWeek()
- const selectedFlowType = useAICreationSessionStore.getState().getSelectedFlowType()
- const errorText = useAICreationSessionStore.getState().getErrorText()
+ const selectedWeek = useAICreationSessionStore(state => state.getSelectedWeek())
+ const selectedFlowType = useAICreationSessionStore(state => state.getSelectedFlowType())
+ const errorText = useAICreationSessionStore(state => state.getErrorText())Note: If the getter functions derive state from other store properties, ensure the selector returns a stable reference or use a shallow equality check to avoid unnecessary re-renders.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const objectiveList = useAICreationSessionStore.getState().getObjective() | |
| const allObjectiveChatHistory = useAICreationSessionStore.getState().getObjectiveChatHistory() | |
| const allActionListChatHistory = useAICreationSessionStore.getState().getActionListChatHistory() | |
| const selectedObjective = useAICreationSessionStore(state => state.selectedObjective) | |
| const selectedAction = useAICreationSessionStore(state => state.selectedAction) | |
| const selectedWeek = useAICreationSessionStore.getState().getSelectedWeek() | |
| const selectedFlowType = useAICreationSessionStore.getState().getSelectedFlowType() | |
| const errorText = useAICreationSessionStore.getState().getErrorText() | |
| const objectiveList = useAICreationSessionStore(state => state.getObjective()) | |
| const allObjectiveChatHistory = useAICreationSessionStore(state => state.getObjectiveChatHistory()) | |
| const allActionListChatHistory = useAICreationSessionStore(state => state.getActionListChatHistory()) | |
| const selectedObjective = useAICreationSessionStore(state => state.selectedObjective) | |
| const selectedAction = useAICreationSessionStore(state => state.selectedAction) | |
| const selectedWeek = useAICreationSessionStore(state => state.getSelectedWeek()) | |
| const selectedFlowType = useAICreationSessionStore(state => state.getSelectedFlowType()) | |
| const errorText = useAICreationSessionStore(state => state.getErrorText()) |
🤖 Prompt for AI Agents
In
@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/ChatWindow.jsx
around lines 7 - 14, Several selectors use useAICreationSessionStore.getState()
which reads once and won't subscribe to updates, causing stale UI (e.g.,
objectiveList, allObjectiveChatHistory, selectedWeek, selectedFlowType,
errorText); change these to use the reactive selector form
useAICreationSessionStore(state => state.<property>) so the component subscribes
and re-renders on changes, and ensure derived getters return stable references
or use shallow equality if needed to avoid unnecessary re-renders (apply this to
objectiveList, allObjectiveChatHistory, selectedWeek, selectedFlowType,
errorText to match selectedObjective/selectedAction).
| const chat_history = [...getChatHistory()] | ||
| if (chatHistory[chatHistory?.length - 1]?.source === BOT) { | ||
| const lastMessage = chat_history[chat_history?.length - 1] | ||
| lastMessage.msg += " " + sentence | ||
| setChatHistory(chat_history) | ||
| } else { | ||
| chat_history.push({ | ||
| msg: sentence, | ||
| source: BOT, | ||
| }) | ||
| setChatHistory(chat_history) | ||
| } |
There was a problem hiding this comment.
Object mutation through shallow copy (same issue as earlier).
lastMessage.msg += " " + sentence mutates the original object. Apply the same fix as suggested for onWebSocketMessage.
Suggested fix
const chat_history = [...getChatHistory()]
if (chatHistory[chatHistory?.length - 1]?.source === BOT) {
- const lastMessage = chat_history[chat_history?.length - 1]
- lastMessage.msg += " " + sentence
+ chat_history[chat_history.length - 1] = {
+ ...chat_history[chat_history.length - 1],
+ msg: chat_history[chat_history.length - 1].msg + " " + sentence,
+ }
setChatHistory(chat_history)
} else {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const chat_history = [...getChatHistory()] | |
| if (chatHistory[chatHistory?.length - 1]?.source === BOT) { | |
| const lastMessage = chat_history[chat_history?.length - 1] | |
| lastMessage.msg += " " + sentence | |
| setChatHistory(chat_history) | |
| } else { | |
| chat_history.push({ | |
| msg: sentence, | |
| source: BOT, | |
| }) | |
| setChatHistory(chat_history) | |
| } | |
| const chat_history = [...getChatHistory()] | |
| if (chatHistory[chatHistory?.length - 1]?.source === BOT) { | |
| chat_history[chat_history.length - 1] = { | |
| ...chat_history[chat_history.length - 1], | |
| msg: chat_history[chat_history.length - 1].msg + " " + sentence, | |
| } | |
| setChatHistory(chat_history) | |
| } else { | |
| chat_history.push({ | |
| msg: sentence, | |
| source: BOT, | |
| }) | |
| setChatHistory(chat_history) | |
| } |
🤖 Prompt for AI Agents
In
@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/StateMachineDefineChallenge.jsx
around lines 444 - 455, The code mutates the last message object via
lastMessage.msg += " " + sentence; instead, create immutable copies: build a new
message object (copying properties and updating msg) and replace the last
element in a new chat array before calling setChatHistory; reference the
variables/functions chat_history, getChatHistory(), chatHistory, BOT,
lastMessage, setChatHistory and mirror the non-mutating approach used in
onWebSocketMessage to avoid shallow-copy mutation.
- Enhanced readability by reorganizing imports and formatting code. - Updated loading chat logic to ensure proper handling of chat history and loading states. - Streamlined the use of hooks and conditional rendering for better performance and maintainability.
- Reorganized imports for improved readability and consistency. - Streamlined state initialization and effect hooks for better performance. - Enhanced loading state handling and conditional rendering logic. - Improved overall code clarity and maintainability.
- Reorganized imports for better clarity and consistency. - Enhanced formatting of the ChatMessage function for improved readability. - Streamlined conditional rendering for BotMessage and UserMessage components. - Ensured consistent use of semicolons and code style throughout the file.
…ement - Added a getter for stateMachineLength in the chat data store for better state access. - Updated StateMachineDefineChallenge to utilize the new getter, enhancing clarity and maintainability. - Improved conditional logic by using the retrieved stateMachineLength value directly.
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
Summary by CodeRabbit
New Features
Refactor
Chores
✏️ Tip: You can customize this high-level summary in your review settings.