@@ -22,7 +22,7 @@ import {
2222} from "../utils/formatters"
2323import { debugLog } from "../utils/debug"
2424import { appState } from "../state/AppState"
25- import { loadMessages , loadContacts } from "./ConversationView"
25+ import { loadMessages , loadContacts , destroyConversationScrollBox } from "./ConversationView"
2626import { ROW_HEIGHT } from "../utils/chatListScroll"
2727
2828interface ChatRowData {
@@ -88,6 +88,9 @@ class ChatListManager {
8888 // CASE 1: exact same content (no changes)
8989 if ( this . scrollBox && newContentHash === this . currentChatsHash ) {
9090 debugLog ( "ChatListManager" , "Using cached chat list (exact match)" )
91+ // Still need to update selection/active styling as those may have changed
92+ const state = appState . getState ( )
93+ this . updateSelectionAndActive ( state . selectedChatIndex , state . currentChatId , chats )
9194 return this . scrollBox
9295 }
9396
@@ -188,6 +191,10 @@ class ChatListManager {
188191 }
189192 }
190193
194+ // Capture index and chat reference for click handler closure
195+ const chatIndex = index
196+ const chatRef = chat
197+
191198 // Create chat row box
192199 // Use simple ID to enable in-place updates (no hash in ID)
193200 const rowId = `chat-row-${ index } `
@@ -204,26 +211,32 @@ class ChatListManager {
204211 : isCurrentChat
205212 ? WhatsAppTheme . activeBg
206213 : WhatsAppTheme . panelDark ,
207- } )
208-
209- // Handle click to open chat using the filtered chat
210- const chatIndex = index // Capture for closure
211- const chatRef = chat // Capture chat reference for closure
212- chatRow . on ( "click" , async ( ) => {
213- const currentState = appState . getState ( )
214- appState . setSelectedChatIndex ( chatIndex )
215- if ( chatRef && currentState . currentSession ) {
216- appState . setCurrentView ( "conversation" )
217- appState . setCurrentChat ( chatRef . id )
218-
219- // When switching chats, we want to start polling for messages immediately
220- // BUT we need to be careful not to create circular dependency imports
221- // PollingService imports ConversationView, so ConversationView/ChatListManager shouldn't import PollingService if possible
222- // Ideally PollingService observes state changes.
223-
224- await loadMessages ( currentState . currentSession , chatRef . id )
225- await loadContacts ( currentState . currentSession )
226- }
214+ // Handle click (mouse down) to open chat
215+ onMouse : ( event ) => {
216+ if ( event . type === "down" ) {
217+ const currentState = appState . getState ( )
218+ if ( chatRef && currentState . currentSession ) {
219+ // Extract chat ID properly (handle _serialized property)
220+ const chatId =
221+ typeof chatRef . id === "string"
222+ ? chatRef . id
223+ : ( chatRef . id as { _serialized : string } ) . _serialized
224+
225+ debugLog ( "ChatListManager" , `Clicked chat: ${ chatRef . name || chatId } ` )
226+
227+ // Destroy old scroll box before loading new messages
228+ destroyConversationScrollBox ( )
229+
230+ // Set current chat first (this changes view to "conversation")
231+ appState . setCurrentChat ( chatId )
232+ appState . setSelectedChatIndex ( chatIndex )
233+
234+ // Load contacts and messages
235+ loadContacts ( currentState . currentSession )
236+ loadMessages ( currentState . currentSession , chatId )
237+ }
238+ }
239+ } ,
227240 } )
228241
229242 // Avatar
@@ -375,6 +388,44 @@ class ChatListManager {
375388 }
376389 }
377390
391+ /**
392+ * Update selection and active (current chat) highlighting for all rows
393+ * This handles both selectedChatIndex and currentChatId changes
394+ */
395+ private updateSelectionAndActive (
396+ newSelectedIndex : number ,
397+ currentChatId : string | null ,
398+ chats : ChatSummary [ ]
399+ ) : void {
400+ if ( ! this . scrollBox ) return
401+
402+ // Update all rows to reflect current selection and active state
403+ for ( let index = 0 ; index < chats . length ; index ++ ) {
404+ const rowData = this . chatRows . get ( index )
405+ if ( ! rowData ) continue
406+
407+ const chat = chats [ index ]
408+ const chatId =
409+ typeof chat . id === "string" ? chat . id : ( chat . id as { _serialized : string } ) . _serialized
410+
411+ const isSelected = index === newSelectedIndex
412+ const isCurrentChat = currentChatId === chatId
413+
414+ // Update background color
415+ rowData . box . backgroundColor = isSelected
416+ ? WhatsAppTheme . selectedBg
417+ : isCurrentChat
418+ ? WhatsAppTheme . activeBg
419+ : WhatsAppTheme . panelDark
420+
421+ // Update text attributes
422+ rowData . avatarText . attributes = isSelected ? TextAttributes . BOLD : TextAttributes . NONE
423+ rowData . nameText . attributes = isSelected ? TextAttributes . BOLD : TextAttributes . NONE
424+ }
425+
426+ this . currentSelectedIndex = newSelectedIndex
427+ }
428+
378429 /**
379430 * Update selection highlight - only changes styles, doesn't rebuild
380431 */
0 commit comments