[CYS on core] Update the WooCommerce Extensions Themes page to include references to the CYS (#45468)
* Introduce the new 'Design your own' button in the themes screen. * unify the SCSS margins * Add double quotes for woocommerce-marketplace__sub-header * Add the CYS banner to the marketplace. * Ensure each child in a list should have a unique 'key' prop * Update the NoAIBanner component to direct users to the CYS flow. * Add the customizeStoreDesignUrl const * Ditch navigateOrParent * Add the 'Browse the WordPress.org theme directory to discover more' link. * Ensure the warning Modal is displayed whenever the user clicks on the 'Design your own' button and their current active theme is not TT4 * Remove the unnecessary fragment * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint. --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
0f98ffee64
commit
4933b86cc7
|
@ -2,8 +2,9 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { addQueryArgs } from '@wordpress/url';
|
||||
import classNames from 'classnames';
|
||||
import { Button, Modal } from '@wordpress/components';
|
||||
import { Button } from '@wordpress/components';
|
||||
import { getNewPath } from '@woocommerce/navigation';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import interpolateComponents from '@automattic/interpolate-components';
|
||||
|
@ -16,8 +17,9 @@ import { useSelect } from '@wordpress/data';
|
|||
*/
|
||||
import { Intro } from '.';
|
||||
import { IntroSiteIframe } from './intro-site-iframe';
|
||||
import { getAdminSetting } from '~/utils/admin-settings';
|
||||
import { ADMIN_URL, getAdminSetting } from '~/utils/admin-settings';
|
||||
import { navigateOrParent } from '../utils';
|
||||
import { ThemeSwitchWarningModal } from '~/customize-store/intro/warning-modals';
|
||||
|
||||
export const BaseIntroBanner = ( {
|
||||
bannerTitle,
|
||||
|
@ -217,11 +219,7 @@ export const ThemeHasModsBanner = ( {
|
|||
);
|
||||
};
|
||||
|
||||
export const NoAIBanner = ( {
|
||||
sendEvent,
|
||||
}: {
|
||||
sendEvent: React.ComponentProps< typeof Intro >[ 'sendEvent' ];
|
||||
} ) => {
|
||||
export const NoAIBanner = () => {
|
||||
const [ isModalOpen, setIsModalOpen ] = useState( false );
|
||||
interface Theme {
|
||||
stylesheet?: string;
|
||||
|
@ -232,6 +230,10 @@ export const NoAIBanner = ( {
|
|||
}, [] );
|
||||
|
||||
const isDefaultTheme = currentTheme?.stylesheet === 'twentytwentyfour';
|
||||
const customizeStoreDesignUrl = addQueryArgs( `${ ADMIN_URL }admin.php`, {
|
||||
page: 'wc-admin',
|
||||
path: '/customize-store/design',
|
||||
} );
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -247,56 +249,16 @@ export const NoAIBanner = ( {
|
|||
if ( ! isDefaultTheme ) {
|
||||
setIsModalOpen( true );
|
||||
} else {
|
||||
sendEvent( {
|
||||
type: 'DESIGN_WITHOUT_AI',
|
||||
} );
|
||||
window.location.href = customizeStoreDesignUrl;
|
||||
}
|
||||
} }
|
||||
showAIDisclaimer={ false }
|
||||
/>
|
||||
{ isModalOpen && (
|
||||
<Modal
|
||||
className={
|
||||
'woocommerce-customize-store__theme-switch-warning-modal'
|
||||
}
|
||||
title={ __(
|
||||
'Are you sure you want to design a new theme?',
|
||||
'woocommerce'
|
||||
) }
|
||||
onRequestClose={ () => setIsModalOpen( false ) }
|
||||
shouldCloseOnClickOutside={ false }
|
||||
>
|
||||
<p>
|
||||
{ __(
|
||||
'Your active theme will be changed and you could lose any changes you’ve made to it.',
|
||||
'woocommerce'
|
||||
) }
|
||||
</p>
|
||||
<div className="woocommerce-customize-store__theme-switch-warning-modal-footer">
|
||||
<Button
|
||||
onClick={ () => {
|
||||
setIsModalOpen( false );
|
||||
} }
|
||||
variant="link"
|
||||
>
|
||||
{ __( 'Cancel', 'woocommerce' ) }
|
||||
</Button>
|
||||
<Button
|
||||
onClick={ () => {
|
||||
sendEvent( {
|
||||
type: 'DESIGN_WITHOUT_AI',
|
||||
} );
|
||||
setIsModalOpen( false );
|
||||
recordEvent(
|
||||
'customize_your_store_agree_to_theme_switch_click'
|
||||
);
|
||||
} }
|
||||
variant="primary"
|
||||
>
|
||||
{ __( 'Design a new theme', 'woocommerce' ) }
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<ThemeSwitchWarningModal
|
||||
setIsModalOpen={ setIsModalOpen }
|
||||
customizeStoreDesignUrl={ customizeStoreDesignUrl }
|
||||
/>
|
||||
) }
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -194,3 +194,54 @@ export const StartOverWarningModal = ( {
|
|||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export const ThemeSwitchWarningModal = ( {
|
||||
setIsModalOpen,
|
||||
customizeStoreDesignUrl,
|
||||
}: {
|
||||
setIsModalOpen: ( arg0: boolean ) => void;
|
||||
customizeStoreDesignUrl: string;
|
||||
} ) => {
|
||||
return (
|
||||
<Modal
|
||||
className={
|
||||
'woocommerce-customize-store__theme-switch-warning-modal'
|
||||
}
|
||||
title={ __(
|
||||
'Are you sure you want to design a new theme?',
|
||||
'woocommerce'
|
||||
) }
|
||||
onRequestClose={ () => setIsModalOpen( false ) }
|
||||
shouldCloseOnClickOutside={ false }
|
||||
>
|
||||
<p>
|
||||
{ __(
|
||||
'Your active theme will be changed and you could lose any changes you’ve made to it.',
|
||||
'woocommerce'
|
||||
) }
|
||||
</p>
|
||||
<div className="woocommerce-customize-store__theme-switch-warning-modal-footer">
|
||||
<Button
|
||||
onClick={ () => {
|
||||
setIsModalOpen( false );
|
||||
} }
|
||||
variant="link"
|
||||
>
|
||||
{ __( 'Cancel', 'woocommerce' ) }
|
||||
</Button>
|
||||
<Button
|
||||
onClick={ () => {
|
||||
window.location.href = customizeStoreDesignUrl;
|
||||
setIsModalOpen( false );
|
||||
recordEvent(
|
||||
'customize_your_store_agree_to_theme_switch_click'
|
||||
);
|
||||
} }
|
||||
variant="primary"
|
||||
>
|
||||
{ __( 'Design a new theme', 'woocommerce' ) }
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useQuery } from '@woocommerce/navigation';
|
|||
*/
|
||||
import './content.scss';
|
||||
import { Product, ProductType, SearchResultType } from '../product-list/types';
|
||||
import { getAdminSetting } from '../../../utils/admin-settings';
|
||||
import { getAdminSetting } from '~/utils/admin-settings';
|
||||
import Discover from '../discover/discover';
|
||||
import Products from '../products/products';
|
||||
import SearchResults from '../search-results/search-results';
|
||||
|
|
|
@ -12,6 +12,25 @@
|
|||
color: $white;
|
||||
height: 270px;
|
||||
}
|
||||
|
||||
.woocommerce-customize-store-banner {
|
||||
grid-column: 1 / -1;
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.woocommerce-customize-store-banner-content {
|
||||
margin-top: 63px;
|
||||
}
|
||||
|
||||
&__browse-wp-theme-directory {
|
||||
margin-top: 24px;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: $breakpoint-medium) {
|
||||
|
|
|
@ -1,16 +1,26 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
createInterpolateElement,
|
||||
Fragment,
|
||||
useEffect,
|
||||
useState,
|
||||
} from '@wordpress/element';
|
||||
import classnames from 'classnames';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './product-list-content.scss';
|
||||
import '~/customize-store/intro/intro.scss';
|
||||
import '~/customize-store/style.scss';
|
||||
import ProductCard from '../product-card/product-card';
|
||||
import { Product, ProductType } from '../product-list/types';
|
||||
import { appendURLParams } from '../../utils/functions';
|
||||
import { getAdminSetting } from '../../../utils/admin-settings';
|
||||
import { ADMIN_URL, getAdminSetting } from '~/utils/admin-settings';
|
||||
import { NoAIBanner } from '~/customize-store/intro/intro-banners';
|
||||
|
||||
export default function ProductListContent( props: {
|
||||
products: Product[];
|
||||
|
@ -28,54 +38,115 @@ export default function ProductListContent( props: {
|
|||
props.className
|
||||
);
|
||||
|
||||
const [ columns, setColumns ] = useState( 1 );
|
||||
|
||||
const updateColumns = () => {
|
||||
const screenWidth = window.innerWidth;
|
||||
if ( screenWidth >= 1920 ) {
|
||||
setColumns( 4 );
|
||||
} else if ( screenWidth >= 1024 ) {
|
||||
setColumns( 3 );
|
||||
} else if ( screenWidth >= 769 ) {
|
||||
setColumns( 2 );
|
||||
} else {
|
||||
setColumns( 1 );
|
||||
}
|
||||
};
|
||||
|
||||
useEffect( () => {
|
||||
updateColumns();
|
||||
// Update columns on screen resize to adjust for responsive layout
|
||||
window.addEventListener( 'resize', updateColumns );
|
||||
|
||||
return () => window.removeEventListener( 'resize', updateColumns );
|
||||
}, [] );
|
||||
|
||||
const bannerPosition = columns * 2 - 1;
|
||||
|
||||
return (
|
||||
<div className={ classes }>
|
||||
{ props.products.map( ( product, index ) => (
|
||||
<ProductCard
|
||||
key={ product.id }
|
||||
type={ props.type }
|
||||
product={ {
|
||||
id: product.id,
|
||||
slug: product.slug,
|
||||
title: product.title,
|
||||
image: product.image,
|
||||
type: product.type,
|
||||
icon: product.icon,
|
||||
vendorName: product.vendorName,
|
||||
vendorUrl: product.vendorUrl
|
||||
? appendURLParams( product.vendorUrl, [
|
||||
[ 'utm_source', 'extensionsscreen' ],
|
||||
[ 'utm_medium', 'product' ],
|
||||
[ 'utm_campaign', 'wcaddons' ],
|
||||
[ 'utm_content', 'devpartner' ],
|
||||
] )
|
||||
: '',
|
||||
price: product.price,
|
||||
url: appendURLParams(
|
||||
product.url,
|
||||
Object.entries( {
|
||||
...wccomHelperSettings.inAppPurchaseURLParams,
|
||||
...( props.productGroup !== undefined
|
||||
? { utm_group: props.productGroup }
|
||||
: {} ),
|
||||
} )
|
||||
<>
|
||||
<div className={ classes }>
|
||||
{ props.products.map( ( product, index ) => (
|
||||
<Fragment key={ product.id }>
|
||||
<ProductCard
|
||||
key={ product.id }
|
||||
type={ props.type }
|
||||
product={ {
|
||||
id: product.id,
|
||||
slug: product.slug,
|
||||
title: product.title,
|
||||
image: product.image,
|
||||
type: product.type,
|
||||
icon: product.icon,
|
||||
vendorName: product.vendorName,
|
||||
vendorUrl: product.vendorUrl
|
||||
? appendURLParams( product.vendorUrl, [
|
||||
[
|
||||
'utm_source',
|
||||
'extensionsscreen',
|
||||
],
|
||||
[ 'utm_medium', 'product' ],
|
||||
[ 'utm_campaign', 'wcaddons' ],
|
||||
[ 'utm_content', 'devpartner' ],
|
||||
] )
|
||||
: '',
|
||||
price: product.price,
|
||||
url: appendURLParams(
|
||||
product.url,
|
||||
Object.entries( {
|
||||
...wccomHelperSettings.inAppPurchaseURLParams,
|
||||
...( props.productGroup !== undefined
|
||||
? { utm_group: props.productGroup }
|
||||
: {} ),
|
||||
} )
|
||||
),
|
||||
averageRating: product.averageRating,
|
||||
reviewsCount: product.reviewsCount,
|
||||
description: product.description,
|
||||
isInstallable: product.isInstallable,
|
||||
} }
|
||||
tracksData={ {
|
||||
position: index + 1,
|
||||
...( product.label && {
|
||||
label: product.label,
|
||||
} ),
|
||||
...( props.group && { group: props.group } ),
|
||||
...( props.searchTerm && {
|
||||
searchTerm: props.searchTerm,
|
||||
} ),
|
||||
...( props.category && {
|
||||
category: props.category,
|
||||
} ),
|
||||
} }
|
||||
/>
|
||||
{ index === bannerPosition && <NoAIBanner /> }
|
||||
</Fragment>
|
||||
) ) }
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
'woocommerce-marketplace__browse-wp-theme-directory'
|
||||
}
|
||||
>
|
||||
<b>{ __( 'Didn’t find a theme you like?', 'woocommerce' ) }</b>
|
||||
{ createInterpolateElement(
|
||||
__(
|
||||
' Browse the <a>WordPress.org theme directory</a> to discover more.',
|
||||
'woocommerce'
|
||||
),
|
||||
{
|
||||
a: (
|
||||
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
||||
<a
|
||||
href={
|
||||
ADMIN_URL +
|
||||
'theme-install.php?search=e-commerce'
|
||||
}
|
||||
/>
|
||||
),
|
||||
averageRating: product.averageRating,
|
||||
reviewsCount: product.reviewsCount,
|
||||
description: product.description,
|
||||
isInstallable: product.isInstallable,
|
||||
} }
|
||||
tracksData={ {
|
||||
position: index + 1,
|
||||
...( product.label && { label: product.label } ),
|
||||
...( props.group && { group: props.group } ),
|
||||
...( props.searchTerm && {
|
||||
searchTerm: props.searchTerm,
|
||||
} ),
|
||||
...( props.category && { category: props.category } ),
|
||||
} }
|
||||
/>
|
||||
) ) }
|
||||
</div>
|
||||
}
|
||||
) }
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,3 +7,11 @@
|
|||
margin-top: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-marketplace__sub-header {
|
||||
display: flex;
|
||||
|
||||
.woocommerce-marketplace__customize-your-store-button {
|
||||
margin: 16px 0 6px auto;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { __, _n, sprintf } from '@wordpress/i18n';
|
||||
import { useContext } from '@wordpress/element';
|
||||
import { useContext, useState } from '@wordpress/element';
|
||||
import { getNewPath, navigateTo, useQuery } from '@woocommerce/navigation';
|
||||
import { Button } from '@wordpress/components';
|
||||
import classnames from 'classnames';
|
||||
import { addQueryArgs } from '@wordpress/url';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -18,6 +20,8 @@ import ProductLoader from '../product-loader/product-loader';
|
|||
import NoResults from '../product-list-content/no-results';
|
||||
import { Product, ProductType, SearchResultType } from '../product-list/types';
|
||||
import { MARKETPLACE_ITEMS_PER_PAGE } from '../constants';
|
||||
import { ADMIN_URL } from '~/utils/admin-settings';
|
||||
import { ThemeSwitchWarningModal } from '~/customize-store/intro/warning-modals';
|
||||
|
||||
interface ProductsProps {
|
||||
categorySelector?: boolean;
|
||||
|
@ -39,15 +43,27 @@ const LABELS = {
|
|||
},
|
||||
};
|
||||
|
||||
export default function Products( props: ProductsProps ): JSX.Element {
|
||||
export default function Products( props: ProductsProps ) {
|
||||
const marketplaceContextValue = useContext( MarketplaceContext );
|
||||
const { isLoading } = marketplaceContextValue;
|
||||
const label = LABELS[ props.type ].label;
|
||||
const singularLabel = LABELS[ props.type ].singularLabel;
|
||||
const query = useQuery();
|
||||
const category = query?.category;
|
||||
|
||||
const perPage = props.perPage ?? MARKETPLACE_ITEMS_PER_PAGE;
|
||||
interface Theme {
|
||||
stylesheet?: string;
|
||||
}
|
||||
|
||||
const currentTheme = useSelect( ( select ) => {
|
||||
return select( 'core' ).getCurrentTheme() as Theme;
|
||||
}, [] );
|
||||
const isDefaultTheme = currentTheme?.stylesheet === 'twentytwentyfour';
|
||||
const [ isModalOpen, setIsModalOpen ] = useState( false );
|
||||
const customizeStoreDesignUrl = addQueryArgs( `${ ADMIN_URL }admin.php`, {
|
||||
page: 'wc-admin',
|
||||
path: '/customize-store/design',
|
||||
} );
|
||||
|
||||
// Only show the "View all" button when on search but not showing a specific section of results.
|
||||
const showAllButton = props.showAllButton ?? false;
|
||||
|
@ -92,53 +108,28 @@ export default function Products( props: ProductsProps ): JSX.Element {
|
|||
baseContainerClass + 'button-' + label
|
||||
);
|
||||
|
||||
function content() {
|
||||
if ( isLoading ) {
|
||||
return (
|
||||
<>
|
||||
{ props.categorySelector && (
|
||||
<CategorySelector type={ props.type } />
|
||||
) }
|
||||
<ProductLoader hasTitle={ false } type={ props.type } />
|
||||
</>
|
||||
);
|
||||
}
|
||||
if ( products.length === 0 ) {
|
||||
const type =
|
||||
props.type === ProductType.extension
|
||||
? SearchResultType.extension
|
||||
: SearchResultType.theme;
|
||||
|
||||
if ( products.length === 0 ) {
|
||||
const type =
|
||||
props.type === ProductType.extension
|
||||
? SearchResultType.extension
|
||||
: SearchResultType.theme;
|
||||
return <NoResults type={ type } showHeading={ false } />;
|
||||
}
|
||||
|
||||
return <NoResults type={ type } showHeading={ false } />;
|
||||
}
|
||||
|
||||
const productListClass = classnames(
|
||||
showAllButton
|
||||
? 'woocommerce-marketplace__product-list-content--collapsed'
|
||||
: ''
|
||||
);
|
||||
const productListClass = classnames(
|
||||
showAllButton
|
||||
? 'woocommerce-marketplace__product-list-content--collapsed'
|
||||
: ''
|
||||
);
|
||||
|
||||
if ( isLoading ) {
|
||||
return (
|
||||
<>
|
||||
{ props.categorySelector && (
|
||||
<CategorySelector type={ props.type } />
|
||||
) }
|
||||
<ProductListContent
|
||||
products={ products }
|
||||
type={ props.type }
|
||||
className={ productListClass }
|
||||
searchTerm={ props.searchTerm }
|
||||
category={ category }
|
||||
/>
|
||||
{ showAllButton && (
|
||||
<Button
|
||||
className={ viewAllButonClassName }
|
||||
variant="secondary"
|
||||
text={ __( 'View all', 'woocommerce' ) }
|
||||
onClick={ () => showSection( props.type ) }
|
||||
/>
|
||||
) }
|
||||
<ProductLoader hasTitle={ false } type={ props.type } />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -148,7 +139,46 @@ export default function Products( props: ProductsProps ): JSX.Element {
|
|||
<h2 className={ productListTitleClassName }>
|
||||
{ isLoading ? ' ' : title }
|
||||
</h2>
|
||||
{ content() }
|
||||
<div className="woocommerce-marketplace__sub-header">
|
||||
{ props.categorySelector && (
|
||||
<CategorySelector type={ props.type } />
|
||||
) }
|
||||
{ props.type === 'theme' && (
|
||||
<Button
|
||||
className="woocommerce-marketplace__customize-your-store-button"
|
||||
variant="secondary"
|
||||
text={ __( 'Design your own', 'woocommerce' ) }
|
||||
onClick={ () => {
|
||||
if ( ! isDefaultTheme ) {
|
||||
setIsModalOpen( true );
|
||||
} else {
|
||||
window.location.href = customizeStoreDesignUrl;
|
||||
}
|
||||
} }
|
||||
/>
|
||||
) }
|
||||
</div>
|
||||
{ isModalOpen && (
|
||||
<ThemeSwitchWarningModal
|
||||
setIsModalOpen={ setIsModalOpen }
|
||||
customizeStoreDesignUrl={ customizeStoreDesignUrl }
|
||||
/>
|
||||
) }
|
||||
<ProductListContent
|
||||
products={ products }
|
||||
type={ props.type }
|
||||
className={ productListClass }
|
||||
searchTerm={ props.searchTerm }
|
||||
category={ category }
|
||||
/>
|
||||
{ showAllButton && (
|
||||
<Button
|
||||
className={ viewAllButonClassName }
|
||||
variant="secondary"
|
||||
text={ __( 'View all', 'woocommerce' ) }
|
||||
onClick={ () => showSection( props.type ) }
|
||||
/>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: major
|
||||
Type: add
|
||||
|
||||
Update the WooCommerce Extensions Theme page to include references to the Customize Your Store flow.
|
Loading…
Reference in New Issue