3

I'm using the Reactour library in order to build a user tour in React (duh), which is easy enough for simple steps, but I can't figure out how to prevent the user from going further in the tour until they complete the action associated with the current step.

For example, in step 1, I want them to perform a search (enter text and submit) before continuing. Right now I'm using the goTo() function to automatically advance to the next step, but how do I prevent them from just using the navigation arrows without disabling navigation completely (in case they need to go back)?

export const steps: ReactourStep[] = [
  // This will automatically advance to the next step after a search... but the user could also just use the tour navigation instead...
  {
    selector: '.search-input',
    content: ({ goTo }: { goTo: (step: number) => void }) => {
      const searchBar = document.getElementById('search-bar') as HTMLInputElement;
      const searchButton = document.querySelector('.search-button') as HTMLButtonElement;

      // Timeout in order to allow for results to render
      searchButton.addEventListener('click', () => setTimeout(() => {
        if (searchBar.value !== '' && document.querySelector('.no-results') === null) {
          goTo(1);
        }
      }, 1000));

      return (
        <div>
          You can search using keywords and boolean expressions.
        </div>
      );
    }
  },
  {
     // Step 2 here
  }
]

I've tried using a conditional disabled boolean with a custom button too, but unlike React it doesn't re-render immediately -- only when the user revisits that step -- which defeats the whole purpose.

If it helps at all, the library GitHub has issues similar to mine but with no responses (here and here).

yev
  • 65
  • 1
  • 6

3 Answers3

1

I solved this by using a method to build the steps for the <Tour/> component, and passing in a state setter which then controls whether or not the navigation is shown/keyboard interaction is enabled:

function createSteps (setLockTour) {
  return [
    // Step which requires a specific action...
    {
      content: () => {
        return ( /* Your content */ )
      },
      action: node => {
        setLockTour(true)

        // Or whatever event you're waiting for
        node.onclick = () => {
          setLockTour(false)
          // ...
        }
      }
    }
  ]
}

Then for your tour component:

const [lockTour, setLockTour] = useState(false)
//...
<Tour
  steps={createSteps(setLockTour)}
  disableKeyboardNavigation={lockTour}
  disableDotsNavigation={lockTour}
  showButtons={!lockTour}
/>
Tom Walters
  • 15,366
  • 7
  • 57
  • 74
0

this is setps

export const steps ==(setCurrentStep: Dispatch<React.SetStateAction<number>>,setDisabledActions:Dispatch<React.SetStateAction<boolean>>)=> [
  {
    selector: '.third-step-WorkspaceWalkthroughSettings',
    content: 'Click on the settings icon of the whole Edit area.',
    disableActions:true,
    action: node => {
      node?.addEventListener("click", function(e) {
        setCurrentStep(1);
        setDisabledActions(false);
    }, false);
    }
  },
  {
    selector: '.dashboard-workspace',
    content: 'In this walkthrough guide ',
  },
]

and the tour caller

const {setIsOpen,setSteps,setCurrentStep,setDisabledActions  }: TourProps = useTour();

 <div onClick={()=>{
              setSteps(WorkspaceWalkthroughSettings(setCurrentStep,setDisabledActions));
              setIsOpen(true);
              setCurrentStep(0)
            }} >start tour</div>
Maxim
  • 81
  • 9
0

In the v2 of Reactour called @reactour/tour there is a step prop disableActions to control when is possible to interact.

Then you can control where you want through setDisabledActions method of useTour hook.

Here is an example

Lionel T
  • 1,559
  • 1
  • 13
  • 30