Skip to content

Commit 3a89b4a

Browse files
do not repeat guided tours, do not show multiple guided tours
1 parent 3ee04a7 commit 3a89b4a

File tree

3 files changed

+100
-2
lines changed

3 files changed

+100
-2
lines changed

src/components/guided-modal-tour/index.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
* Internal dependencies
33
*/
44
import { TOUR_STEPS } from './tour-steps'
5+
import {
6+
setActiveTour,
7+
clearActiveTour,
8+
isTourActive,
9+
getActiveTourId,
10+
addTourStateListener,
11+
} from './util'
512

613
/**
714
* External dependencies
@@ -42,6 +49,17 @@ const GuidedModalTour = props => {
4249
// We need this to prevent the tour from being shown again if it's just completed.
4350
const [ justCompleted, setJustCompleted ] = useState( false )
4451

52+
// Check if another tour is already active
53+
const [ isAnotherTourActive, setIsAnotherTourActive ] = useState( isTourActive() && getActiveTourId() !== tourId )
54+
55+
// Listen for tour state changes
56+
useEffect( () => {
57+
const removeListener = addTourStateListener( activeId => {
58+
setIsAnotherTourActive( activeId !== null && activeId !== tourId )
59+
} )
60+
return removeListener
61+
}, [ tourId ] )
62+
4563
const {
4664
steps = [],
4765
condition = null,
@@ -53,6 +71,11 @@ const GuidedModalTour = props => {
5371
return null
5472
}
5573

74+
// If another tour is already active, don't show this tour
75+
if ( isAnotherTourActive ) {
76+
return null
77+
}
78+
5679
// If there is a condition, check if it's met, if not, don't show the tour.
5780
// condition can be true, false, or null. true will show the tour (even if
5881
// it's already done), false will not show the tour, null will show the tour
@@ -71,13 +94,17 @@ const GuidedModalTour = props => {
7194
}
7295

7396
return <ModalTour
97+
tourId={ tourId }
7498
steps={ steps }
7599
hasConfetti={ hasConfetti }
76100
initialize={ initialize }
77101
onClose={ () => {
78102
setIsDone( true )
79103
setJustCompleted( true )
80104

105+
// Clear the active tour
106+
clearActiveTour()
107+
81108
// Update the stackable_guided_tour_states setting
82109
if ( ! guidedTourStates.includes( tourId ) ) {
83110
// eslint-disable-next-line camelcase
@@ -98,6 +125,7 @@ const GuidedModalTour = props => {
98125

99126
const ModalTour = props => {
100127
const {
128+
tourId,
101129
steps,
102130
onClose = NOOP,
103131
hasConfetti = true,
@@ -141,6 +169,22 @@ const ModalTour = props => {
141169
}, 50 )
142170
}, [ initialize ] )
143171

172+
// Set active tour when modal becomes visible
173+
useEffect( () => {
174+
if ( isVisible ) {
175+
setActiveTour( tourId )
176+
}
177+
}, [ isVisible, tourId ] )
178+
179+
// Clear active tour when component unmounts
180+
useEffect( () => {
181+
return () => {
182+
if ( getActiveTourId() === tourId ) {
183+
clearActiveTour()
184+
}
185+
}
186+
}, [ tourId ] )
187+
144188
// While the modal is visible, just keep on force refreshing the modal in an interval to make sure the modal is always in the correct position.
145189
useEffect( () => {
146190
let interval

src/components/guided-modal-tour/tours/editor.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { __ } from '@wordpress/i18n'
2-
import { i18n } from 'stackable'
2+
import { i18n, guidedTourStates } from 'stackable'
33
import { createInterpolateElement } from '@wordpress/element'
44

55
export const editor = {
66
hasConfetti: false,
77
condition: () => { // If provided, true will show the tour (even if it's already done), false will not show the tour, null will show the tour only once.
88
// Do not show the tour if there is a GET parameter that shows another tour.
9-
return window?.location?.search?.includes( 'tour=' ) ? false : null
9+
return window?.location?.search?.includes( 'tour=' ) ? false
10+
: guidedTourStates.includes( 'design-library' ) ? false : null
1011
},
1112
steps: [
1213
{
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Global tour state management utilities
3+
*
4+
* This module provides functions to manage the global state of guided modal tours,
5+
* ensuring that only one tour can be active at a time.
6+
*/
7+
8+
// Global tour state
9+
let activeTourId = null
10+
const tourStateListeners = new Set()
11+
12+
/**
13+
* Set the currently active tour
14+
*
15+
* @param {string} tourId - The ID of the tour to set as active
16+
*/
17+
export const setActiveTour = tourId => {
18+
activeTourId = tourId
19+
tourStateListeners.forEach( listener => listener( tourId ) )
20+
}
21+
22+
/**
23+
* Clear the currently active tour
24+
*/
25+
export const clearActiveTour = () => {
26+
activeTourId = null
27+
tourStateListeners.forEach( listener => listener( null ) )
28+
}
29+
30+
/**
31+
* Check if any tour is currently active
32+
*
33+
* @return {boolean} True if a tour is active, false otherwise
34+
*/
35+
export const isTourActive = () => activeTourId !== null
36+
37+
/**
38+
* Get the currently active tour ID
39+
*
40+
* @return {string|null} The active tour ID or null if no tour is active
41+
*/
42+
export const getActiveTourId = () => activeTourId
43+
44+
/**
45+
* Add a listener for tour state changes
46+
*
47+
* @param {Function} listener - Function to call when tour state changes
48+
* @return {Function} Function to remove the listener
49+
*/
50+
export const addTourStateListener = listener => {
51+
tourStateListeners.add( listener )
52+
return () => tourStateListeners.delete( listener )
53+
}

0 commit comments

Comments
 (0)