[CYS - Core] Update the homepage with default patterns when the assembler is loaded (#43457)
CYS - Core: Setup the site with a default homepage when the assembler is loaded
This commit is contained in:
parent
99e825df1f
commit
c686f605e6
|
@ -243,11 +243,13 @@ export const Layout = () => {
|
|||
</div>
|
||||
{ ! isEditorLoading &&
|
||||
shouldTourBeShown &&
|
||||
! showAiOfflineModal && (
|
||||
( FlowType.AIOnline === context.flowType ||
|
||||
FlowType.noAI === context.flowType ) && (
|
||||
<OnboardingTour
|
||||
skipTour={ skipTour }
|
||||
takeTour={ takeTour }
|
||||
onClose={ onClose }
|
||||
flowType={ context.flowType }
|
||||
{ ...onboardingTourProps }
|
||||
/>
|
||||
) }
|
||||
|
|
|
@ -10,6 +10,7 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
* Internal dependencies
|
||||
*/
|
||||
export * from './use-onboarding-tour';
|
||||
import { FlowType } from '~/customize-store/types';
|
||||
|
||||
type OnboardingTourProps = {
|
||||
onClose: () => void;
|
||||
|
@ -17,18 +18,53 @@ type OnboardingTourProps = {
|
|||
takeTour: () => void;
|
||||
showWelcomeTour: boolean;
|
||||
setIsResizeHandleVisible: ( isVisible: boolean ) => void;
|
||||
flowType: FlowType.AIOnline | FlowType.noAI;
|
||||
};
|
||||
|
||||
const getLabels = ( flowType: FlowType.AIOnline | FlowType.noAI ) => {
|
||||
switch ( flowType ) {
|
||||
case FlowType.AIOnline:
|
||||
return {
|
||||
heading: __(
|
||||
'Welcome to your AI-generated store!',
|
||||
'woocommerce'
|
||||
),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'This is where you can start customizing the look and feel of your store, including adding your logo, and changing colors and layouts. Take a quick tour to discover what’s possible.',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
};
|
||||
case FlowType.noAI:
|
||||
return {
|
||||
heading: __(
|
||||
"Discover what's possible with the store designer",
|
||||
'woocommerce'
|
||||
),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
"Start designing your store, including adding your logo, changing color schemes, and choosing layouts. Take a quick tour to discover what's possible.",
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const OnboardingTour = ( {
|
||||
onClose,
|
||||
skipTour,
|
||||
takeTour,
|
||||
flowType,
|
||||
showWelcomeTour,
|
||||
setIsResizeHandleVisible,
|
||||
}: OnboardingTourProps ) => {
|
||||
const [ placement, setPlacement ] =
|
||||
useState< TourKitTypes.WooConfig[ 'placement' ] >( 'left' );
|
||||
|
||||
const { heading, descriptions } = getLabels( flowType );
|
||||
|
||||
if ( showWelcomeTour ) {
|
||||
return (
|
||||
<TourKit
|
||||
|
@ -71,16 +107,8 @@ export const OnboardingTour = ( {
|
|||
primaryButton: {
|
||||
text: __( 'Take a tour', 'woocommerce' ),
|
||||
},
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
"This is where you can start customizing the look and feel of your store, including adding your logo, and changing colors and layouts. Take a quick tour to discover what's possible.",
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
heading: __(
|
||||
'Welcome to your AI-generated store!',
|
||||
'woocommerce'
|
||||
),
|
||||
descriptions,
|
||||
heading,
|
||||
skipButton: {
|
||||
isVisible: true,
|
||||
},
|
||||
|
|
|
@ -9,6 +9,7 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { OnboardingTour } from '../index';
|
||||
import { FlowType } from '~/customize-store/types';
|
||||
|
||||
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
|
||||
jest.mock( '../../', () => ( {
|
||||
|
@ -26,6 +27,7 @@ describe( 'OnboardingTour', () => {
|
|||
takeTour: jest.Mock;
|
||||
setShowWelcomeTour: jest.Mock;
|
||||
showWelcomeTour: boolean;
|
||||
flowType: FlowType.AIOnline | FlowType.noAI;
|
||||
setIsResizeHandleVisible: ( isVisible: boolean ) => void;
|
||||
};
|
||||
|
||||
|
@ -37,10 +39,11 @@ describe( 'OnboardingTour', () => {
|
|||
setShowWelcomeTour: jest.fn(),
|
||||
showWelcomeTour: true,
|
||||
setIsResizeHandleVisible: jest.fn(),
|
||||
flowType: FlowType.AIOnline,
|
||||
};
|
||||
} );
|
||||
|
||||
it( 'should render welcome tour', () => {
|
||||
it( 'should render welcome tour mentioning the AI when the flowType is AIOnline', () => {
|
||||
render( <OnboardingTour { ...props } /> );
|
||||
|
||||
expect(
|
||||
|
@ -48,6 +51,16 @@ describe( 'OnboardingTour', () => {
|
|||
).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should render welcome tour not mentioning the AI when the flowType is AIOnline', () => {
|
||||
render( <OnboardingTour { ...props } flowType={ FlowType.noAI } /> );
|
||||
|
||||
expect(
|
||||
screen.getByText(
|
||||
/Discover what's possible with the store designer/i
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should render step 1', () => {
|
||||
render( <OnboardingTour { ...props } showWelcomeTour={ false } /> );
|
||||
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/* eslint-disable @woocommerce/dependency-group */
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { resolveSelect, dispatch } from '@wordpress/data';
|
||||
// @ts-ignore No types for this exist yet.
|
||||
import { store as coreStore } from '@wordpress/core-data';
|
||||
// @ts-ignore No types for this exist yet.
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
patternsToNameMap,
|
||||
getTemplatePatterns,
|
||||
} from '../assembler-hub/hooks/use-home-templates';
|
||||
import { setLogoWidth } from '../utils';
|
||||
import { HOMEPAGE_TEMPLATES } from './homepageTemplates';
|
||||
|
||||
// Update the current theme template
|
||||
export const updateTemplate = async ( {
|
||||
homepageTemplateId,
|
||||
}: {
|
||||
homepageTemplateId: keyof typeof HOMEPAGE_TEMPLATES;
|
||||
} ) => {
|
||||
// @ts-ignore No types for this exist yet.
|
||||
const { invalidateResolutionForStoreSelector } = dispatch( coreStore );
|
||||
|
||||
// Ensure that the patterns are up to date because we populate images and content in previous step.
|
||||
invalidateResolutionForStoreSelector( 'getBlockPatterns' );
|
||||
invalidateResolutionForStoreSelector( '__experimentalGetTemplateForLink' );
|
||||
|
||||
const patterns = ( await resolveSelect(
|
||||
coreStore
|
||||
// @ts-ignore No types for this exist yet.
|
||||
).getBlockPatterns() ) as Pattern[];
|
||||
const patternsByName = patternsToNameMap( patterns );
|
||||
const homepageTemplate = getTemplatePatterns(
|
||||
HOMEPAGE_TEMPLATES[ homepageTemplateId ].blocks,
|
||||
patternsByName
|
||||
);
|
||||
|
||||
let content = [ ...homepageTemplate ]
|
||||
.filter( Boolean )
|
||||
.map( ( pattern ) => pattern.content )
|
||||
.join( '\n\n' );
|
||||
|
||||
// Replace the logo width with the default width.
|
||||
content = setLogoWidth( content );
|
||||
|
||||
const currentTemplate = await resolveSelect(
|
||||
coreStore
|
||||
// @ts-ignore No types for this exist yet.
|
||||
).__experimentalGetTemplateForLink( '/' );
|
||||
|
||||
// @ts-ignore No types for this exist yet.
|
||||
const { saveEntityRecord } = dispatch( coreStore );
|
||||
|
||||
await saveEntityRecord(
|
||||
'postType',
|
||||
currentTemplate.type,
|
||||
{
|
||||
id: currentTemplate.id,
|
||||
content,
|
||||
},
|
||||
{
|
||||
throwOnError: true,
|
||||
}
|
||||
);
|
||||
};
|
|
@ -19,12 +19,8 @@ import { mergeBaseAndUserConfigs } from '@wordpress/edit-site/build-module/compo
|
|||
import { designWithAiStateMachineContext } from './types';
|
||||
import { FONT_PAIRINGS } from '../assembler-hub/sidebar/global-styles/font-pairing-variations/constants';
|
||||
import { COLOR_PALETTES } from '../assembler-hub/sidebar/global-styles/color-palette-variations/constants';
|
||||
import {
|
||||
patternsToNameMap,
|
||||
getTemplatePatterns,
|
||||
} from '../assembler-hub/hooks/use-home-templates';
|
||||
import { HOMEPAGE_TEMPLATES } from '../data/homepageTemplates';
|
||||
import { setLogoWidth } from '../utils';
|
||||
import { updateTemplate } from '../data/actions';
|
||||
|
||||
const { escalate } = actions;
|
||||
|
||||
|
@ -396,58 +392,6 @@ const updateGlobalStyles = async ( {
|
|||
);
|
||||
};
|
||||
|
||||
// Update the current theme template
|
||||
const updateTemplate = async ( {
|
||||
homepageTemplateId,
|
||||
}: {
|
||||
homepageTemplateId: keyof typeof HOMEPAGE_TEMPLATES;
|
||||
} ) => {
|
||||
// @ts-ignore No types for this exist yet.
|
||||
const { invalidateResolutionForStoreSelector } = dispatch( coreStore );
|
||||
|
||||
// Ensure that the patterns are up to date because we populate images and content in previous step.
|
||||
invalidateResolutionForStoreSelector( 'getBlockPatterns' );
|
||||
invalidateResolutionForStoreSelector( '__experimentalGetTemplateForLink' );
|
||||
|
||||
const patterns = ( await resolveSelect(
|
||||
coreStore
|
||||
// @ts-ignore No types for this exist yet.
|
||||
).getBlockPatterns() ) as Pattern[];
|
||||
const patternsByName = patternsToNameMap( patterns );
|
||||
const homepageTemplate = getTemplatePatterns(
|
||||
HOMEPAGE_TEMPLATES[ homepageTemplateId ].blocks,
|
||||
patternsByName
|
||||
);
|
||||
|
||||
let content = [ ...homepageTemplate ]
|
||||
.filter( Boolean )
|
||||
.map( ( pattern ) => pattern.content )
|
||||
.join( '\n\n' );
|
||||
|
||||
// Replace the logo width with the default width.
|
||||
content = setLogoWidth( content );
|
||||
|
||||
const currentTemplate = await resolveSelect(
|
||||
coreStore
|
||||
// @ts-ignore No types for this exist yet.
|
||||
).__experimentalGetTemplateForLink( '/' );
|
||||
|
||||
// @ts-ignore No types for this exist yet.
|
||||
const { saveEntityRecord } = dispatch( coreStore );
|
||||
|
||||
await saveEntityRecord(
|
||||
'postType',
|
||||
currentTemplate.type,
|
||||
{
|
||||
id: currentTemplate.id,
|
||||
content,
|
||||
},
|
||||
{
|
||||
throwOnError: true,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const assembleSite = async (
|
||||
context: designWithAiStateMachineContext
|
||||
) => {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { getNewPath } from '@woocommerce/navigation';
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { attachIframeListeners, onIframeLoad } from '../utils';
|
||||
|
||||
const redirectToAssemblerHub = async () => {
|
||||
const assemblerUrl = getNewPath( {}, '/customize-store/assembler-hub', {} );
|
||||
const iframe = document.createElement( 'iframe' );
|
||||
iframe.classList.add( 'cys-fullscreen-iframe' );
|
||||
iframe.src = assemblerUrl;
|
||||
|
||||
const showIframe = () => {
|
||||
if ( iframe.style.opacity === '1' ) {
|
||||
// iframe is already visible
|
||||
return;
|
||||
}
|
||||
|
||||
const loader = document.getElementsByClassName(
|
||||
'woocommerce-onboarding-loader'
|
||||
);
|
||||
if ( loader[ 0 ] ) {
|
||||
( loader[ 0 ] as HTMLElement ).style.display = 'none';
|
||||
}
|
||||
|
||||
iframe.style.opacity = '1';
|
||||
};
|
||||
|
||||
iframe.onload = () => {
|
||||
// Hide loading UI
|
||||
attachIframeListeners( iframe );
|
||||
onIframeLoad( showIframe );
|
||||
|
||||
// Ceiling wait time set to 60 seconds
|
||||
setTimeout( showIframe, 60 * 1000 );
|
||||
window.history?.pushState( {}, '', assemblerUrl );
|
||||
};
|
||||
|
||||
document.body.appendChild( iframe );
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
redirectToAssemblerHub,
|
||||
};
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useMachine, useSelector } from '@xstate/react';
|
||||
import { AnyInterpreter, Sender } from 'xstate';
|
||||
import { useEffect, useState } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { customizeStoreStateMachineEvents } from '..';
|
||||
import {
|
||||
CustomizeStoreComponent,
|
||||
customizeStoreStateMachineContext,
|
||||
} from '../types';
|
||||
import { designWithNoAiStateMachineDefinition } from './state-machine';
|
||||
import { findComponentMeta } from '~/utils/xstate/find-component';
|
||||
import { AssembleHubLoader } from '../design-with-ai/pages';
|
||||
|
||||
export type DesignWithoutAiComponent = typeof AssembleHubLoader;
|
||||
export type DesignWithoutAiComponentMeta = {
|
||||
component: DesignWithoutAiComponent;
|
||||
};
|
||||
|
||||
export const DesignWithNoAiController = ( {
|
||||
parentMachine,
|
||||
}: {
|
||||
parentMachine?: AnyInterpreter;
|
||||
sendEventToParent?: Sender< customizeStoreStateMachineEvents >;
|
||||
parentContext?: customizeStoreStateMachineContext;
|
||||
} ) => {
|
||||
const [ , , service ] = useMachine( designWithNoAiStateMachineDefinition, {
|
||||
devTools: process.env.NODE_ENV === 'development',
|
||||
parent: parentMachine,
|
||||
} );
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- false positive due to function name match, this isn't from react std lib
|
||||
const currentNodeMeta = useSelector( service, ( currentState ) =>
|
||||
findComponentMeta< DesignWithoutAiComponentMeta >(
|
||||
currentState?.meta ?? undefined
|
||||
)
|
||||
);
|
||||
|
||||
const [ CurrentComponent, setCurrentComponent ] =
|
||||
useState< DesignWithoutAiComponent | null >( null );
|
||||
useEffect( () => {
|
||||
if ( currentNodeMeta?.component ) {
|
||||
setCurrentComponent( () => currentNodeMeta?.component );
|
||||
}
|
||||
}, [ CurrentComponent, currentNodeMeta?.component ] );
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={ `woocommerce-design-without-ai__container` }>
|
||||
{ CurrentComponent ? <CurrentComponent /> : <div /> }
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
//loader should send event 'THEME_SUGGESTED' when it's done
|
||||
export const DesignWithoutAi: CustomizeStoreComponent = ( {
|
||||
parentMachine,
|
||||
context,
|
||||
} ) => {
|
||||
return (
|
||||
<>
|
||||
<DesignWithNoAiController
|
||||
parentMachine={ parentMachine }
|
||||
parentContext={ context }
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Sender } from 'xstate';
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { updateTemplate } from '../data/actions';
|
||||
import { HOMEPAGE_TEMPLATES } from '../data/homepageTemplates';
|
||||
|
||||
const assembleSite = async () => {
|
||||
await updateTemplate( {
|
||||
homepageTemplateId: 'template1' as keyof typeof HOMEPAGE_TEMPLATES,
|
||||
} );
|
||||
};
|
||||
|
||||
const browserPopstateHandler =
|
||||
() => ( sendBack: Sender< { type: 'EXTERNAL_URL_UPDATE' } > ) => {
|
||||
const popstateHandler = () => {
|
||||
sendBack( { type: 'EXTERNAL_URL_UPDATE' } );
|
||||
};
|
||||
window.addEventListener( 'popstate', popstateHandler );
|
||||
return () => {
|
||||
window.removeEventListener( 'popstate', popstateHandler );
|
||||
};
|
||||
};
|
||||
|
||||
export const services = {
|
||||
assembleSite,
|
||||
browserPopstateHandler,
|
||||
};
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { EventObject, createMachine } from 'xstate';
|
||||
import { getQuery } from '@woocommerce/navigation';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
|
||||
import { AssembleHubLoader } from '../design-with-ai/pages';
|
||||
|
||||
import { FlowType } from '../types';
|
||||
import { DesignWithoutAIStateMachineContext } from './types';
|
||||
import { services } from './services';
|
||||
import { actions } from './actions';
|
||||
|
||||
export const hasStepInUrl = (
|
||||
_ctx: unknown,
|
||||
_evt: unknown,
|
||||
{ cond }: { cond: unknown }
|
||||
) => {
|
||||
const { path = '' } = getQuery() as { path: string };
|
||||
const pathFragments = path.split( '/' );
|
||||
return (
|
||||
pathFragments[ 2 ] === // [0] '', [1] 'customize-store', [2] design step slug
|
||||
( cond as { step: string | undefined } ).step
|
||||
);
|
||||
};
|
||||
|
||||
export const designWithNoAiStateMachineDefinition = createMachine(
|
||||
{
|
||||
id: 'designWithoutAI',
|
||||
predictableActionArguments: true,
|
||||
preserveActionOrder: true,
|
||||
schema: {
|
||||
context: {} as DesignWithoutAIStateMachineContext,
|
||||
events: {} as EventObject,
|
||||
},
|
||||
invoke: {
|
||||
src: 'browserPopstateHandler',
|
||||
},
|
||||
on: {
|
||||
EXTERNAL_URL_UPDATE: {
|
||||
target: 'navigate',
|
||||
},
|
||||
},
|
||||
context: {
|
||||
startLoadingTime: null,
|
||||
flowType: FlowType.noAI,
|
||||
apiCallLoader: {
|
||||
hasErrors: false,
|
||||
},
|
||||
},
|
||||
initial: 'navigate',
|
||||
states: {
|
||||
navigate: {
|
||||
always: [
|
||||
{
|
||||
cond: {
|
||||
type: 'hasStepInUrl',
|
||||
step: 'design',
|
||||
},
|
||||
target: 'preAssembleSite',
|
||||
},
|
||||
],
|
||||
},
|
||||
preAssembleSite: {
|
||||
type: 'parallel',
|
||||
states: {
|
||||
assembleSite: {
|
||||
initial: 'pending',
|
||||
states: {
|
||||
pending: {
|
||||
invoke: {
|
||||
src: 'assembleSite',
|
||||
onDone: {
|
||||
target: 'done',
|
||||
},
|
||||
onError: {
|
||||
actions: [ 'assignAPICallLoaderError' ],
|
||||
},
|
||||
},
|
||||
},
|
||||
done: {
|
||||
type: 'final',
|
||||
},
|
||||
},
|
||||
onDone: {
|
||||
target: '#designWithoutAI.showAssembleHub',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
showAssembleHub: {
|
||||
meta: {
|
||||
component: AssembleHubLoader,
|
||||
},
|
||||
entry: [ 'redirectToAssemblerHub' ],
|
||||
type: 'final',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
actions,
|
||||
services,
|
||||
guards: {
|
||||
hasStepInUrl,
|
||||
},
|
||||
}
|
||||
);
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { FlowType } from '../types';
|
||||
|
||||
export type DesignWithoutAIStateMachineContext = {
|
||||
startLoadingTime: number | null;
|
||||
apiCallLoader: {
|
||||
hasErrors: boolean;
|
||||
};
|
||||
flowType: FlowType.noAI;
|
||||
};
|
|
@ -28,6 +28,8 @@ import {
|
|||
actions as introActions,
|
||||
} from './intro';
|
||||
import { DesignWithAi, events as designWithAiEvents } from './design-with-ai';
|
||||
import { DesignWithoutAi } from './design-without-ai';
|
||||
|
||||
import { AssemblerHub, events as assemblerHubEvents } from './assembler-hub';
|
||||
import {
|
||||
events as transitionalEvents,
|
||||
|
@ -193,6 +195,13 @@ export const customizeStoreStateMachineDefinition = createMachine( {
|
|||
step: 'design-with-ai',
|
||||
},
|
||||
},
|
||||
{
|
||||
target: 'designWithoutAi',
|
||||
cond: {
|
||||
type: 'hasStepInUrl',
|
||||
step: 'design',
|
||||
},
|
||||
},
|
||||
{
|
||||
target: 'assemblerHub',
|
||||
cond: {
|
||||
|
@ -222,20 +231,17 @@ export const customizeStoreStateMachineDefinition = createMachine( {
|
|||
// eslint-disable-next-line xstate/prefer-always
|
||||
'': [
|
||||
{
|
||||
target: 'intro',
|
||||
target: 'fetchIntroData',
|
||||
cond: 'isNotWooExpress',
|
||||
actions: 'assignNoAI',
|
||||
},
|
||||
{
|
||||
target: 'preIntro',
|
||||
target: 'checkAiStatus',
|
||||
cond: 'isWooExpress',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
preIntro: {
|
||||
type: 'parallel',
|
||||
states: {
|
||||
checkAiStatus: {
|
||||
initial: 'pending',
|
||||
states: {
|
||||
|
@ -254,6 +260,7 @@ export const customizeStoreStateMachineDefinition = createMachine( {
|
|||
},
|
||||
success: { type: 'final' },
|
||||
},
|
||||
onDone: 'fetchIntroData',
|
||||
},
|
||||
fetchIntroData: {
|
||||
initial: 'pending',
|
||||
|
@ -262,8 +269,7 @@ export const customizeStoreStateMachineDefinition = createMachine( {
|
|||
invoke: {
|
||||
src: 'fetchIntroData',
|
||||
onError: {
|
||||
actions:
|
||||
'assignFetchIntroDataError',
|
||||
actions: 'assignFetchIntroDataError',
|
||||
target: 'success',
|
||||
},
|
||||
onDone: {
|
||||
|
@ -279,8 +285,6 @@ export const customizeStoreStateMachineDefinition = createMachine( {
|
|||
},
|
||||
success: { type: 'final' },
|
||||
},
|
||||
},
|
||||
},
|
||||
onDone: 'intro',
|
||||
},
|
||||
intro: {
|
||||
|
@ -297,6 +301,10 @@ export const customizeStoreStateMachineDefinition = createMachine( {
|
|||
actions: [ 'recordTracksDesignWithAIClicked' ],
|
||||
target: 'designWithAi',
|
||||
},
|
||||
DESIGN_WITHOUT_AI: {
|
||||
actions: [ 'recordTracksDesignWithAIClicked' ],
|
||||
target: 'designWithoutAi',
|
||||
},
|
||||
SELECTED_NEW_THEME: {
|
||||
actions: [ 'recordTracksThemeSelected' ],
|
||||
target: 'appearanceTask',
|
||||
|
@ -313,6 +321,22 @@ export const customizeStoreStateMachineDefinition = createMachine( {
|
|||
},
|
||||
},
|
||||
},
|
||||
designWithoutAi: {
|
||||
initial: 'preDesignWithoutAi',
|
||||
states: {
|
||||
preDesignWithoutAi: {
|
||||
always: {
|
||||
target: 'designWithoutAi',
|
||||
},
|
||||
},
|
||||
designWithoutAi: {
|
||||
entry: [ { type: 'updateQueryStep', step: 'design' } ],
|
||||
meta: {
|
||||
component: DesignWithoutAi,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
designWithAi: {
|
||||
initial: 'preDesignWithAi',
|
||||
states: {
|
||||
|
|
|
@ -30,7 +30,7 @@ import {
|
|||
DefaultBanner,
|
||||
ExistingAiThemeBanner,
|
||||
ExistingThemeBanner,
|
||||
CoreBanner,
|
||||
NoAIBanner,
|
||||
} from './intro-banners';
|
||||
|
||||
export type events =
|
||||
|
@ -39,7 +39,8 @@ export type events =
|
|||
| { type: 'CLICKED_ON_BREADCRUMB' }
|
||||
| { type: 'SELECTED_BROWSE_ALL_THEMES' }
|
||||
| { type: 'SELECTED_ACTIVE_THEME'; payload: { theme: string } }
|
||||
| { type: 'SELECTED_NEW_THEME'; payload: { theme: string } };
|
||||
| { type: 'SELECTED_NEW_THEME'; payload: { theme: string } }
|
||||
| { type: 'DESIGN_WITHOUT_AI' };
|
||||
|
||||
export * as actions from './actions';
|
||||
export * as services from './services';
|
||||
|
@ -52,7 +53,7 @@ const BANNER_COMPONENTS = {
|
|||
'jetpack-offline': JetpackOfflineBanner,
|
||||
'existing-ai-theme': ExistingAiThemeBanner,
|
||||
'existing-theme': ExistingThemeBanner,
|
||||
[ FlowType.noAI ]: CoreBanner,
|
||||
[ FlowType.noAI ]: NoAIBanner,
|
||||
default: DefaultBanner,
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ export const BaseIntroBanner = ( {
|
|||
bannerTitle,
|
||||
bannerText,
|
||||
bannerClass,
|
||||
showAIDisclaimer,
|
||||
buttonIsLink,
|
||||
bannerButtonOnClick,
|
||||
bannerButtonText,
|
||||
|
@ -30,6 +31,7 @@ export const BaseIntroBanner = ( {
|
|||
bannerTitle: string;
|
||||
bannerText: string;
|
||||
bannerClass: string;
|
||||
showAIDisclaimer: boolean;
|
||||
buttonIsLink?: boolean;
|
||||
bannerButtonOnClick?: () => void;
|
||||
bannerButtonText?: string;
|
||||
|
@ -58,6 +60,7 @@ export const BaseIntroBanner = ( {
|
|||
</Button>
|
||||
) }
|
||||
{ secondaryButton }
|
||||
{ showAIDisclaimer && (
|
||||
<p className="ai-disclaimer">
|
||||
{ interpolateComponents( {
|
||||
mixedString: __(
|
||||
|
@ -75,6 +78,7 @@ export const BaseIntroBanner = ( {
|
|||
},
|
||||
} ) }
|
||||
</p>
|
||||
) }
|
||||
</div>
|
||||
{ children }
|
||||
</div>
|
||||
|
@ -95,6 +99,7 @@ export const NetworkOfflineBanner = () => {
|
|||
) }
|
||||
bannerClass="offline-banner"
|
||||
bannerButtonOnClick={ () => {} }
|
||||
showAIDisclaimer={ true }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -122,6 +127,7 @@ export const JetpackOfflineBanner = ( {
|
|||
} );
|
||||
} }
|
||||
bannerButtonText={ __( 'Find out how', 'woocommerce' ) }
|
||||
showAIDisclaimer={ true }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -147,6 +153,7 @@ export const ExistingThemeBanner = ( {
|
|||
setOpenDesignChangeWarningModal( true );
|
||||
} }
|
||||
bannerButtonText={ __( 'Design with AI', 'woocommerce' ) }
|
||||
showAIDisclaimer={ true }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -174,6 +181,7 @@ export const DefaultBanner = ( {
|
|||
} );
|
||||
} }
|
||||
bannerButtonText={ __( 'Design with AI', 'woocommerce' ) }
|
||||
showAIDisclaimer={ true }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -199,11 +207,16 @@ export const ThemeHasModsBanner = ( {
|
|||
setOpenDesignChangeWarningModal( true );
|
||||
} }
|
||||
bannerButtonText={ __( 'Design with AI', 'woocommerce' ) }
|
||||
showAIDisclaimer={ true }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const CoreBanner = () => {
|
||||
export const NoAIBanner = ( {
|
||||
sendEvent,
|
||||
}: {
|
||||
sendEvent: React.ComponentProps< typeof Intro >[ 'sendEvent' ];
|
||||
} ) => {
|
||||
return (
|
||||
<BaseIntroBanner
|
||||
bannerTitle={ __( 'Design your own', 'woocommerce' ) }
|
||||
|
@ -211,8 +224,14 @@ export const CoreBanner = () => {
|
|||
'Quickly create a beautiful store using our built-in store designer. Choose your layout, select a style, and much more.',
|
||||
'woocommerce'
|
||||
) }
|
||||
bannerClass="core-banner"
|
||||
bannerButtonOnClick={ () => {} }
|
||||
bannerClass="no-ai-banner"
|
||||
bannerButtonText={ __( 'Start designing', 'woocommerce' ) }
|
||||
bannerButtonOnClick={ () => {
|
||||
sendEvent( {
|
||||
type: 'DESIGN_WITHOUT_AI',
|
||||
} );
|
||||
} }
|
||||
showAIDisclaimer={ false }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -260,6 +279,7 @@ export const ExistingAiThemeBanner = ( {
|
|||
} }
|
||||
bannerButtonText={ __( 'Customize', 'woocommerce' ) }
|
||||
secondaryButton={ secondaryButton }
|
||||
showAIDisclaimer={ true }
|
||||
>
|
||||
<div className={ 'woocommerce-block-preview-container' }>
|
||||
<div className="iframe-container">
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
[CYS - Core] Update the homepage with default patterns when the assembler is loaded.
|
Loading…
Reference in New Issue