diff --git a/apps/web/components/task/chat/use-chat-input-state.ts b/apps/web/components/task/chat/use-chat-input-state.ts index f7082be03f..0d98ec5bc8 100644 --- a/apps/web/components/task/chat/use-chat-input-state.ts +++ b/apps/web/components/task/chat/use-chat-input-state.ts @@ -1,4 +1,4 @@ -import { useRef, useCallback, useState, useEffect, useMemo } from "react"; +import { useRef, useCallback, useState, useEffect, useLayoutEffect, useMemo } from "react"; import { getChatDraftText, setChatDraftText, @@ -68,11 +68,30 @@ function useAttachments(sessionId: string | null) { ); const attachmentsRef = useRef(attachments); const prevSessionIdRef = useRef(sessionId); + const prevPersistSessionIdRef = useRef(sessionId); + // Reset attachments from storage when session changes (runs before paint) + useLayoutEffect(() => { + if (sessionId === prevSessionIdRef.current) return; + prevSessionIdRef.current = sessionId; + const newAttachments = sessionId + ? getChatDraftAttachments(sessionId).map(restoreAttachmentPreview) + : []; + /* eslint-disable react-hooks/set-state-in-effect -- syncing from localStorage on session switch */ + setAttachments(newAttachments); + /* eslint-enable react-hooks/set-state-in-effect */ + attachmentsRef.current = newAttachments; + }, [sessionId]); + + // Persist attachments to storage when they change (for the same session) useEffect(() => { + // Skip first invocation after session change to avoid overwriting freshly loaded attachments + if (sessionId !== prevPersistSessionIdRef.current) { + prevPersistSessionIdRef.current = sessionId; + return; + } attachmentsRef.current = attachments; - if (sessionId && prevSessionIdRef.current === sessionId) - setChatDraftAttachments(sessionId, attachments); + if (sessionId) setChatDraftAttachments(sessionId, attachments); }, [attachments, sessionId]); const addFiles = useCallback( @@ -102,7 +121,6 @@ function useAttachments(sessionId: string | null) { return { attachments, attachmentsRef, - prevSessionIdRef, setAttachments, addFiles, handleRemoveAttachment, @@ -124,23 +142,19 @@ export function useChatInputState({ const inputRef = useRef(null); const valueRef = useRef(value); const pendingCommentsRef = useRef(pendingCommentsByFile); + const prevTextSessionIdRef = useRef(sessionId); - const { - attachments, - attachmentsRef, - prevSessionIdRef, - setAttachments, - addFiles, - handleRemoveAttachment, - } = useAttachments(sessionId); + const { attachments, attachmentsRef, setAttachments, addFiles, handleRemoveAttachment } = + useAttachments(sessionId); - useEffect(() => { - if (sessionId === prevSessionIdRef.current) return; - prevSessionIdRef.current = sessionId; + // Reset text value from storage when session changes (runs before paint) + useLayoutEffect(() => { + if (sessionId === prevTextSessionIdRef.current) return; + prevTextSessionIdRef.current = sessionId; /* eslint-disable react-hooks/set-state-in-effect -- syncing from localStorage on session switch */ setValue(sessionId ? getChatDraftText(sessionId) : ""); /* eslint-enable react-hooks/set-state-in-effect */ - }, [sessionId, prevSessionIdRef]); + }, [sessionId]); useEffect(() => { valueRef.current = value;