Skip to content

Commit 27350a5

Browse files
authored
bugfix/allow-users-to-close-tour-if-local-storage-mismatch (#61)
1 parent b9da8eb commit 27350a5

1 file changed

Lines changed: 47 additions & 1 deletion

File tree

frontend/components/onboarding/onboarding-tour.tsx

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export function OnboardingTour() {
4242
const router = useRouter()
4343
const [run, setRun] = useState(getInitialRun)
4444
const [stepIndex, setStepIndex] = useState(getInitialStepIndex)
45+
const [targetMissing, setTargetMissing] = useState(false)
4546
const prevPathnameRef = useRef(pathname)
4647
const originPathRef = useRef<string | null>(null)
4748
const tourActive = run && pathname !== UNAUTHORISED_PATH
@@ -78,6 +79,30 @@ export function OnboardingTour() {
7879
queueMicrotask(() => setRun(true))
7980
}, [])
8081

82+
// When the tour is resumed on a page that doesn't contain the current
83+
// step's target (e.g. the page is reloaded with a mid-tour step index in
84+
// local storage), react-joyride renders its grey overlay but never renders
85+
// the tooltip - leaving the user with a grey screen and no close button.
86+
// Detect that case so we can let them click the overlay to close the tour.
87+
useEffect(() => {
88+
setTargetMissing(false)
89+
90+
if (!tourActive) return
91+
92+
const currentStep = steps[stepIndex]
93+
const target = currentStep?.target
94+
if (typeof target !== 'string') return
95+
96+
// Give react-joyride's own target polling (targetWaitTimeout) a chance to
97+
// find the element first, so we don't fire during normal navigation when
98+
// the target appears a moment after the route changes.
99+
const timeout = setTimeout(() => {
100+
setTargetMissing(!document.querySelector(target))
101+
}, 1200)
102+
103+
return () => clearTimeout(timeout)
104+
}, [tourActive, steps, stepIndex, pathname])
105+
81106
useEffect(() => {
82107
window.addEventListener(RESTART_ONBOARDING_TOUR_EVENT, restartTour)
83108
return () =>
@@ -168,5 +193,26 @@ export function OnboardingTour() {
168193
},
169194
})
170195

171-
return Tour
196+
return (
197+
<>
198+
{Tour}
199+
{tourActive && targetMissing && (
200+
<div
201+
role="button"
202+
aria-label="Close tour"
203+
tabIndex={0}
204+
onClick={finishTour}
205+
onKeyDown={(event) => {
206+
if (event.key === 'Enter' || event.key === ' ') finishTour()
207+
}}
208+
style={{
209+
position: 'fixed',
210+
inset: 0,
211+
zIndex: 10000,
212+
cursor: 'pointer',
213+
}}
214+
/>
215+
)}
216+
</>
217+
)
172218
}

0 commit comments

Comments
 (0)