woocommerce/plugins/woocommerce-admin/client/wp-admin-scripts/product-tour/index.tsx

340 lines
8.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* External dependencies
*/
import { render, useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { TourKit, TourKitTypes } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
import qs from 'qs';
/**
* Internal dependencies
*/
import { useTmceIframeFocusStyle } from './use-tmce-iframe-focus-style';
import { useActiveEditorType } from './use-active-editor-type';
import {
bindEnableGuideModeClickEvent,
waitUntilElementTopNotChange,
} from './utils';
import {
ProductTourStepName,
useProductStepChange,
} from './use-product-step-change';
import { useTrackPublishButton } from './use-track-publish-button';
const getTourConfig = ( {
isExcerptEditorTmceActive,
isContentEditorTmceActive,
closeHandler,
onNextStepHandler,
}: {
isExcerptEditorTmceActive: boolean;
isContentEditorTmceActive: boolean;
closeHandler: TourKitTypes.CloseHandler;
onNextStepHandler: ( currentStepIndex: number ) => void;
} ): TourKitTypes.WooConfig => {
return {
placement: 'bottom-start',
options: {
effects: {
spotlight: {
interactivity: {
enabled: true,
rootElementSelector: '#wpwrap',
},
},
arrowIndicator: true,
autoScroll: {
behavior: 'auto',
block: 'center',
},
liveResize: {
mutation: true,
resize: true,
rootElementSelector: '#wpwrap',
},
},
popperModifiers: [
{
name: 'arrow',
options: {
padding: ( {
popper,
}: {
popper: { width: number };
} ) => {
return {
// Align the arrow to the left of the popper.
right: popper.width - 34,
};
},
},
},
],
callbacks: {
onNextStep: onNextStepHandler,
},
},
steps: [
{
referenceElements: {
desktop: '#title',
},
focusElement: {
desktop: '#title',
},
meta: {
name: 'product-name',
heading: __( 'Product name', 'woocommerce' ),
descriptions: {
desktop: __(
'Start typing your new product name here. This will be what your customers will see in your store.',
'woocommerce'
),
},
},
},
{
referenceElements: {
desktop: '#postdivrich',
},
focusElement: {
iframe: isContentEditorTmceActive
? '#content_ifr'
: undefined,
desktop: isContentEditorTmceActive
? '#tinymce'
: '#wp-content-editor-container > .wp-editor-area',
},
meta: {
name: 'product-description',
heading: __(
'Add your product description',
'woocommerce'
),
descriptions: {
desktop: __(
'Start typing your new product name here. Add your full product description here. Describe your product in detail.',
'woocommerce'
),
},
},
},
{
referenceElements: {
desktop: '#woocommerce-product-data',
},
focusElement: {
desktop: '#_regular_price',
},
meta: {
name: 'product-data',
heading: __( 'Add your product data', 'woocommerce' ),
descriptions: {
desktop: __(
'Use the tabs to switch between sections and insert product details. Start by adding your product price.',
'woocommerce'
),
},
},
},
{
referenceElements: {
desktop: '#postexcerpt',
},
focusElement: {
iframe: isExcerptEditorTmceActive
? '#excerpt_ifr'
: undefined,
desktop: isExcerptEditorTmceActive
? '#tinymce'
: '#wp-excerpt-editor-container > .wp-editor-area',
},
meta: {
name: 'product-short-description',
heading: __(
'Add your short product description',
'woocommerce'
),
descriptions: {
desktop: __(
'Type a quick summary for your product here. This will appear on the product page right under the product name.',
'woocommerce'
),
},
},
},
{
referenceElements: {
desktop: '#postimagediv',
},
focusElement: {
desktop: '#set-post-thumbnail',
},
meta: {
name: 'product-image',
heading: __( 'Add your product image', 'woocommerce' ),
descriptions: {
desktop: __(
'Upload an image to your product here. Ideally a JPEG or PNG about 600 px wide or bigger. This image will be shown in your stores catalog.',
'woocommerce'
),
},
},
},
{
referenceElements: {
desktop: '#tagsdiv-product_tag',
},
focusElement: {
desktop: '#new-tag-product_tag',
},
meta: {
name: 'product-tags',
heading: __( 'Add your product tags', 'woocommerce' ),
descriptions: {
desktop: __(
'Add your product tags here. Tags are a method of labeling your products to make them easier for customers to find. For example, if you sell clothing, and you have a lot of cat prints, you could make a tag for “cat.”',
'woocommerce'
),
},
},
},
{
referenceElements: {
desktop: '#product_catdiv',
},
meta: {
name: 'product-categories',
heading: __( 'Add your product categories', 'woocommerce' ),
descriptions: {
desktop: __(
'Add your product categories here. Assign categories to your products to make them easier to browse through and find in your store.',
'woocommerce'
),
},
},
},
{
referenceElements: {
desktop: '#submitdiv',
},
focusElement: {
desktop: '#submitdiv',
},
meta: {
name: 'publish',
heading: __( 'Publish your product 🎉', 'woocommerce' ),
descriptions: {
desktop: __(
'Good work! Now you can publish your product to your store by hitting the “Publish” button or keep editing it.',
'woocommerce'
),
},
primaryButton: {
text: __( 'Keep editing', 'woocommerce' ),
},
},
},
],
closeHandler,
};
};
const ProductTour = () => {
const [ showTour, setShowTour ] = useState< boolean >( false );
const { setIsLoaded, hasUpdatedInfo } = useProductStepChange();
const { isTmce: isContentEditorTmceActive } = useActiveEditorType( {
editorWrapSelector: '#wp-content-wrap',
} );
const { isTmce: isExcerptEditorTmceActive } = useActiveEditorType( {
editorWrapSelector: '#wp-excerpt-wrap',
} );
const { style: contentTmceIframeFocusStyle } = useTmceIframeFocusStyle( {
isActive: showTour && isContentEditorTmceActive,
iframeSelector: '#content_ifr',
} );
const { style: excerptTmceIframeFocusStyle } = useTmceIframeFocusStyle( {
isActive: showTour && isExcerptEditorTmceActive,
iframeSelector: '#excerpt_ifr',
} );
const tourConfig = getTourConfig( {
isContentEditorTmceActive,
isExcerptEditorTmceActive,
closeHandler: ( steps, stepIndex ) => {
setShowTour( false );
if ( steps.length - 1 === stepIndex ) {
recordEvent( 'walkthrough_product_completed' );
} else {
recordEvent( 'walkthrough_product_dismissed', {
step_name: steps[ stepIndex ].meta.name,
} );
}
},
onNextStepHandler: ( stepIndex ) => {
const stepName = tourConfig.steps[ stepIndex ].meta.name;
// This records all "next" steps and ignores the final "publish" step.
recordEvent( 'walkthrough_product_step_completed', {
step_name: stepName,
added_info: hasUpdatedInfo( stepName as ProductTourStepName )
? 'yes'
: 'no',
} );
},
} );
useEffect( () => {
bindEnableGuideModeClickEvent( ( e ) => {
e.preventDefault();
setShowTour( true );
recordEvent( 'walkthrough_product_enable_button_click' );
} );
const query = qs.parse( window.location.search.slice( 1 ) );
if ( query && query.tutorial === 'true' ) {
const intervalId = waitUntilElementTopNotChange(
tourConfig.steps[ 0 ].referenceElements?.desktop || '',
() => {
setShowTour( true );
recordEvent( 'walkthrough_product_view', {
spotlight: 'yes',
product_template: 'physical',
} );
setIsLoaded( true );
},
500
);
return () => clearInterval( intervalId );
}
// only run once
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [] );
useTrackPublishButton( showTour );
if ( ! showTour ) {
return null;
}
return (
<>
<style>
{ contentTmceIframeFocusStyle }
{ excerptTmceIframeFocusStyle }
{ `.wp-editor-area:focus {
border: 1.5px solid #007CBA;
}` }
</style>
<TourKit config={ tourConfig } />
</>
);
};
const root = document.createElement( 'div' );
root.setAttribute( 'id', 'product-tour-root' );
render( <ProductTour />, document.body.appendChild( root ) );