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:
parent
43024547a1
commit
44c29dd2f3
|
@ -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 /> }
|
||||||
|
|
Loading…
Reference in New Issue