diff --git a/client/src/App.tsx b/client/src/App.tsx index 667b077..f82e3c6 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react' +import { useState, useEffect, useCallback, useRef } from 'react' import './App.css' import { DialogProvider } from './components/ModalDialog.tsx' import AuthOnboarding from './components/AuthOnboarding.tsx' @@ -69,6 +69,12 @@ function App() { const [isSyncing, setIsSyncing] = useState(false) const [isAcceptingInvite, setIsAcceptingInvite] = useState(false) const [showUserProfile, setShowUserProfile] = useState(false) + const tourLogbookRef = useRef<{ id: string; title: string } | null>(null) + const activeLogbookRef = useRef<{ id: string | null; title: string | null }>({ + id: activeLogbookId, + title: activeLogbookTitle + }) + activeLogbookRef.current = { id: activeLogbookId, title: activeLogbookTitle } // Viewer mode for read-only shared links const [isViewerMode, setIsViewerMode] = useState(false) @@ -313,7 +319,32 @@ function App() { registerNavigation({ setActiveTab, setSelectedEntryId: setTourSelectedEntryId, - setFeedbackOpen: setTourFeedbackOpen + setFeedbackOpen: setTourFeedbackOpen, + setProfileOpen: setShowUserProfile, + setLogbookActive: (active) => { + if (active) { + const saved = tourLogbookRef.current + const id = saved?.id ?? localStorage.getItem('active_logbook_id') + const title = saved?.title ?? localStorage.getItem('active_logbook_title') + if (id && title) { + setActiveLogbookId(id) + setActiveLogbookTitle(title) + localStorage.setItem('active_logbook_id', id) + localStorage.setItem('active_logbook_title', title) + } + return + } + + const { id, title } = activeLogbookRef.current + if (id && title) { + tourLogbookRef.current = { id, title } + } + setActiveLogbookId(null) + setActiveLogbookTitle(null) + setTourSelectedEntryId(null) + localStorage.removeItem('active_logbook_id') + localStorage.removeItem('active_logbook_title') + } }) }, [registerNavigation]) diff --git a/client/src/components/AppTourOverlay.tsx b/client/src/components/AppTourOverlay.tsx index 0f45b38..8e06b04 100644 --- a/client/src/components/AppTourOverlay.tsx +++ b/client/src/components/AppTourOverlay.tsx @@ -4,6 +4,7 @@ import { X, ChevronLeft, ChevronRight } from 'lucide-react' import { getTourStepCopy, getTourTargetSelector, + getTourTargetRetryDelay, isCenteredTourStep, useAppTour } from '../context/AppTourContext.tsx' @@ -89,10 +90,15 @@ export default function AppTourOverlay() { updateSpotlight() window.addEventListener('resize', updateSpotlight) window.addEventListener('scroll', updateSpotlight, true) - const timer = window.setTimeout(updateSpotlight, 120) + const retryDelay = getTourTargetRetryDelay(currentStepId) + const timer = window.setTimeout(updateSpotlight, retryDelay) + const retryTimer = retryDelay > 120 + ? window.setTimeout(updateSpotlight, retryDelay + 180) + : undefined return () => { window.clearTimeout(timer) + if (retryTimer !== undefined) window.clearTimeout(retryTimer) window.removeEventListener('resize', updateSpotlight) window.removeEventListener('scroll', updateSpotlight, true) } diff --git a/client/src/components/LogbookDashboard.tsx b/client/src/components/LogbookDashboard.tsx index 7bc0fe5..1a3eb25 100644 --- a/client/src/components/LogbookDashboard.tsx +++ b/client/src/components/LogbookDashboard.tsx @@ -314,6 +314,7 @@ export default function LogbookDashboard({ onSelectLogbook, onLogout, onOpenProf onClick={onOpenProfile} title={t('dashboard.open_profile', { name: username })} aria-label={t('dashboard.open_profile', { name: username })} + data-tour="nav-profile" >