From d94fd0e61b484d85269188a76568965235de49bc Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 17 Jul 2026 18:12:47 -0700 Subject: [PATCH] FN-8257: retain quick chat state when closed Keep Quick Chat mounted after its first opening so closing and reopening preserves its session and scroll state. - Add an opt-in hidden state for FloatingWindow that suspends invisible-window effects. - Retain Quick Chat per project while resetting its React identity on project changes. - Cover persistent close/reopen behavior and hidden floating-window semantics. Files changed: packages/dashboard/app/App.tsx | 25 ++++- .../dashboard/app/components/FloatingWindow.css | 10 ++ .../dashboard/app/components/FloatingWindow.tsx | 38 +++++-- .../components/__tests__/FloatingWindow.test.tsx | 90 +++++++++++++++- .../__tests__/QuickChat.persist.test.tsx | 120 +++++++++++++++++++++ 5 files changed, 274 insertions(+), 9 deletions(-) Fusion-Task-Id: FN-8257 Fusion-Task-Lineage: 6b0cd41c-32e8-4cd4-8c0c-82d0254aa1e4 Co-authored-by: Fusion (runfusion.ai) --- packages/dashboard/app/App.tsx | 25 +++- .../app/components/FloatingWindow.css | 10 ++ .../app/components/FloatingWindow.tsx | 38 +++++- .../__tests__/FloatingWindow.test.tsx | 90 ++++++++++++- .../__tests__/QuickChat.persist.test.tsx | 120 ++++++++++++++++++ 5 files changed, 274 insertions(+), 9 deletions(-) create mode 100644 packages/dashboard/app/components/__tests__/QuickChat.persist.test.tsx diff --git a/packages/dashboard/app/App.tsx b/packages/dashboard/app/App.tsx index 5dfd2474d6..817ac09686 100644 --- a/packages/dashboard/app/App.tsx +++ b/packages/dashboard/app/App.tsx @@ -568,6 +568,27 @@ function AppInner() { }, [initialLoadComplete]); const [quickChatOpen, setQuickChatOpen] = useState(false); + const [quickChatEverOpenedProjectId, setQuickChatEverOpenedProjectId] = useState(null); + const quickChatProjectIdRef = useRef(undefined); + + /* + FNXC:ChatModal 2026-07-18-00:00: + FN-8257 requires Quick Chat to mount only after its first open, then remain mounted and hidden + across close/reopen so ChatView retains its selected session, transcript, and scroll position. + Reset the latch when the project changes so a hidden ChatView cannot leak one project's state + into another project; the FloatingWindow key supplies the matching React identity boundary. + */ + useEffect(() => { + const projectId = currentProject?.id; + if (quickChatProjectIdRef.current !== projectId) { + quickChatProjectIdRef.current = projectId; + setQuickChatEverOpenedProjectId(quickChatOpen && projectId ? projectId : null); + return; + } + if (quickChatOpen && projectId) { + setQuickChatEverOpenedProjectId(projectId); + } + }, [currentProject?.id, quickChatOpen]); const { keyboardOpen } = useMobileKeyboard({ enabled: isMobile }); // Keyboard visibility controls both MobileNavBar rendering and whether @@ -1829,9 +1850,11 @@ function AppInner() { onOpenChange={setQuickChatOpen} /> )} - {quickChatOpen && currentProject && ( + {currentProject && quickChatEverOpenedProjectId === currentProject.id && (