Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Product Editor Onboarding: Show spotlight for first time visitors #38590

Merged
merged 13 commits into from Jun 6, 2023
5 changes: 5 additions & 0 deletions packages/js/components/changelog/add-block-tour
@@ -0,0 +1,5 @@
Significance: patch
Type: tweak
Comment: Allow passing react elements to heading in TourKit


2 changes: 1 addition & 1 deletion packages/js/components/src/tour-kit/types.ts
Expand Up @@ -12,7 +12,7 @@ export interface WooStep extends Step {
meta: {
/** Unique name for step, mainly used for tracking. */
name: string | null;
heading: string | null;
heading: string | React.ReactElement | null;
descriptions: {
desktop: string | React.ReactElement | null;
mobile?: string | React.ReactElement | null;
Expand Down
12 changes: 8 additions & 4 deletions plugins/woocommerce-admin/client/products/product-page.tsx
Expand Up @@ -17,6 +17,7 @@ import { useParams } from 'react-router-dom';
import { useProductEntityRecord } from './hooks/use-product-entity-record';
import './fills/product-block-editor-fills';
import './product-page.scss';
import BlockEditorTourWrapper from './tour/block-editor/block-editor-tour-wrapper';

declare const productBlockEditorSettings: ProductEditorSettings;

Expand All @@ -36,9 +37,12 @@ export default function ProductPage() {
}

return (
<Editor
product={ product }
settings={ productBlockEditorSettings || {} }
/>
<>
<Editor
product={ product }
settings={ productBlockEditorSettings || {} }
/>
<BlockEditorTourWrapper />
</>
);
}
@@ -0,0 +1,113 @@
/**
* External dependencies
*/

import { Guide } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import './style.scss';

interface Props {
onCloseGuide: () => void;
}

const BlockEditorGuide = ( { onCloseGuide }: Props ) => {
return (
<Guide
className="woocommerce-block-editor-guide"
finishButtonText={ __( 'Close', 'woocommerce' ) }
onFinish={ onCloseGuide }
pages={ [
{
content: (
<>
<h1 className="woocommerce-block-editor-guide__heading">
{ __(
'Refreshed, streamlined interface',
'woocommerce'
) }
</h1>
<p className="woocommerce-block-editor-guide__text">
{ __(
'Experience a simpler, more focused interface with a modern design that enhances usability.',
'woocommerce'
) }
</p>
</>
),
image: (
<div className="woocommerce-block-editor-guide__background1"></div>
),
},
{
content: (
<>
<h1 className="woocommerce-block-editor-guide__heading">
{ __(
'Content-rich product descriptions',
'woocommerce'
) }
</h1>
<p className="woocommerce-block-editor-guide__text">
{ __(
'Create compelling product pages with blocks, media, images, videos, and any content you desire to engage customers.',
'woocommerce'
) }
</p>
</>
),
image: (
<div className="woocommerce-block-editor-guide__background2"></div>
),
},
{
content: (
<>
<h1 className="woocommerce-block-editor-guide__heading">
{ __(
'Improved speed & performance',
'woocommerce'
) }
</h1>
<p className="woocommerce-block-editor-guide__text">
{ __(
'Enjoy a seamless experience without page reloads. Our modern technology ensures reliability and lightning-fast performance.',
'woocommerce'
) }
</p>
</>
),
image: (
<div className="woocommerce-block-editor-guide__background3"></div>
),
},
{
content: (
<>
<h1 className="woocommerce-block-editor-guide__heading">
{ __(
'More features are on the way',
'woocommerce'
) }
</h1>
<p className="woocommerce-block-editor-guide__text">
{ __(
'While we currently support physical products, exciting updates are coming to accommodate more types, like digital products, variations, and more. Stay tuned!',
'woocommerce'
) }
</p>
</>
),
image: (
<div className="woocommerce-block-editor-guide__background4"></div>
),
},
] }
/>
);
};

export default BlockEditorGuide;
@@ -0,0 +1,12 @@
/**
* Internal dependencies
*/
import BlockEditorTour from './block-editor-tour';
import { useBlockEditorTourOptions } from './use-block-editor-tour-options';

const BlockEditorTourWrapper = () => {
const blockEditorTourProps = useBlockEditorTourOptions();
return <BlockEditorTour { ...blockEditorTourProps } />;
};

export default BlockEditorTourWrapper;
@@ -0,0 +1,127 @@
/**
* External dependencies
*/
import { Pill, TourKit } from '@woocommerce/components';
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
import { useEffect, useState } from '@wordpress/element';

/**
* Internal dependencies
*/

import './style.scss';
import BlockEditorGuide from './block-editor-guide';

interface Props {
shouldTourBeShown: boolean;
dismissModal: () => void;
}

const BlockEditorTour = ( { shouldTourBeShown, dismissModal }: Props ) => {
useEffect( () => {
if ( shouldTourBeShown ) {
recordEvent( 'block_product_editor_spotlight_view' );
}
}, [ shouldTourBeShown ] );

const [ isGuideOpen, setIsGuideOpen ] = useState( false );

const openGuide = () => {
setIsGuideOpen( true );
};

const closeGuide = () => {
recordEvent( 'block_product_editor_spotlight_completed' );
setIsGuideOpen( false );
};

if ( isGuideOpen ) {
return <BlockEditorGuide onCloseGuide={ closeGuide } />;
} else if ( shouldTourBeShown ) {
return (
<TourKit
config={ {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the design the tourkit also includes a purple box at the top, is it possible to add this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the background color in the TourKit, we would have to change the component to allow customizing the CardHeader, which is the part where the X button is, and where we would change the background color and increase its size.

Do you think I should implement this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think I should implement this?

Yeah, but you can do this as part of a follow up.

steps: [
{
meta: {
name: 'woocommerce-block-editor-tour',
primaryButton: {
text: __(
'View highlights',
'woocommerce'
),
},
descriptions: {
desktop: __(
"We designed a brand new product editing experience to let you focus on what's important.",
'woocommerce'
),
},
heading: (
<>
<span>
{ __(
'Meet a streamlined product form',
'woocommerce'
) }
</span>{ ' ' }
<Pill className="woocommerce-block-editor-guide__pill">
{ __( 'Beta', 'woocommerce' ) }
</Pill>
</>
),
},
referenceElements: {
desktop: '#adminmenuback',
},
},
],
closeHandler: ( _steps, _currentStepIndex, source ) => {
dismissModal();
if ( source === 'done-btn' ) {
recordEvent(
'block_product_editor_spotlight_view_highlights'
);
openGuide();
} else {
recordEvent(
'block_product_editor_spotlight_dismissed'
);
}
},
options: {
effects: {
arrowIndicator: false,
overlay: false,
liveResize: {
rootElementSelector: '#adminmenuback',
resize: true,
},
},
portalParentElement:
document.getElementById( 'wpbody' ),
popperModifiers: [
{
name: 'bottom-left',
enabled: true,
phase: 'beforeWrite',
requires: [ 'computeStyles' ],
fn: ( { state } ) => {
state.styles.popper.top = 'auto';
state.styles.popper.left = 'auto';
state.styles.popper.bottom = '10px';
state.styles.popper.transform =
'translate3d(10px, 0px, 0px)';
},
},
],
},
} }
/>
);
}
return null;
};

export default BlockEditorTour;
@@ -0,0 +1,58 @@
$background-height: 220px;
$yellow: #f5e6ab;

.woocommerce-block-editor-guide {
&__background1 {
height: $background-height;
background-color: #f2edff;
}
&__background2 {
height: $background-height;
background-color: #dfd1fb;
}
&__background3 {
height: $background-height;
background-color: #cfb9f6;
}
&__background4 {
height: $background-height;
background-color: #bea0f2;
}
&__pill {
border: 1px solid $yellow;
background-color: $yellow;
}
&.components-modal__frame {
max-width: 320px;
}
&__heading,
&__text {
margin: $gap-small $gap-large;
}

&__heading {
font-size: 24px;
line-height: 30px;
}

.components-guide {
&__page-control {
margin-top: $gap-small;
}
&__footer {
width: unset;
margin: $gap-large $gap-large;
.components-guide__back-button {
left: 0;
padding: $gap-smaller $gap-small;
}
.components-guide__forward-button {
right: 0;
padding: $gap-smaller $gap-small;
}
.components-guide__finish-button {
right: 0;
}
}
}
}
@@ -0,0 +1,37 @@
/**
* External dependencies
*/
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
import { useSelect, useDispatch } from '@wordpress/data';

export const BLOCK_EDITOR_TOUR_SHOWN_OPTION =
'woocommerce_block_product_tour_shown';

export const useBlockEditorTourOptions = () => {
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
const { shouldTourBeShown } = useSelect( ( select ) => {
const { getOption, hasFinishedResolution } =
select( OPTIONS_STORE_NAME );

const wasTourShown =
getOption( BLOCK_EDITOR_TOUR_SHOWN_OPTION ) === 'yes' ||
! hasFinishedResolution( 'getOption', [
BLOCK_EDITOR_TOUR_SHOWN_OPTION,
] );

return {
shouldTourBeShown: ! wasTourShown,
};
} );

const dismissModal = () => {
updateOptions( {
[ BLOCK_EDITOR_TOUR_SHOWN_OPTION ]: 'yes',
} );
};

return {
dismissModal,
shouldTourBeShown,
};
};
4 changes: 4 additions & 0 deletions plugins/woocommerce/changelog/add-block-tour
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Show spotlight for first time visitors of block product editor