When a search is initiated, fetch all categories to keep the tab counts up to date.

The necessary filtering to display data to the current screen will be performed on the frontend.
This commit is contained in:
Boro Sitnikovski 2024-09-11 17:14:11 +02:00
parent 43024547a1
commit 44c29dd2f3
1 changed files with 107 additions and 107 deletions

View File

@ -8,7 +8,7 @@ import { useQuery } from '@woocommerce/navigation';
* Internal dependencies * Internal dependencies
*/ */
import './content.scss'; import './content.scss';
import { Product, ProductType, SearchResultType } from '../product-list/types'; import { Product, ProductType } from '../product-list/types';
import { getAdminSetting } from '~/utils/admin-settings'; import { getAdminSetting } from '~/utils/admin-settings';
import Discover from '../discover/discover'; import Discover from '../discover/discover';
import Products from '../products/products'; import Products from '../products/products';
@ -30,7 +30,10 @@ import SubscriptionsExpiredExpiringNotice from '~/marketplace/components/my-subs
export default function Content(): JSX.Element { export default function Content(): JSX.Element {
const marketplaceContextValue = useContext( MarketplaceContext ); const marketplaceContextValue = useContext( MarketplaceContext );
const [ products, setProducts ] = useState< Product[] >( [] ); const [ allProducts, setAllProducts ] = useState< Product[] >( [] );
const [ filteredProducts, setFilteredProducts ] = useState< Product[] >(
[]
);
const { const {
setIsLoading, setIsLoading,
selectedTab, selectedTab,
@ -39,21 +42,40 @@ export default function Content(): JSX.Element {
} = marketplaceContextValue; } = marketplaceContextValue;
const query = useQuery(); const query = useQuery();
// On initial load of the in-app marketplace, fetch extensions, themes and business services // Function to tag products with their type
// and check if there are any business services available on WCCOM const tagProductsWithType = (
products: Product[],
type: ProductType
): Product[] => {
return products.map( ( product ) => ( {
...product,
type, // Adding the product type to each product
} ) );
};
// Fetch all categories when query.term or query.category changes
useEffect( () => { useEffect( () => {
const categories: Array< keyof SearchResultsCountType > = [ const categories: Array< {
'extensions', key: keyof SearchResultsCountType;
'themes', type: ProductType;
'business-services', } > = [
{ key: 'extensions', type: ProductType.extension },
{ key: 'themes', type: ProductType.theme },
{ key: 'business-services', type: ProductType.businessService },
]; ];
const abortControllers = categories.map( () => new AbortController() ); const abortControllers = categories.map( () => new AbortController() );
categories.forEach( setIsLoading( true );
( category: keyof SearchResultsCountType, index ) => { setAllProducts( [] );
Promise.all(
categories.map( ( { key, type }, index ) => {
const params = new URLSearchParams(); const params = new URLSearchParams();
if ( category !== 'extensions' ) { if ( key !== 'extensions' ) {
params.append( 'category', category ); params.append( 'category', key );
}
if ( query.term ) {
params.append( 'term', query.term );
} }
const wccomSettings = getAdminSetting( 'wccomHelper', false ); const wccomSettings = getAdminSetting( 'wccomHelper', false );
@ -61,114 +83,96 @@ export default function Content(): JSX.Element {
params.append( 'country', wccomSettings.storeCountry ); params.append( 'country', wccomSettings.storeCountry );
} }
fetchSearchResults( return fetchSearchResults(
params, params,
abortControllers[ index ].signal abortControllers[ index ].signal
).then( ( productList ) => { ).then( ( productList ) => {
if ( category === 'business-services' ) { // Tag the products with their type (extension, theme, or business-service)
setHasBusinessServices( productList.length > 0 ); const typedProducts = tagProductsWithType(
productList,
type
);
if ( key === 'business-services' ) {
setHasBusinessServices( typedProducts.length > 0 );
} }
return typedProducts;
} ); } );
return () => { } )
abortControllers.forEach( ( controller ) => { )
controller.abort(); .then( ( results ) => {
} ); const combinedProducts = results.flat();
}; setAllProducts( combinedProducts );
}
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [] );
// Get the content for this screen // Set the search results count based on product types
useEffect( () => { setSearchResultsCount( {
const abortController = new AbortController(); extensions: combinedProducts.filter(
( p ) => p.type === ProductType.extension
if ( ).length,
query.tab === undefined || themes: combinedProducts.filter(
( query.tab && [ '', 'discover' ].includes( query.tab ) ) ( p ) => p.type === ProductType.theme
) { ).length,
return; 'business-services': combinedProducts.filter(
} ( p ) => p.type === ProductType.businessService
).length,
setIsLoading( true ); } );
setProducts( [] );
const params = new URLSearchParams();
if ( query.term ) {
params.append( 'term', query.term );
}
if ( query.category ) {
params.append(
'category',
query.category === '_all' ? '' : query.category
);
} else if ( query?.tab === 'themes' ) {
params.append( 'category', 'themes' );
} else if ( query?.tab === 'business-services' ) {
params.append( 'category', 'business-services' );
}
const wccomSettings = getAdminSetting( 'wccomHelper', false );
if ( wccomSettings.storeCountry ) {
params.append( 'country', wccomSettings.storeCountry );
}
fetchSearchResults( params, abortController.signal )
.then( ( productList ) => {
setProducts( productList );
if ( query.term ) {
setSearchResultsCount( {
extensions: productList.filter(
( p ) => p.type === 'extension'
).length,
themes: productList.filter(
( p ) => p.type === 'theme'
).length,
'business-services': productList.filter(
( p ) => p.type === 'business-service'
).length,
} );
}
} ) } )
.catch( () => { .catch( () => {
setProducts( [] ); setAllProducts( [] );
} ) } )
.finally( () => { .finally( () => {
// we are recording both the new and legacy events here for now
// they're separate methods to make it easier to remove the legacy one later
const marketplaceViewProps = {
view: query?.tab,
search_term: query?.term,
product_type: query?.section,
category: query?.category,
};
recordMarketplaceView( marketplaceViewProps );
recordLegacyTabView( marketplaceViewProps );
setIsLoading( false ); setIsLoading( false );
} ); } );
return () => { return () => {
abortController.abort(); abortControllers.forEach( ( controller ) => {
controller.abort();
} );
}; };
}, [ }, [ query.term, query.category ] ); // Depend on term and category
query.term,
query.category, // Filter the products based on the selected tab
query?.tab, useEffect( () => {
setIsLoading, let filtered: Product[] | null;
query?.section, switch ( selectedTab ) {
] ); case 'extensions':
filtered = allProducts.filter(
( p ) => p.type === ProductType.extension
);
break;
case 'themes':
filtered = allProducts.filter(
( p ) => p.type === ProductType.theme
);
break;
case 'business-services':
filtered = allProducts.filter(
( p ) => p.type === ProductType.businessService
);
break;
default:
filtered = [];
}
setFilteredProducts( filtered );
}, [ selectedTab, allProducts ] );
// Record tab view events when the query changes
useEffect( () => {
const marketplaceViewProps = {
view: query?.tab,
search_term: query?.term,
product_type: query?.section,
category: query?.category,
};
recordMarketplaceView( marketplaceViewProps );
recordLegacyTabView( marketplaceViewProps );
}, [ query?.tab, query?.term, query?.section, query?.category ] );
const renderContent = (): JSX.Element => { const renderContent = (): JSX.Element => {
switch ( selectedTab ) { switch ( selectedTab ) {
case 'extensions': case 'extensions':
return ( return (
<Products <Products
products={ products.filter( products={ filteredProducts }
( p ) => p.type === 'extension'
) }
categorySelector={ true } categorySelector={ true }
type={ ProductType.extension } type={ ProductType.extension }
/> />
@ -176,9 +180,7 @@ export default function Content(): JSX.Element {
case 'themes': case 'themes':
return ( return (
<Products <Products
products={ products.filter( products={ filteredProducts }
( p ) => p.type === 'theme'
) }
categorySelector={ true } categorySelector={ true }
type={ ProductType.theme } type={ ProductType.theme }
/> />
@ -186,9 +188,7 @@ export default function Content(): JSX.Element {
case 'business-services': case 'business-services':
return ( return (
<Products <Products
products={ products.filter( products={ filteredProducts }
( p ) => p.type === 'business-service'
) }
categorySelector={ true } categorySelector={ true }
type={ ProductType.businessService } type={ ProductType.businessService }
/> />
@ -209,7 +209,7 @@ export default function Content(): JSX.Element {
return ( return (
<div className="woocommerce-marketplace__content"> <div className="woocommerce-marketplace__content">
<Promotions /> <Promotions />
<InstallNewProductModal products={ products } /> <InstallNewProductModal products={ filteredProducts } />
{ selectedTab !== 'business-services' && { selectedTab !== 'business-services' &&
selectedTab !== 'my-subscriptions' && <ConnectNotice /> } selectedTab !== 'my-subscriptions' && <ConnectNotice /> }
{ selectedTab !== 'business-services' && <PluginInstallNotice /> } { selectedTab !== 'business-services' && <PluginInstallNotice /> }