/** * WordPress dependencies */ import { useEffect, useState } from '@safe-wordpress/element'; import { _x } from '@safe-wordpress/i18n'; /** * External dependencies */ import introJs from 'intro.js'; import { usePluginSetting } from '@nab/data'; import { getValue, isMultiArray, setValue } from '@nab/utils'; import type { Tour } from 'intro.js/src/packages/tour'; import type { TourStep } from 'intro.js/src/packages/tour/steps'; /** * Internal dependencies */ import './style.scss'; import type { TutorialStep } from '../types'; export function useWalkthroughEffect( screen: string, steps: ReadonlyArray< TutorialStep > ): false | ( () => void ) { const areAutoTutorialsEnabled = usePluginSetting( 'areAutoTutorialsEnabled' ); const shouldAutoRun = areAutoTutorialsEnabled && !! steps.length && shouldRunOnStartup( screen ); const tour = useTourInitEffect( screen, steps ); useEffect( () => { if ( ! shouldAutoRun ) { return; } void tour?.start(); }, [ tour, shouldAutoRun ] ); return !! steps.length && ( () => void tour?.start() ); } // ======= // HELPERS // ======= function useTourInitEffect( screen: string, steps: ReadonlyArray< TutorialStep > ): Tour | null { const [ tour, setTour ] = useState< Tour | null >( null ); useEffect( () => { const finalSteps = [ ...steps, { title: _x( 'Enjoy!', 'text', 'nelio-ab-testing' ), intro: _x( 'That’s all! If you have any further questions or you want to view this guide again, click on “Help”.', 'user', 'nelio-ab-testing' ), element: () => document.querySelector( '.nab-contextual-help__toggle' ), } as TutorialStep, ] .filter( ( s: TutorialStep ) => ! s?.active || s.active() ) .map( tutorialStepToIntroStep ); const newTour = introJs.tour().setOptions( { buttonClass: 'button button-secondary nab-walkthrough-button', disableInteraction: true, exitOnOverlayClick: false, overlayOpacity: 0.8, tooltipClass: 'nab-walkthrough-tooltip', steps: finalSteps, } ); newTour.onStart( () => { setValue( `is-guide-${ screen }-disabled`, true ); setTimeout( () => updateNavigationButtons( newTour, finalSteps.length ), 1 ); } ); newTour.onAfterChange( () => { setTimeout( () => updateNavigationButtons( newTour, finalSteps.length ), 1 ); } ); setTour( newTour ); }, [ screen, steps, setTour ] ); return tour; } function tutorialStepToIntroStep( step: TutorialStep ): Pick< TourStep, 'title' | 'intro' | 'element' > { const element = step.element?.(); return { title: step.title, intro: step.intro, element: element || null, }; } function shouldRunOnStartup( screen: string ): boolean { return ( ! getValue( 'are-guides-disabled', false ) && ! getValue( `is-guide-${ screen }-disabled`, false ) ); } function updateNavigationButtons( tour: Tour, totalSteps: number ): void { const { prev, next, skip } = getNavigationButtons( tour ); if ( ! prev || ! next || ! skip ) { return; } prev.textContent = _x( 'Prev', 'command', 'nelio-ab-testing' ); prev.style.display = isFirstStep( tour ) ? 'none' : 'block'; skip.style.display = isFirstStep( tour ) ? 'block' : 'none'; if ( isLastStep( tour, totalSteps ) ) { next.classList.add( 'button-primary' ); next.classList.remove( 'button-secondary' ); next.textContent = _x( 'Close', 'command', 'nelio-ab-testing' ); } else if ( isFirstStep( tour ) ) { next.classList.add( 'button-primary' ); next.textContent = _x( 'Start', 'command', 'nelio-ab-testing' ); } else { next.classList.remove( 'button-primary' ); next.classList.add( 'button-secondary' ); next.textContent = _x( 'Next', 'command', 'nelio-ab-testing' ); } } type NavigationButtons = { readonly prev?: HTMLElement; readonly next?: HTMLElement; readonly skip?: HTMLElement; }; function getNavigationButtons( tour: Tour ): NavigationButtons { const buttons: ReadonlyArray< HTMLElement > = Array.from( document.querySelectorAll( '.nab-walkthrough-button' ) ); if ( ! isMultiArray( buttons ) ) { return {}; } const prev = buttons[ 0 ]; const next = buttons[ 1 ]; const skip = getSkipButton( tour, prev ); return { prev, next, skip }; } function getSkipButton( tour: Tour, prev: HTMLElement ): HTMLElement { const existing = document.querySelector< HTMLElement >( '.nab-walkthrough-skip' ); if ( existing ) { return existing; } const skip = document.createElement( 'a' ); skip.setAttribute( 'role', 'button' ); skip.setAttribute( 'tabindex', '0' ); skip.className = 'button button-secondary nab-walkthrough-skip'; skip.textContent = _x( 'Skip', 'command', 'nelio-ab-testing' ); skip.style.float = 'left'; skip.addEventListener( 'click', () => { setValue( 'are-guides-disabled', true ); void tour.exit(); } ); prev.parentNode?.insertBefore( skip, prev ); return skip; } function isFirstStep( tour: Tour ): boolean { return ! tour.getCurrentStep(); } function isLastStep( tour: Tour, totalSteps: number ): boolean { return tour.getCurrentStep() === totalSteps - 1; }