/** * External dependencies */ import { useEffect, useState } from '@wordpress/element'; import { TourKit, TourKitTypes } from '@woocommerce/components'; import { recordEvent } from '@woocommerce/tracks'; import { useDispatch } from '@wordpress/data'; import { OPTIONS_STORE_NAME } from '@woocommerce/data'; import qs from 'qs'; /** * Internal dependencies */ import { observePositionChange, waitUntilElementTopNotChange } from '../utils'; import { getTourConfig } from './get-config'; import { scrollPopperToVisibleAreaIfNeeded } from './utils'; import { getSteps } from './get-steps'; const WCAddonsTour = () => { const [ showTour, setShowTour ] = useState( false ); const { updateOptions } = useDispatch( OPTIONS_STORE_NAME ); const steps = getSteps(); const defaultAutoScrollBlock: ScrollLogicalPosition = 'center'; useEffect( () => { const query = qs.parse( window.location.search.slice( 1 ) ); if ( query?.tutorial === 'true' ) { const intervalId = waitUntilElementTopNotChange( steps[ 0 ].referenceElements?.desktop || '', () => { const stepName = steps[ 0 ]?.meta?.name; setShowTour( true ); recordEvent( 'in_app_marketplace_tour_started', { step: stepName, } ); }, 500 ); return () => clearInterval( intervalId ); } // only run once // eslint-disable-next-line react-hooks/exhaustive-deps }, [] ); useEffect( () => { if ( showTour ) { function showPopper() { const tourKitElement = document.querySelector( '.tour-kit-frame__container' ); if ( tourKitElement ) { scrollPopperToVisibleAreaIfNeeded( tourKitElement.getBoundingClientRect() ); } } // In a rare case, admin notices might load before observe is added below (moving `.wc-addons-wrap`). // In such a case, if Tour is shown before this effect is called, it might not be position correctly. // Updating popper's position here, ensures it's always visible. const timeoutId = setTimeout( showPopper, 500 ); const intervalId = observePositionChange( '.wc-addons-wrap', showPopper, 150 ); return () => { clearTimeout( timeoutId ); clearInterval( intervalId ); }; } }, [ showTour ] ); if ( ! showTour ) { return null; } const closeHandler: TourKitTypes.CloseHandler = ( tourSteps, currentStepIndex ) => { setShowTour( false ); // mark tour as completed updateOptions( { woocommerce_admin_dismissed_in_app_marketplace_tour: 'yes', } ); // remove `tutorial` from search query, so it's not shown on page refresh const url = new URL( window.location.href ); url.searchParams.delete( 'tutorial' ); window.history.replaceState( null, '', url ); if ( steps.length - 1 === currentStepIndex ) { recordEvent( 'in_app_marketplace_tour_completed' ); } else { const stepName = tourSteps[ currentStepIndex ]?.meta?.name; recordEvent( 'in_app_marketplace_tour_dismissed', { step: stepName, } ); } }; const onNextStepHandler = ( previousStepIndex: number ) => { const stepName = steps[ previousStepIndex + 1 ]?.meta?.name || ''; recordEvent( 'in_app_marketplace_tour_step_viewed', { step: stepName, } ); }; const tourConfig = getTourConfig( { closeHandler, onNextStepHandler, autoScrollBlock: defaultAutoScrollBlock, steps, } ); return ; }; export default WCAddonsTour;