From 2705b30f64e0431cfa0de056dc853e24e143df7d Mon Sep 17 00:00:00 2001 From: Frederick Legaspi Date: Tue, 4 Nov 2025 12:44:14 -0500 Subject: [PATCH 1/2] fix: prevent timestamp updates during conversation loads (complete fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found three locations where saveConversation() was updating timestamps during conversation loads, causing list to reorder: 1. ✅ saveConversation() itself - added updateTimestamp parameter (PR #23) 2. ✅ handleLoadConversation() - now uses updateTimestamp: false 3. ✅ Auto-save effect - now uses updateTimestamp: false The auto-save effect was triggering when currentConversationId changed during load. Even with isLoadingConversationRef flag, the effect would run and update the timestamp. Solution: - Auto-save effect now uses updateTimestamp: false to prevent timestamp updates when just preserving state - Explicit timestamp update added in onComplete callback when user sends new messages (the only time we actually want to update the timestamp) This ensures conversations only move to top when users send new messages, not when just selecting from history. Fixes persistent sorting issue confirmed by user. --- src/app/page.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index 15c6fc3..7e604cb 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -134,7 +134,7 @@ export default function Home() { // Update existing conversation with current ID and title from ref const conversation = createConversation(messages, files, aiTheme || undefined, conversationTitleRef.current); conversation.id = currentConversationId; - saveConversation(conversation); // This will update timestamp when content actually changes + saveConversation(conversation, false); // Don't update timestamp in auto-save - only when user sends messages } } } @@ -181,7 +181,7 @@ export default function Home() { const currentConversation = createConversation(messages, files, aiTheme || undefined); currentConversation.id = currentConversationId; currentConversation.title = conversationTitle; // Preserve current title - saveConversation(currentConversation); + saveConversation(currentConversation, false); // Don't update timestamp when just saving before switch } // Load selected conversation @@ -269,7 +269,16 @@ export default function Home() { onComplete: (fullText) => { // Add the complete message to history const aiMessage: Message = { id: aiMessageId, role: 'ai', content: fullText }; - setMessages((prev) => [...prev, aiMessage]); + setMessages((prev) => { + const newMessages = [...prev, aiMessage]; + // Explicitly save with timestamp update when conversation actually has new content + if (currentConversationId) { + const conversation = createConversation(newMessages, files, aiTheme || undefined, conversationTitleRef.current); + conversation.id = currentConversationId; + saveConversation(conversation, true); // Update timestamp for new messages + } + return newMessages; + }); setStreamingMessageId(null); setPending(false); }, From b59cd4d9fdf42ed83d1f517a1df35d9663b1522f Mon Sep 17 00:00:00 2001 From: Frederick Legaspi Date: Tue, 4 Nov 2025 12:48:06 -0500 Subject: [PATCH 2/2] fix: remove currentConversationId from auto-save effect dependencies The root cause was the auto-save effect depending on currentConversationId. When loading a conversation, setCurrentConversationId() would trigger the effect, causing an unwanted save that updated the timestamp. Changes: 1. Removed currentConversationId from effect dependencies 2. Removed "|| currentConversationId" from the if condition (only save when there are messages) 3. Added explicit saveConversation(conversation, true) in onComplete callback to update timestamp when user sends messages 4. Updated comments to explain why currentConversationId is not in dependencies This ensures the effect only runs when actual content (messages, files, aiTheme) changes, not when just switching conversations. Fixes the persistent sorting issue where conversations jump to top when selected. --- src/app/page.tsx | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index 7e604cb..08a1d65 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -121,26 +121,29 @@ export default function Home() { // Auto-save conversation when messages or sources change useEffect(() => { if (isLoaded && !isLoadingConversationRef.current) { // Don't save while loading - // Save if we have messages OR if we have a conversation ID (empty conversation with title) - if (messages.length > 0 || currentConversationId) { - // If we don't have a current conversation ID, create new one with auto-generated title + // Only save when we have actual content (messages) + // Don't trigger on currentConversationId changes (that happens when loading) + if (messages.length > 0) { if (!currentConversationId) { + // Create new conversation with auto-generated title const conversation = createConversation(messages, files, aiTheme || undefined); setCurrentConversationIdState(conversation.id); setCurrentConversationId(conversation.id); - setConversationTitle(conversation.title); // Set auto-generated title + setConversationTitle(conversation.title); saveConversation(conversation); } else { - // Update existing conversation with current ID and title from ref + // Update existing conversation - don't update timestamp (only happens when user sends message) const conversation = createConversation(messages, files, aiTheme || undefined, conversationTitleRef.current); conversation.id = currentConversationId; - saveConversation(conversation, false); // Don't update timestamp in auto-save - only when user sends messages + saveConversation(conversation, false); } } } - // Note: conversationTitle is NOT in dependencies because title updates are handled by handleTitleChange + // Note: conversationTitle and currentConversationId are NOT in dependencies + // - conversationTitle updates are handled by handleTitleChange + // - currentConversationId changes happen during loads (we don't want to trigger saves then) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [messages, files, aiTheme, currentConversationId, isLoaded]); + }, [messages, files, aiTheme, isLoaded]); const handleNewConversation = () => { // Save current conversation before creating new one @@ -269,18 +272,16 @@ export default function Home() { onComplete: (fullText) => { // Add the complete message to history const aiMessage: Message = { id: aiMessageId, role: 'ai', content: fullText }; - setMessages((prev) => { - const newMessages = [...prev, aiMessage]; - // Explicitly save with timestamp update when conversation actually has new content - if (currentConversationId) { - const conversation = createConversation(newMessages, files, aiTheme || undefined, conversationTitleRef.current); - conversation.id = currentConversationId; - saveConversation(conversation, true); // Update timestamp for new messages - } - return newMessages; - }); + setMessages((prev) => [...prev, aiMessage]); setStreamingMessageId(null); setPending(false); + + // Explicitly save with timestamp update when conversation has new content + if (currentConversationId) { + const conversation = createConversation([...messages, userMessage, aiMessage], files, aiTheme || undefined, conversationTitleRef.current); + conversation.id = currentConversationId; + saveConversation(conversation, true); // Update timestamp for new messages + } }, onError: (error) => { toast({