diff --git a/client/my-sites/plans/jetpack-plans/use-item-price.ts b/client/my-sites/plans/jetpack-plans/use-item-price.ts index b027e8d773e137..cb8c52243519ec 100644 --- a/client/my-sites/plans/jetpack-plans/use-item-price.ts +++ b/client/my-sites/plans/jetpack-plans/use-item-price.ts @@ -13,6 +13,7 @@ import { import { getProductCost } from 'calypso/state/products-list/selectors/get-product-cost'; import { getProductPriceTierList } from 'calypso/state/products-list/selectors/get-product-price-tiers'; import { isProductsListFetching } from 'calypso/state/products-list/selectors/is-products-list-fetching'; +import getIntroOfferEligibility from 'calypso/state/selectors/get-intro-offer-eligibility'; import getIntroOfferPrice from 'calypso/state/selectors/get-intro-offer-price'; import isRequestingIntroOffers from 'calypso/state/selectors/get-is-requesting-into-offers'; import { @@ -113,7 +114,12 @@ const useIntroductoryOfferPrices = ( } const introOfferPrice = getIntroOfferPrice( state, product.product_id, siteId ?? 'none' ); - return isNumber( introOfferPrice ) ? introOfferPrice : null; + const isEligibleForIntroPrice = getIntroOfferEligibility( + state, + product.product_id, + siteId ?? 'none' + ); + return isNumber( introOfferPrice ) && isEligibleForIntroPrice ? introOfferPrice : null; } ); return { diff --git a/client/state/products-list/actions.js b/client/state/products-list/actions.js index 2af2de4345d315..8f2f52392da990 100644 --- a/client/state/products-list/actions.js +++ b/client/state/products-list/actions.js @@ -37,23 +37,35 @@ export function receiveProductsList( productsList, type = null ) { * or undefined, for all products * @returns {Function} an Action thunk */ -export function requestProductsList( query = {} ) { +export function requestProductsList( query = {}, siteQueryFailed = false ) { + const queryParams = new URLSearchParams( window.location.search ); + const site = siteQueryFailed ? null : queryParams.get( 'site' ); + const requestQuery = { ...query }; if ( query.product_slugs && query.product_slugs.length > 0 ) { const product_slugs = query.product_slugs?.join( ',' ); requestQuery.product_slugs = product_slugs; } + + const path = site ? `/sites/${ site }/products` : '/products'; + return ( dispatch ) => { dispatch( { type: PRODUCTS_LIST_REQUEST } ); return wpcom.req - .get( '/products', requestQuery ) + .get( path, requestQuery ) .then( ( productsList ) => dispatch( receiveProductsList( productsList, query.type ) ) ) - .catch( ( error ) => + .catch( ( error ) => { + // If the query had the site in context and it failed, it means there was either a server error or the site doesn't exist. + // In this case, we should retry to fetch the products list without the site in context. + if ( site ) { + return requestProductsList( query, true )( dispatch ); + } + dispatch( { type: PRODUCTS_LIST_REQUEST_FAILURE, error, - } ) - ); + } ); + } ); }; } diff --git a/client/state/products-list/test/actions.js b/client/state/products-list/test/actions.js index 207c238ba8ad4a..39f7eb247e805d 100644 --- a/client/state/products-list/test/actions.js +++ b/client/state/products-list/test/actions.js @@ -11,6 +11,11 @@ describe( 'actions', () => { beforeEach( () => { spy = jest.fn(); + global.window = { + location: { + search: '', + }, + }; } ); const businessPlan = { diff --git a/client/state/selectors/get-intro-offer-eligibility.ts b/client/state/selectors/get-intro-offer-eligibility.ts new file mode 100644 index 00000000000000..01faa382c8193d --- /dev/null +++ b/client/state/selectors/get-intro-offer-eligibility.ts @@ -0,0 +1,22 @@ +import type { AppState } from 'calypso/types'; + +/** + * @param {Object} state Global state tree + * @param {number} productId The productId to check for an intro offer + * @param {number|'none'|undefined} siteId The ID of the site we're querying + * @returns {boolean} Whether the site is eligible for an intro offer + */ + +export default function getIntroOfferEligibility( + state: AppState, + productId: number, + siteId: number | 'none' | undefined +): boolean { + const siteIdKey = siteId && typeof siteId === 'number' && siteId > 0 ? siteId : 'none'; + + const introOffer = state.sites?.introOffers?.items?.[ siteIdKey ]?.[ productId ]; + + const ineligibleReason = introOffer?.ineligibleReason; + + return ! ineligibleReason || ineligibleReason?.length === 0; +}