[CYS] Update the intro page (#46916)

* Change the modal condition to check if the theme is a block theme

* Only switch to TT4 if the theme is not a block theme

* Remove unnecessary code

* Add new Intro cards when the theme is customized

* Redirect to the customizer if the active theme is a classic one

* Update the "Start designing" link depending on the type of theme

* Fix lint errors

* Fix more lint errors

* Fix tests

* Remove only

* Add tests for the customize button

* Update copy

* Fix lint errors

* Try to fix tests

* Fix tests

* Add changefile(s) from automation for the following project(s): woocommerce

* Remove commented out css code

* Fix tests

* Remove unused

* Add margin to the cards

* Change active theme has mods by customize task completed

* Add events to the new intro page

* Fix color palette tests

* Remove unused 'fetchActiveThemeHasMods' function

This fixes the "select( 'core' ).getCurrentThemeGlobalStylesRevisions() is deprecated since version 6.5.0" warning

* Revert allowing any block theme in the assembler

* Prevent other block themes to go to the assembler

* Fix linting errors, restore test

* Remove only from test

Co-authored-by: Luigi Teschio <gigitux@gmail.com>

* Fix lint error

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Luigi Teschio <gigitux@gmail.com>
This commit is contained in:
Alba Rincón 2024-06-05 16:54:29 +02:00 committed by GitHub
parent 307d893549
commit 88cbceb6fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 483 additions and 151 deletions

View File

@ -0,0 +1,31 @@
<svg width="292" height="167" viewBox="0 0 292 167" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M172.355 16.4116H6.04958C3.04735 16.4116 0.5 18.9598 0.5 21.9629V28.1513H177.814V21.9629C177.905 18.8688 175.448 16.4116 172.355 16.4116Z" fill="#BEA0F2"/>
<path d="M195.865 110.693V154.057H240.125V110.693H195.865ZM207.237 142.681V122.078H228.744V142.681H207.237Z" fill="#E5E5E5" fill-opacity="0.6"/>
<path d="M195.865 38.3438V98.9624H291.5V38.3438H195.865ZM207.237 87.5867V49.7194H280.128V87.5867H207.237Z" fill="#E5E5E5" fill-opacity="0.6"/>
<path d="M280.262 106.298C278.833 105.161 264.514 94.1675 264.514 94.1675C264.514 94.1675 262.676 112.141 262.521 113.961C262.367 115.772 264.122 116.573 265.542 115.372C267.516 113.715 271.528 110.439 271.528 110.439C271.528 110.439 276.659 109.766 279.215 109.475C281.062 109.256 281.69 107.427 280.262 106.298Z" fill="#3C2861"/>
<path d="M99.0199 80.7158C100.075 80.7158 100.93 79.8601 100.93 78.8047C100.93 77.7492 100.075 76.8936 99.0199 76.8936C97.9647 76.8936 97.1094 77.7492 97.1094 78.8047C97.1094 79.8601 97.9647 80.7158 99.0199 80.7158Z" fill="#3C2861"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M217.471 164.623V78.7139H218.381V164.623H217.471Z" fill="#3C2861"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M98.5645 164.623V81.1709H99.4745V164.623H98.5645Z" fill="#3C2861"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M99.0195 163.804H218.017V164.714H99.0195V163.804Z" fill="#3C2861"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M99.0195 78.3496H216.016V79.2597H99.0195V78.3496Z" fill="#3C2861"/>
<path d="M217.926 80.7158C218.981 80.7158 219.837 79.8601 219.837 78.8047C219.837 77.7492 218.981 76.8936 217.926 76.8936C216.871 76.8936 216.016 77.7492 216.016 78.8047C216.016 79.8601 216.871 80.7158 217.926 80.7158Z" fill="#3C2861"/>
<path d="M218.018 166.17C219.073 166.17 219.928 165.314 219.928 164.259C219.928 163.203 219.073 162.348 218.018 162.348C216.963 162.348 216.107 163.203 216.107 164.259C216.107 165.314 216.963 166.17 218.018 166.17Z" fill="#3C2861"/>
<path d="M99.0199 166.17C100.075 166.17 100.93 165.314 100.93 164.259C100.93 163.203 100.075 162.348 99.0199 162.348C97.9647 162.348 97.1094 163.203 97.1094 164.259C97.1094 165.314 97.9647 166.17 99.0199 166.17Z" fill="#3C2861"/>
<path d="M0.591797 27.6963L0.864727 121.523C0.864727 124.617 3.3211 127.074 6.4143 127.074H172.447C175.449 127.074 177.996 124.526 177.996 121.523L177.723 27.6963H0.591797Z" fill="#E5E5E5" fill-opacity="0.6"/>
<path d="M166.168 115.334H71.0971L70.8242 39.3447H166.168V115.334Z" fill="white"/>
<path d="M15.9662 24.1469C17.0213 24.1469 17.8767 23.2913 17.8767 22.2358C17.8767 21.1803 17.0213 20.3247 15.9662 20.3247C14.911 20.3247 14.0557 21.1803 14.0557 22.2358C14.0557 23.2913 14.911 24.1469 15.9662 24.1469Z" fill="#EAE2FF"/>
<path d="M8.41539 24.1469C9.47054 24.1469 10.3259 23.2913 10.3259 22.2358C10.3259 21.1803 9.47054 20.3247 8.41539 20.3247C7.36025 20.3247 6.50488 21.1803 6.50488 22.2358C6.50488 23.2913 7.36025 24.1469 8.41539 24.1469Z" fill="white"/>
<path d="M23.517 24.1469C24.5721 24.1469 25.4275 23.2913 25.4275 22.2358C25.4275 21.1803 24.5721 20.3247 23.517 20.3247C22.4618 20.3247 21.6064 21.1803 21.6064 22.2358C21.6064 23.2913 22.4618 24.1469 23.517 24.1469Z" fill="#3C2861"/>
<path d="M160.528 75.0696C164.201 65.7023 154.223 53.0242 138.24 46.7522C122.257 40.4802 106.322 42.9893 102.649 52.3566C98.9751 61.7238 108.954 74.4019 124.937 80.6739C140.919 86.9459 156.854 84.4368 160.528 75.0696Z" fill="#EAE2FF"/>
<path d="M129.172 90.1226C130.799 82.9208 121.529 74.6899 108.468 71.7383C95.4068 68.7867 83.5001 72.2322 81.8737 79.4341C80.2472 86.6359 89.5169 94.8668 102.578 97.8184C115.639 100.77 127.546 97.3245 129.172 90.1226Z" fill="#EAE2FF"/>
<path d="M57.7245 107.417C56.9057 106.598 55.723 106.052 54.4494 106.052H16.967C14.4196 106.052 12.3271 108.145 12.3271 110.693C12.3271 111.967 12.873 113.15 13.6918 113.969C14.5106 114.788 15.6933 115.334 16.967 115.334H54.4494C56.9967 115.334 59.0892 113.241 59.0892 110.693C59.0892 109.419 58.5433 108.236 57.7245 107.417Z" fill="white"/>
<path d="M4.28826 158.902C1.95831 156.571 0.5 153.386 0.5 149.764C0.5 142.696 6.27459 136.92 13.3399 136.92C20.4051 136.92 26.1797 142.696 26.1797 149.764C26.1797 156.831 20.4051 162.608 13.3399 162.608C9.89523 162.692 6.61821 161.224 4.28826 158.902Z" fill="#3C2861"/>
<path d="M46.1602 162.692C53.2514 162.692 59.0001 156.941 59.0001 149.848C59.0001 142.754 53.2514 137.004 46.1602 137.004C39.0689 137.004 33.3203 142.754 33.3203 149.848C33.3203 156.941 39.0689 162.692 46.1602 162.692Z" fill="#CFB9F6"/>
<path d="M12.3271 66.3735H59.0892V71.1968H12.3271V66.3735Z" fill="white"/>
<path d="M12.3271 76.3843H59.0892V81.2076H12.3271V76.3843Z" fill="white"/>
<path d="M12.3271 86.4858H35.7082V91.3091H12.3271V86.4858Z" fill="white"/>
<path d="M12.3271 39.3447H59.0892V48.7183H12.3271V39.3447Z" fill="white"/>
<path d="M247.008 27.2823L245.345 22.8098H234.009L232.346 27.2823H226L236.192 0.861328H243.26L253.451 27.2823H247H247.008ZM239.73 6.47832L235.567 17.8178H243.779L239.722 6.47832H239.73Z" fill="#3C2861"/>
<path d="M268.949 27.2821V24.782C267.391 26.6571 265.411 27.6961 263.025 27.6961C258.246 27.6961 254.497 24.0515 254.497 17.6066C254.497 11.1616 258.14 7.51709 263.025 7.51709C265.314 7.51709 267.391 8.45055 268.949 10.4311V7.93106H274.045V27.071H268.949V27.2821ZM268.949 21.1456V14.3841C268.113 13.1341 266.247 12.2006 264.583 12.2006C261.67 12.2006 259.698 14.4896 259.698 17.7121C259.698 20.9346 261.67 23.3291 264.583 23.3291C266.247 23.3291 268.121 22.3956 268.949 21.1456Z" fill="#3C2861"/>
<path d="M108.317 103.857C108.816 99.0021 102.131 94.3362 93.3844 93.4351C84.6378 92.534 77.1421 95.739 76.6423 100.594C76.1425 105.448 82.8278 110.114 91.5745 111.015C100.321 111.916 107.817 108.711 108.317 103.857Z" fill="#EAE2FF"/>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 MiB

View File

@ -3,8 +3,9 @@
*/ */
import { useMachine, useSelector } from '@xstate/react'; import { useMachine, useSelector } from '@xstate/react';
import { useEffect, useState } from '@wordpress/element'; import { useEffect, useState } from '@wordpress/element';
import { AnyInterpreter, Sender } from 'xstate';
import { getNewPath } from '@woocommerce/navigation'; import { getNewPath } from '@woocommerce/navigation';
import { useSelect } from '@wordpress/data';
import { AnyInterpreter, Sender } from 'xstate';
/** /**
* Internal dependencies * Internal dependencies
@ -47,6 +48,18 @@ export const DesignWithAiController = ( {
sendEventToParent?: Sender< customizeStoreStateMachineEvents >; sendEventToParent?: Sender< customizeStoreStateMachineEvents >;
parentContext?: customizeStoreStateMachineContext; parentContext?: customizeStoreStateMachineContext;
} ) => { } ) => {
interface Theme {
is_block_theme?: boolean;
}
const currentTheme = useSelect( ( select ) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return select( 'core' ).getCurrentTheme() as Theme;
}, [] );
const isBlockTheme = currentTheme?.is_block_theme;
// Assign aiOnline value from the parent context if it exists. Otherwise, ai is online by default. // Assign aiOnline value from the parent context if it exists. Otherwise, ai is online by default.
designWithAiStateMachineDefinition.context.aiOnline = designWithAiStateMachineDefinition.context.aiOnline =
parentContext?.flowType === FlowType.AIOnline; parentContext?.flowType === FlowType.AIOnline;
@ -57,6 +70,10 @@ export const DesignWithAiController = ( {
{ {
devTools: versionEnabled === 'V4', devTools: versionEnabled === 'V4',
parent: parentMachine, parent: parentMachine,
context: {
...designWithAiStateMachineDefinition.context,
isBlockTheme,
},
} }
); );

View File

@ -89,6 +89,7 @@ export const designWithAiStateMachineDefinition = createMachine(
hasErrors: false, hasErrors: false,
}, },
aiOnline: true, aiOnline: true,
isBlockTheme: false,
}, },
initial: 'navigate', initial: 'navigate',
states: { states: {

View File

@ -40,6 +40,7 @@ export type designWithAiStateMachineContext = {
// we can retrieve them in preBusinessInfoDescription and then assign them here // we can retrieve them in preBusinessInfoDescription and then assign them here
spawnSaveDescriptionToOptionRef?: ReturnType< typeof spawn >; spawnSaveDescriptionToOptionRef?: ReturnType< typeof spawn >;
aiOnline: boolean; aiOnline: boolean;
isBlockTheme: boolean;
}; };
export type designWithAiStateMachineEvents = export type designWithAiStateMachineEvents =
| { type: 'AI_WIZARD_CLOSED_BEFORE_COMPLETION'; payload: { step: string } } | { type: 'AI_WIZARD_CLOSED_BEFORE_COMPLETION'; payload: { step: string } }

View File

@ -4,6 +4,7 @@
import { useMachine, useSelector } from '@xstate/react'; import { useMachine, useSelector } from '@xstate/react';
import { AnyInterpreter, Sender } from 'xstate'; import { AnyInterpreter, Sender } from 'xstate';
import { useEffect, useState } from '@wordpress/element'; import { useEffect, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
/** /**
* Internal dependencies * Internal dependencies
@ -31,6 +32,18 @@ export const DesignWithNoAiController = ( {
sendEventToParent?: Sender< customizeStoreStateMachineEvents >; sendEventToParent?: Sender< customizeStoreStateMachineEvents >;
parentContext?: customizeStoreStateMachineContext; parentContext?: customizeStoreStateMachineContext;
} ) => { } ) => {
interface Theme {
is_block_theme?: boolean;
}
const currentTheme = useSelect( ( select ) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return select( 'core' ).getCurrentTheme() as Theme;
}, [] );
const isBlockTheme = currentTheme?.is_block_theme;
const { versionEnabled } = useXStateInspect(); const { versionEnabled } = useXStateInspect();
const [ , send, service ] = useMachine( const [ , send, service ] = useMachine(
designWithNoAiStateMachineDefinition, designWithNoAiStateMachineDefinition,
@ -43,6 +56,7 @@ export const DesignWithNoAiController = ( {
parentContext?.isFontLibraryAvailable ?? false, parentContext?.isFontLibraryAvailable ?? false,
isPTKPatternsAPIAvailable: isPTKPatternsAPIAvailable:
parentContext?.isPTKPatternsAPIAvailable ?? false, parentContext?.isPTKPatternsAPIAvailable ?? false,
isBlockTheme,
}, },
} }
); );

View File

@ -115,6 +115,7 @@ export const designWithNoAiStateMachineDefinition = createMachine(
}, },
isFontLibraryAvailable: false, isFontLibraryAvailable: false,
isPTKPatternsAPIAvailable: false, isPTKPatternsAPIAvailable: false,
isBlockTheme: false,
}, },
initial: 'navigate', initial: 'navigate',
states: { states: {

View File

@ -11,6 +11,7 @@ export type DesignWithoutAIStateMachineContext = {
flowType: FlowType.noAI; flowType: FlowType.noAI;
isFontLibraryAvailable: boolean; isFontLibraryAvailable: boolean;
isPTKPatternsAPIAvailable: boolean; isPTKPatternsAPIAvailable: boolean;
isBlockTheme: boolean;
}; };
export interface Theme { export interface Theme {

View File

@ -425,22 +425,22 @@ export const customizeStoreStateMachineDefinition = createMachine( {
}, },
}, },
assemblerHub: { assemblerHub: {
initial: 'fetchActiveThemeHasMods', initial: 'fetchCustomizeStoreCompleted',
states: { states: {
fetchActiveThemeHasMods: { fetchCustomizeStoreCompleted: {
invoke: { invoke: {
src: 'fetchActiveThemeHasMods', src: 'fetchCustomizeStoreCompleted',
onDone: { onDone: {
actions: 'assignActiveThemeHasMods', actions: 'assignCustomizeStoreCompleted',
target: 'checkActiveThemeHasMods', target: 'checkCustomizeStoreCompleted',
}, },
}, },
}, },
checkActiveThemeHasMods: { checkCustomizeStoreCompleted: {
always: [ always: [
{ {
// Redirect to the "intro step" if the active theme has no modifications. // Redirect to the "intro step" if the active theme has no modifications.
cond: 'activeThemeHasNoMods', cond: 'customizeTaskIsNotCompleted',
actions: [ actions: [
{ type: 'updateQueryStep', step: 'intro' }, { type: 'updateQueryStep', step: 'intro' },
], ],
@ -448,7 +448,7 @@ export const customizeStoreStateMachineDefinition = createMachine( {
}, },
{ {
// Otherwise, proceed to the next step. // Otherwise, proceed to the next step.
cond: 'activeThemeHasMods', cond: 'customizeTaskIsCompleted',
target: 'assemblerHub', target: 'assemblerHub',
}, },
], ],

View File

@ -2,10 +2,12 @@
* External dependencies * External dependencies
*/ */
import { useState } from '@wordpress/element'; import { useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { chevronLeft } from '@wordpress/icons'; import { chevronLeft } from '@wordpress/icons';
import interpolateComponents from '@automattic/interpolate-components'; import interpolateComponents from '@automattic/interpolate-components';
import { getNewPath } from '@woocommerce/navigation';
import { Sender } from 'xstate';
import { import {
Notice, Notice,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -36,6 +38,12 @@ import {
NoAIBanner, NoAIBanner,
ExistingNoAiThemeBanner, ExistingNoAiThemeBanner,
} from './intro-banners'; } from './intro-banners';
import welcomeTourImg from '../assets/images/design-your-own.svg';
import professionalThemeImg from '../assets/images/professional-theme.svg';
import { navigateOrParent } from '~/customize-store/utils';
import { RecommendThemesAPIResponse } from '~/customize-store/types';
import { customizeStoreStateMachineEvents } from '~/customize-store';
import { trackEvent } from '~/customize-store/tracking';
export type events = export type events =
| { type: 'DESIGN_WITH_AI' } | { type: 'DESIGN_WITH_AI' }
@ -71,6 +79,162 @@ const MODAL_COMPONENTS = {
type ModalStatus = keyof typeof MODAL_COMPONENTS; type ModalStatus = keyof typeof MODAL_COMPONENTS;
const ThemeCards = ( {
sendEvent,
themeData,
}: {
sendEvent: Sender< customizeStoreStateMachineEvents >;
themeData: RecommendThemesAPIResponse;
} ) => {
return (
<>
<p className="select-theme-text">
{ __(
'Or select a professionally designed theme to customize and make your own.',
'woocommerce'
) }
</p>
<div className="woocommerce-customize-store-theme-cards">
{ themeData.themes?.map( ( theme ) => (
<ThemeCard
key={ theme.slug }
slug={ theme.slug }
description={ theme.description }
thumbnail_url={ theme.thumbnail_url }
name={ theme.name }
color_palettes={ theme.color_palettes }
total_palettes={ theme.total_palettes }
link_url={ theme?.link_url }
is_active={ theme.is_active }
price={ theme.price }
onClick={ () => {
if ( theme.is_active ) {
sendEvent( {
type: 'SELECTED_ACTIVE_THEME',
payload: { theme: theme.slug },
} );
} else {
sendEvent( {
type: 'SELECTED_NEW_THEME',
payload: { theme: theme.slug },
} );
}
} }
/>
) ) }
</div>
<div className="woocommerce-customize-store-browse-themes">
<button
onClick={ () =>
sendEvent( {
type: 'SELECTED_BROWSE_ALL_THEMES',
} )
}
>
{ __( 'Browse all themes', 'woocommerce' ) }
</button>
</div>
</>
);
};
const CustomizedThemeBanners = ( {
isBlockTheme,
sendEvent,
}: {
isBlockTheme: boolean | undefined;
sendEvent: Sender< customizeStoreStateMachineEvents >;
} ) => {
return (
<>
<p className="select-theme-text">
{ __( 'Design or choose a new theme', 'woocommerce' ) }
</p>
<div className="woocommerce-customize-store-cards">
<div className="intro-card">
<img
src={ welcomeTourImg }
alt={ __( 'Design your own theme', 'woocommerce' ) }
/>
<div>
<h2 className="intro-card__title">
{ __( 'Design your own theme', 'woocommerce' ) }
</h2>
<button
className="intro-card__link"
onClick={ () => {
trackEvent(
'customize_your_store_intro_design_theme',
{
theme_type: isBlockTheme
? 'block'
: 'classic',
}
);
if ( isBlockTheme ) {
navigateOrParent(
window,
getNewPath(
{ customizing: true },
'/customize-store/assembler-hub',
{}
)
);
} else {
navigateOrParent(
window,
'customize.php?return=/wp-admin/themes.php'
);
}
} }
>
{ __( 'Use the store designer', 'woocommerce' ) }
</button>
</div>
</div>
<div className="intro-card">
<img
src={ professionalThemeImg }
alt={ __(
'Choose a professionally designed theme',
'woocommerce'
) }
/>
<div>
<h2 className="intro-card__title">
{ __(
'Choose a professionally designed theme',
'woocommerce'
) }
</h2>
<button
className="intro-card__link"
onClick={ () => {
trackEvent(
'customize_your_store_intro_browse_themes'
);
sendEvent( {
type: 'SELECTED_BROWSE_ALL_THEMES',
} );
} }
>
{ __( 'Browse themes', 'woocommerce' ) }
</button>
</div>
</div>
</div>
</>
);
};
export const Intro: CustomizeStoreComponent = ( { sendEvent, context } ) => { export const Intro: CustomizeStoreComponent = ( { sendEvent, context } ) => {
const { const {
intro: { intro: {
@ -97,6 +261,17 @@ export const Intro: CustomizeStoreComponent = ( { sendEvent, context } ) => {
let bannerStatus: BannerStatus = 'default'; let bannerStatus: BannerStatus = 'default';
const isDefaultTheme = activeTheme === 'twentytwentyfour'; const isDefaultTheme = activeTheme === 'twentytwentyfour';
interface Theme {
is_block_theme?: boolean;
}
const currentTheme = useSelect( ( select ) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return select( 'core' ).getCurrentTheme() as Theme;
}, [] );
const isBlockTheme = currentTheme?.is_block_theme;
switch ( true ) { switch ( true ) {
case isNetworkOffline: case isNetworkOffline:
@ -111,6 +286,7 @@ export const Intro: CustomizeStoreComponent = ( { sendEvent, context } ) => {
break; break;
case context.flowType === FlowType.noAI && case context.flowType === FlowType.noAI &&
customizeStoreTaskCompleted && customizeStoreTaskCompleted &&
isBlockTheme &&
! isDefaultTheme: ! isDefaultTheme:
bannerStatus = FlowType.noAI; bannerStatus = FlowType.noAI;
break; break;
@ -154,7 +330,7 @@ export const Intro: CustomizeStoreComponent = ( { sendEvent, context } ) => {
'woocommerce' 'woocommerce'
) )
: __( : __(
'Create a store that reflects your brand and business. Select one of our professionally designed themes to customize, or create your own using our store designer.', 'Design a store that reflects your brand and business. Customize your active theme, select a professionally designed theme, or create a new look using our store designer.',
'woocommerce' 'woocommerce'
); );
@ -230,54 +406,18 @@ export const Intro: CustomizeStoreComponent = ( { sendEvent, context } ) => {
sendEvent={ sendEvent } sendEvent={ sendEvent }
/> />
<p className="select-theme-text"> { customizeStoreTaskCompleted &&
{ __( ( isDefaultTheme || ! isBlockTheme ) ? (
'Or select a professionally designed theme to customize and make your own.', <CustomizedThemeBanners
'woocommerce' isBlockTheme={ isBlockTheme }
) } sendEvent={ sendEvent }
</p> />
) : (
<div className="woocommerce-customize-store-theme-cards"> <ThemeCards
{ themeData.themes?.map( ( theme ) => ( sendEvent={ sendEvent }
<ThemeCard themeData={ themeData }
key={ theme.slug } />
slug={ theme.slug } ) }
description={ theme.description }
thumbnail_url={ theme.thumbnail_url }
name={ theme.name }
color_palettes={ theme.color_palettes }
total_palettes={ theme.total_palettes }
link_url={ theme?.link_url }
is_active={ theme.is_active }
price={ theme.price }
onClick={ () => {
if ( theme.is_active ) {
sendEvent( {
type: 'SELECTED_ACTIVE_THEME',
payload: { theme: theme.slug },
} );
} else {
sendEvent( {
type: 'SELECTED_NEW_THEME',
payload: { theme: theme.slug },
} );
}
} }
/>
) ) }
</div>
<div className="woocommerce-customize-store-browse-themes">
<button
onClick={ () =>
sendEvent( {
type: 'SELECTED_BROWSE_ALL_THEMES',
} )
}
>
{ __( 'Browse all themes', 'woocommerce' ) }
</button>
</div>
</div> </div>
</div> </div>
</> </>

View File

@ -225,6 +225,7 @@ export const NoAIBanner = ( {
} ) => { } ) => {
const [ isModalOpen, setIsModalOpen ] = useState( false ); const [ isModalOpen, setIsModalOpen ] = useState( false );
interface Theme { interface Theme {
is_block_theme?: boolean;
stylesheet?: string; stylesheet?: string;
} }
@ -322,9 +323,21 @@ export const ExistingAiThemeBanner = ( {
export const ExistingNoAiThemeBanner = () => { export const ExistingNoAiThemeBanner = () => {
const siteUrl = getAdminSetting( 'siteUrl' ) + '?cys-hide-admin-bar=1'; const siteUrl = getAdminSetting( 'siteUrl' ) + '?cys-hide-admin-bar=1';
interface Theme {
is_block_theme?: boolean;
}
const currentTheme = useSelect( ( select ) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return select( 'core' ).getCurrentTheme() as Theme;
}, [] );
const isBlockTheme = currentTheme?.is_block_theme;
return ( return (
<BaseIntroBanner <BaseIntroBanner
bannerTitle={ __( 'Edit your custom theme', 'woocommerce' ) } bannerTitle={ __( 'Customize your theme', 'woocommerce' ) }
bannerText={ __( bannerText={ __(
'Continue to customize your store using the store designer. Change your color palette, fonts, page layouts, and more.', 'Continue to customize your store using the store designer. Change your color palette, fonts, page layouts, and more.',
'woocommerce' 'woocommerce'
@ -332,15 +345,24 @@ export const ExistingNoAiThemeBanner = () => {
bannerClass="existing-no-ai-theme-banner" bannerClass="existing-no-ai-theme-banner"
buttonIsLink={ false } buttonIsLink={ false }
bannerButtonOnClick={ () => { bannerButtonOnClick={ () => {
trackEvent( 'customize_your_store_intro_customize_click' ); trackEvent( 'customize_your_store_intro_customize_click', {
navigateOrParent( theme_type: isBlockTheme ? 'block' : 'classic',
window, } );
getNewPath( if ( isBlockTheme ) {
{ customizing: true }, navigateOrParent(
'/customize-store/assembler-hub', window,
{} getNewPath(
) { customizing: true },
); '/customize-store/assembler-hub',
{}
)
);
} else {
navigateOrParent(
window,
'customize.php?return=/wp-admin/themes.php'
);
}
} } } }
bannerButtonText={ __( 'Customize your theme', 'woocommerce' ) } bannerButtonText={ __( 'Customize your theme', 'woocommerce' ) }
showAIDisclaimer={ false } showAIDisclaimer={ false }

View File

@ -212,6 +212,47 @@
} }
} }
.woocommerce-customize-store-cards {
display: grid;
flex-wrap: wrap;
gap: 32px;
row-gap: 54px;
grid-template-columns: repeat(2, 1fr);
margin-bottom: 40px;
@media only screen and (min-width: 1600px) {
grid-template-columns: repeat(4, 1fr);
}
.intro-card {
border-radius: 4px;
border: 1px solid #e9e9e9;
text-align: center;
padding: 36px 51px;
margin-top: 0;
img {
width: 100%;
margin-bottom: 20px;
}
div {
text-align: left;
.intro-card__title {
font-size: 14px;
}
.intro-card__link {
background-color: #fff;
border: 0;
padding: 0;
color: #3858e9;
font-size: 13px;
}
}
}
}
.woocommerce-customize-store-theme-cards { .woocommerce-customize-store-theme-cards {
display: grid; display: grid;
flex-wrap: wrap; flex-wrap: wrap;

View File

@ -33,47 +33,6 @@ export const fetchThemeCards = async () => {
return themes; return themes;
}; };
export const fetchActiveThemeHasMods = async () => {
const currentTemplatePromise =
// @ts-expect-error No types for this exist yet.
resolveSelect( coreStore ).__experimentalGetTemplateForLink( '/' );
const styleRevsPromise =
// @ts-expect-error No types for this exist yet.
resolveSelect( coreStore ).getCurrentThemeGlobalStylesRevisions();
// @ts-expect-error No types for this exist yet.
const hasModifiedPagesPromise = resolveSelect( coreStore ).getEntityRecords(
'postType',
'page',
{
per_page: 100,
_fields: [ 'id', '_links.version-history' ],
orderby: 'menu_order',
order: 'asc',
}
);
const [ currentTemplate, styleRevs, rawPages ] = await Promise.all( [
currentTemplatePromise,
styleRevsPromise,
hasModifiedPagesPromise,
] );
const hasModifiedPages = rawPages?.some(
( page: { _links: { [ key: string ]: string[] } } ) => {
return page._links?.[ 'version-history' ]?.length > 1;
}
);
const activeThemeHasMods =
!! currentTemplate?.modified ||
styleRevs?.length > 0 ||
hasModifiedPages;
return { activeThemeHasMods };
};
export const fetchCustomizeStoreCompleted = async () => { export const fetchCustomizeStoreCompleted = async () => {
const task = await resolveSelect( ONBOARDING_STORE_NAME ).getTask( const task = await resolveSelect( ONBOARDING_STORE_NAME ).getTask(
'customize-store' 'customize-store'

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
[CYS] Remove the restriction to TT4 and allow users to proceed to the pattern assembler with any block themes. Update intro page design.

View File

@ -1,6 +1,6 @@
const { test: base, expect, request } = require( '@playwright/test' ); const { test: base, expect, request } = require( '@playwright/test' );
const { AssemblerPage } = require( './assembler/assembler.page' ); const { AssemblerPage } = require( './assembler/assembler.page' );
const { activateTheme, DEFAULT_THEME } = require( '../../utils/themes' ); const { activateTheme } = require( '../../utils/themes' );
const { setOption } = require( '../../utils/options' ); const { setOption } = require( '../../utils/options' );
const ASSEMBLER_HUB_URL = const ASSEMBLER_HUB_URL =
@ -27,7 +27,7 @@ test.describe( 'Store owner can view Assembler Hub for store customization', ()
'woocommerce_customize_store_onboarding_tour_hidden', 'woocommerce_customize_store_onboarding_tour_hidden',
'yes' 'yes'
); );
await activateTheme( 'twentytwentythree' ); await activateTheme( 'twentytwentyfour' );
} catch ( error ) { } catch ( error ) {
console.log( 'Store completed option not updated' ); console.log( 'Store completed option not updated' );
} }
@ -47,9 +47,6 @@ test.describe( 'Store owner can view Assembler Hub for store customization', ()
} ); } );
test.afterAll( async ( { baseURL } ) => { test.afterAll( async ( { baseURL } ) => {
// Reset theme back to default.
await activateTheme( DEFAULT_THEME );
// Reset tour to visible. // Reset tour to visible.
await setOption( await setOption(
request, request,
@ -68,16 +65,15 @@ test.describe( 'Store owner can view Assembler Hub for store customization', ()
await expect( locator ).not.toHaveText( 'Customize your store' ); await expect( locator ).not.toHaveText( 'Customize your store' );
} ); } );
test( 'Can view the Assembler Hub page when the theme is already customized', async ( { test( 'Can access the Assembler Hub page when the theme is already customized', async ( {
page, page,
assemblerPageObject, assemblerPageObject,
} ) => { } ) => {
await page.goto( CUSTOMIZE_STORE_URL ); await page.goto( CUSTOMIZE_STORE_URL );
await page.click( 'text=Start designing' ); await page.click( 'text=Start designing' );
await page
.getByRole( 'button', { name: 'Design a new theme' } )
.click();
await assemblerPageObject.waitForLoadingScreenFinish(); await assemblerPageObject.waitForLoadingScreenFinish();
await page.goto( ASSEMBLER_HUB_URL );
const assembler = await assemblerPageObject.getAssembler(); const assembler = await assemblerPageObject.getAssembler();
await expect( await expect(
assembler.locator( "text=Let's get creative" ) assembler.locator( "text=Let's get creative" )
@ -86,11 +82,16 @@ test.describe( 'Store owner can view Assembler Hub for store customization', ()
test( 'Visiting change header should show a list of block patterns to choose from', async ( { test( 'Visiting change header should show a list of block patterns to choose from', async ( {
page, page,
assemblerPageObject,
} ) => { } ) => {
await page.goto( ASSEMBLER_HUB_URL ); await page.goto( CUSTOMIZE_STORE_URL );
await page.click( 'text=Choose your header' ); await page.click( 'text=Start designing' );
await assemblerPageObject.waitForLoadingScreenFinish();
const locator = page.locator( const assembler = await assemblerPageObject.getAssembler();
await assembler.locator( 'text=Choose your header' ).click();
const locator = assembler.locator(
'.block-editor-block-patterns-list__list-item' '.block-editor-block-patterns-list__list-item'
); );

View File

@ -1,10 +1,18 @@
const { test, expect, request } = require( '@playwright/test' ); const { test: base, expect, request } = require( '@playwright/test' );
const { activateTheme, DEFAULT_THEME } = require( '../../utils/themes' ); const { activateTheme, DEFAULT_THEME } = require( '../../utils/themes' );
const { setOption } = require( '../../utils/options' ); const { setOption } = require( '../../utils/options' );
const { AssemblerPage } = require( './assembler/assembler.page' );
const CUSTOMIZE_STORE_URL = const CUSTOMIZE_STORE_URL =
'/wp-admin/admin.php?page=wc-admin&path=%2Fcustomize-store'; '/wp-admin/admin.php?page=wc-admin&path=%2Fcustomize-store';
const test = base.extend( {
assemblerPageObject: async ( { page }, use ) => {
const pageObject = new AssemblerPage( { page } );
await use( pageObject );
},
} );
test.describe( 'Store owner can view the Intro page', () => { test.describe( 'Store owner can view the Intro page', () => {
test.use( { storageState: process.env.ADMINSTATE } ); test.use( { storageState: process.env.ADMINSTATE } );
@ -92,43 +100,39 @@ test.describe( 'Store owner can view the Intro page', () => {
await expect( await expect(
page.locator( '.existing-no-ai-theme-banner' ) page.locator( '.existing-no-ai-theme-banner' )
).toBeVisible(); ).toBeVisible();
await expect( await expect( page.locator( 'h1' ) ).toHaveText(
page.locator( 'text=Edit your custom theme' ) 'Customize your theme'
).toBeVisible(); );
await expect( await expect(
page.getByRole( 'button', { name: 'Customize your theme' } ) page.getByRole( 'button', { name: 'Customize your theme' } )
).toBeVisible(); ).toBeVisible();
} ); } );
test( 'it shows the "no AI" banner when the task is completed and the theme is not the default', async ( { test( 'Clicking on "Customize your theme" with a block theme should go to the assembler', async ( {
page, page,
baseURL, assemblerPageObject,
} ) => { } ) => {
try { await page.goto( CUSTOMIZE_STORE_URL );
await setOption( await page.click( 'text=Start designing' );
request, await assemblerPageObject.waitForLoadingScreenFinish();
baseURL,
'woocommerce_admin_customize_store_completed',
'yes'
);
} catch ( error ) {
console.log( 'Store completed option not updated', error );
}
await activateTheme( 'twentytwentythree' );
await page.goto( CUSTOMIZE_STORE_URL ); await page.goto( CUSTOMIZE_STORE_URL );
await page
.getByRole( 'button', { name: 'Customize your theme' } )
.click();
await expect( page.locator( '.no-ai-banner' ) ).toBeVisible(); const assembler = await assemblerPageObject.getAssembler();
await expect( page.locator( 'text=Design your own' ) ).toBeVisible();
await expect( await expect(
page.getByRole( 'button', { name: 'Start designing' } ) assembler.locator( "text=Let's get creative" )
).toBeVisible(); ).toBeVisible();
} ); } );
test( 'it shows the "no AI" banner, when the task is completed and the theme is not the default', async ( { test( 'clicking on "Customize your theme" with a classic theme should go to the customizer', async ( {
page, page,
baseURL, baseURL,
} ) => { } ) => {
await activateTheme( 'twentytwenty' );
try { try {
await setOption( await setOption(
request, request,
@ -137,16 +141,15 @@ test.describe( 'Store owner can view the Intro page', () => {
'yes' 'yes'
); );
} catch ( error ) { } catch ( error ) {
console.log( 'Store completed option not updated', error ); console.log( 'Store completed option not updated' );
} }
await activateTheme( 'twentytwentythree' );
await page.goto( CUSTOMIZE_STORE_URL ); await page.goto( CUSTOMIZE_STORE_URL );
await expect( page.locator( '.no-ai-banner' ) ).toBeVisible(); await page
await expect( page.locator( 'text=Design your own' ) ).toBeVisible(); .getByRole( 'button', { name: 'Customize your theme' } )
await expect( .click();
page.getByRole( 'button', { name: 'Start designing' } )
).toBeVisible(); await page.waitForNavigation();
await expect( page.url() ).toContain( 'customize.php' );
} ); } );
} ); } );