From 8608d32dbda9843bccc8640d02e7ef536b5f3f25 Mon Sep 17 00:00:00 2001 From: Haileyesus Date: Sat, 7 Feb 2026 16:58:47 +0300 Subject: [PATCH] fix(mobile): prevent menu tap from triggering unintended dashboard navigation The mobile sidebar menu button redirects users to `cloudcli.ai/dashboard` when a session was active. The redirect happened because the menu was opened on `touchstart`, which mounted the sidebar before the touch sequence completed; the follow-up tap/click then landed on the sidebar header anchor. This change rewrites mobile menu interaction handling in `MainContent.jsx` to eliminate touch/click event leakage and ghost-click behavior. Key changes: - Added `suppressNextMenuClickRef` to guard against synthetic click events that fire after a touch interaction. - Added `openMobileMenu(event)` helper to centralize `preventDefault`, `stopPropagation`, and `onMenuClick()` invocation. - Added `handleMobileMenuTouchEnd(event)`: - opens the menu on `touchend` instead of `touchstart` - sets a short suppression window (350ms) for the next click. - Added `handleMobileMenuClick(event)`: - ignores/suppresses click events during the suppression window - otherwise opens the menu normally. - Updated all mobile menu button instances in `MainContent.jsx` (loading state, no-project state, active header state) to use: - `onTouchEnd={handleMobileMenuTouchEnd}` - `onClick={handleMobileMenuClick}` - Removed the previous `onTouchStart` path that caused premature DOM mutation. Behavioral impact: - Mobile sidebar still opens reliably with one tap. - Tap no longer leaks to newly-mounted sidebar header links. - Prevents accidental redirects while preserving existing menu UX. --- src/components/MainContent.jsx | 44 +++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/components/MainContent.jsx b/src/components/MainContent.jsx index 58daf4f..fb7002e 100644 --- a/src/components/MainContent.jsx +++ b/src/components/MainContent.jsx @@ -63,6 +63,7 @@ function MainContent({ const [isResizing, setIsResizing] = useState(false); const [editorExpanded, setEditorExpanded] = useState(false); const resizeRef = useRef(null); + const suppressNextMenuClickRef = useRef(false); const { preferences } = useUiPreferences(); const { autoExpandTools, showRawParameters, showThinking, autoScrollToBottom, sendByCtrlEnter } = preferences; @@ -164,6 +165,34 @@ function MainContent({ refreshTasks?.(); }; + const openMobileMenu = (event) => { + if (event) { + event.preventDefault(); + event.stopPropagation(); + } + + onMenuClick(); + }; + + const handleMobileMenuTouchEnd = (event) => { + suppressNextMenuClickRef.current = true; + openMobileMenu(event); + + window.setTimeout(() => { + suppressNextMenuClickRef.current = false; + }, 350); + }; + + const handleMobileMenuClick = (event) => { + if (suppressNextMenuClickRef.current) { + event.preventDefault(); + event.stopPropagation(); + return; + } + + openMobileMenu(event); + }; + // Handle resize functionality const handleMouseDown = (e) => { if (isMobile) return; // Disable resize on mobile @@ -218,7 +247,8 @@ function MainContent({ className="bg-background border-b border-border p-2 sm:p-3 pwa-header-safe flex-shrink-0" >