Marketplace: Add no results page (#39690)

This commit is contained in:
Cem Ünalan 2023-08-16 11:28:26 +03:00 committed by GitHub
commit 2233eaf871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 201 additions and 36 deletions

View File

@ -0,0 +1,12 @@
<svg width="74" height="100" viewBox="0 0 74 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M67.7896 0L62.6619 4.11855L57.5289 0L52.4011 4.11855L47.2682 0L42.1353 4.11855L37.0075 0L31.8746 4.11855L26.7468 0L21.6138 4.11855L16.4809 0L11.348 4.11855L6.21501 0L0.916992 4.25258V95.7474L6.20986 100L11.3428 95.8763L16.4706 100L21.6035 95.8763L26.7313 100L31.8642 95.8763L36.9972 100L42.125 95.8763L47.2579 100L52.3857 95.8763L57.5186 100L62.6515 95.8763L67.7896 100L73.0825 95.7474V4.25258L67.7896 0Z" fill="#E0E0E0"/>
<path d="M49.4449 18.7216H7.10547V22.5103H49.4449V18.7216Z" fill="#757575"/>
<path d="M49.4449 30.2784H7.10547V34.067H49.4449V30.2784Z" fill="#757575"/>
<path d="M49.4449 41.8351H7.10547V45.6237H49.4449V41.8351Z" fill="#757575"/>
<path d="M66.8991 18.7216H56.9102V22.5103H66.8991V18.7216Z" fill="white"/>
<path d="M66.8991 30.2783H56.9102V34.067H66.8991V30.2783Z" fill="white"/>
<path d="M66.8991 41.835H56.9102V45.6237H66.8991V41.835Z" fill="white"/>
<path d="M66.8993 63.9176H50.4043V71.1341H66.8993V63.9176Z" fill="#757575"/>
<path d="M7.13379 55.5258H66.8714" stroke="#271B3D" stroke-width="0.510311" stroke-miterlimit="10"/>
<path d="M51.2154 89.8917C50.6639 89.8917 50.1845 89.7731 49.8082 89.4999C48.0556 88.2473 47.8597 85.768 47.6845 83.5772C47.4886 81.0618 47.2876 79.5205 45.736 79.5205C44.437 79.5205 43.5659 81.7731 42.7205 83.9484C41.705 86.5669 40.6535 89.2731 38.6122 89.2731C36.4473 89.2731 36.1895 87.1752 35.937 85.1494C35.6741 83.0205 35.4266 81.0051 33.2256 81.0051V80.4948C35.8802 80.4948 36.1792 82.9329 36.4473 85.0875C36.7308 87.3762 37.1586 88.4071 38.6071 88.4535C39.8648 88.4896 41.2875 86.2267 42.2411 83.768C43.1896 81.3247 44.2978 78.2886 45.9473 78.2886C48.0504 78.2886 48.2721 80.3762 48.4061 82.8195C48.5401 85.2628 48.5401 87.9741 50.102 89.0927C52.8546 91.0618 62.4011 83.2473 66.2259 79.4174L67.0558 80.3711C66.5609 80.804 56.0093 89.8968 51.2154 89.8968V89.8917Z" fill="#CCCCCC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -50,23 +50,17 @@ export default function CategorySelector(): JSX.Element {
fetchCategories()
.then( ( categoriesFromAPI: CategoryAPIItem[] ) => {
const categories: Category[] = categoriesFromAPI.map(
( categoryAPIItem: CategoryAPIItem ): Category => {
const categories: Category[] = categoriesFromAPI
.map( ( categoryAPIItem: CategoryAPIItem ): Category => {
return {
...categoryAPIItem,
selected: false,
};
}
);
// Put the "All" category to the beginning
categories.sort( ( a ) => {
if ( a.slug === ALL_CATEGORIES_SLUG ) {
return -1;
}
return 1;
} );
} )
.filter( ( category: Category ): boolean => {
// The "featured" category is returned from the API for legacy reasons, but we don't need it:
return category.slug !== '_featured';
} );
// Split array into two from 7th item
const visibleCategoryItems = categories.slice( 0, 7 );
@ -132,20 +126,22 @@ export default function CategorySelector(): JSX.Element {
</li>
) ) }
<li className="woocommerce-marketplace__category-item">
<CategoryDropdown
label={ __( 'More', 'woocommerce' ) }
categories={ dropdownItems }
buttonClassName={ classNames(
'woocommerce-marketplace__category-item-button',
{
'woocommerce-marketplace__category-item-button--selected':
isSelectedInDropdown(),
}
) }
contentClassName="woocommerce-marketplace__category-item-content"
arrowIconSize={ 20 }
selected={ selected }
/>
{ dropdownItems.length > 0 && (
<CategoryDropdown
label={ __( 'More', 'woocommerce' ) }
categories={ dropdownItems }
buttonClassName={ classNames(
'woocommerce-marketplace__category-item-button',
{
'woocommerce-marketplace__category-item-button--selected':
isSelectedInDropdown(),
}
) }
contentClassName="woocommerce-marketplace__category-item-content"
arrowIconSize={ 20 }
selected={ selected }
/>
) }
</li>
</ul>

View File

@ -2,7 +2,7 @@
* External dependencies
*/
import { useContext } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { __, _n, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
@ -12,6 +12,7 @@ import CategorySelector from '../category-selector/category-selector';
import { ProductListContext } from '../../contexts/product-list-context';
import ProductListContent from '../product-list-content/product-list-content';
import ProductLoader from '../product-loader/product-loader';
import NoResults from '../product-list-content/no-results';
export default function Extensions(): JSX.Element {
const productListContextValue = useContext( ProductListContext );
@ -19,27 +20,40 @@ export default function Extensions(): JSX.Element {
const { productList, isLoading } = productListContextValue;
const products = productList.slice( 0, 60 );
let title = __( 'Extensions', 'woocommerce' );
let title = __( '0 extensions found', 'woocommerce' );
if ( products.length > 0 ) {
title = sprintf(
// translators: %s: number of extensions
__( '%s extensions', 'woocommerce' ),
_n(
'%s extension',
'%s extensions',
products.length,
'woocommerce'
),
products.length
);
}
function content() {
if ( isLoading ) {
return <ProductLoader />;
}
if ( products.length === 0 ) {
return <NoResults />;
}
return <ProductListContent products={ products } />;
}
return (
<div className="woocommerce-marketplace__extensions">
<h2 className="woocommerce-marketplace__product-list-title woocommerce-marketplace__product-list-title--extensions">
{ title }
</h2>
<CategorySelector />
{ isLoading ? (
<ProductLoader />
) : (
<ProductListContent products={ products } />
) }
{ content() }
</div>
);
}

View File

@ -0,0 +1,27 @@
@import '../../stylesheets/_variables.scss';
.woocommerce-marketplace__no-results__content {
border: 1px solid $gutenberg-gray-100;
padding: $grid-unit-80 $grid-unit-40;
display: flex;
flex-direction: column;
margin-top: $grid-unit-30;
}
.woocommerce-marketplace__no-results__product-group {
margin-top: $grid-unit-60;
}
.woocommerce-marketplace__no-results__icon {
height: 100px;
}
.woocommerce-marketplace__no-results__description {
text-align: center;
font-size: 13px;
}
.woocommerce-marketplace__no-results__description--bold {
font-weight: 600;
font-size: 16px;
}

View File

@ -0,0 +1,116 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { useEffect, useState } from '@wordpress/element';
import { useQuery } from '@woocommerce/navigation';
/**
* Internal dependencies
*/
import NoResultsIcon from '../../assets/images/no-results.svg';
import { fetchDiscoverPageData, ProductGroup } from '../../utils/functions';
import ProductLoader from '../product-loader/product-loader';
import ProductList from '../product-list/product-list';
import './no-results.scss';
export default function NoResults(): JSX.Element {
const [ productGroup, setProductGroup ] = useState< ProductGroup >();
const [ isLoadingProductGroup, setisLoadingProductGroup ] =
useState( false );
const [ noResultsTerm, setNoResultsTerm ] = useState< string >( '' );
const query = useQuery();
useEffect( () => {
if ( query.term ) {
setNoResultsTerm( query.term );
}
if ( query.category ) {
/**
* Trim understore from start and end of a category. Some categories have underscores at the start and end
* and we don't want to show them for the no results term
*/
const categoryTerm = query.category.replace( /^_+|_+$/g, '' );
setNoResultsTerm( categoryTerm );
}
}, [ query ] );
useEffect( () => {
setisLoadingProductGroup( true );
fetchDiscoverPageData()
.then( ( products: Array< ProductGroup > ) => {
const mostPopularGroup = products.find(
( group ) => group.id === 'most-popular'
);
if ( ! mostPopularGroup ) {
return;
}
mostPopularGroup.items = mostPopularGroup.items.slice( 0, 9 );
setProductGroup( mostPopularGroup );
} )
.catch( () => {
setProductGroup( undefined );
} )
.finally( () => {
setisLoadingProductGroup( false );
} );
}, [] );
function renderProductGroup() {
if ( isLoadingProductGroup ) {
return <ProductLoader />;
}
if ( ! productGroup ) {
return <></>;
}
return (
<ProductList
title={ productGroup.title }
products={ productGroup.items }
groupURL={ productGroup.url }
/>
);
}
return (
<div className="woocommerce-marketplace__no-results">
<div className="woocommerce-marketplace__no-results__content">
<img
className="woocommerce-marketplace__no-results__icon"
src={ NoResultsIcon }
alt={ __( 'No results.', 'woocommerce' ) }
/>
<div className="woocommerce-marketplace__no-results__description">
<p className="woocommerce-marketplace__no-results__description--bold">
{ sprintf(
// translators: %s: search term
__(
'We didn\'t find any results for "%s"',
'woocommerce'
),
noResultsTerm
) }
</p>
<p>
{ __(
'Try searching again using a different term, or take a look at some of our most popular extensions below.',
'woocommerce'
) }
</p>
</div>
</div>
<div className="woocommerce-marketplace__no-results__product-group">
{ renderProductGroup() }
</div>
</div>
);
}

View File

@ -6,7 +6,7 @@ import { MARKETPLACE_URL } from '../components/constants';
import { CategoryAPIItem } from '../components/category-selector/types';
interface ProductGroup {
id: number;
id: string;
title: string;
items: Product[];
url: string;