Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -536,89 +536,6 @@ describe( 'useWPCOMDomainSearchProps', () => {
} );
} );

describe( 'config.priceRules.freeForFirstYearTlds', () => {
it( 'passes through the flow-provided list while the credit is still available in the stepper', () => {
mockUseShoppingCart.mockReturnValue(
buildShoppingCart( { responseCart: { products: [] } } )
);

const { result } = renderHookWithProvider( () =>
useWPCOMDomainSearchProps( {
...defaultProps,
isFirstDomainFreeForFirstYear: true,
config: { priceRules: { freeForFirstYearTlds: [ 'blog', 'art' ] } },
} )
);

expect( result.current.config.priceRules.freeForFirstYearTlds ).toEqual( [ 'blog', 'art' ] );
} );

it( 'clears the flow-provided list once the free slot is taken in the stepper', () => {
mockUseShoppingCart.mockReturnValue(
buildShoppingCart( {
responseCart: {
products: [
buildProduct( {
uuid: 'dotblog',
product_slug: 'blog_domain',
meta: 'my-domain.blog',
is_domain_registration: true,
item_original_cost_integer: 1000,
item_subtotal_integer: 1000,
} ),
],
},
} )
);

const { result } = renderHookWithProvider( () =>
useWPCOMDomainSearchProps( {
...defaultProps,
isFirstDomainFreeForFirstYear: true,
config: { priceRules: { freeForFirstYearTlds: [ 'blog', 'art' ] } },
} )
);

expect( result.current.config.priceRules.freeForFirstYearTlds ).toBeUndefined();
} );

it( 'derives the list from next_domain_condition when the plan is in the cart and the credit is available', () => {
mockUseShoppingCart.mockReturnValue(
buildShoppingCart( {
responseCart: {
next_domain_is_free: true,
next_domain_condition: 'blog,art',
products: [ buildProduct( { product_slug: 'business-bundle' } ) ],
},
} )
);

const { result } = renderHookWithProvider( () =>
useWPCOMDomainSearchProps( { ...defaultProps, isFirstDomainFreeForFirstYear: true } )
);

expect( result.current.config.priceRules.freeForFirstYearTlds ).toEqual( [ 'blog', 'art' ] );
} );

it( 'does not restrict by TLD when the plan is in the cart but the credit has already been used', () => {
mockUseShoppingCart.mockReturnValue(
buildShoppingCart( {
responseCart: {
next_domain_is_free: false,
next_domain_condition: 'blog,art',
products: [ buildProduct( { product_slug: 'business-bundle' } ) ],
},
} )
);

const { result } = renderHookWithProvider( () =>
useWPCOMDomainSearchProps( { ...defaultProps, isFirstDomainFreeForFirstYear: true } )
);

expect( result.current.config.priceRules.freeForFirstYearTlds ).toBeUndefined();
} );
} );

describe( 'total price', () => {
it( 'returns the total price for the cart', () => {
mockUseShoppingCart.mockReturnValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
CartActionError,
type CartKey,
type MinimalRequestCartProduct,
parseNextDomainCondition,
type ResponseCartProduct,
useShoppingCart,
} from '@automattic/shopping-cart';
Expand Down Expand Up @@ -56,7 +55,6 @@ interface UseWPCOMDomainSearchCartOptions {
flowName?: string;
flowAllowsMultipleDomainsInCart: boolean;
isFirstDomainFreeForFirstYear: boolean;
freeForFirstYearTlds?: string[];
onContinue( cartItems: ResponseCartProduct[] ): void;
beforeAddDomainToCart?: ( domain: MinimalRequestCartProduct ) => MinimalRequestCartProduct;
}
Expand All @@ -66,7 +64,6 @@ export const useWPCOMDomainSearchCart = ( {
flowName,
flowAllowsMultipleDomainsInCart,
isFirstDomainFreeForFirstYear,
freeForFirstYearTlds,
onContinue,
beforeAddDomainToCart = ( domain ) => domain,
}: UseWPCOMDomainSearchCartOptions ) => {
Expand All @@ -87,16 +84,6 @@ export const useWPCOMDomainSearchCart = ( {
// when they start a domain search flow.
const forceFirstNonPremiumDomainToBeFree = isFirstDomainFreeForFirstYear && ! isPlanInCart;

// Stepper: use flow config. Checkout (plan in real cart): derive from next_domain_condition.
let effectiveFreeForFirstYearTlds: string[] | undefined;
if ( forceFirstNonPremiumDomainToBeFree ) {
effectiveFreeForFirstYearTlds = freeForFirstYearTlds;
} else if ( responseCart.next_domain_condition ) {
effectiveFreeForFirstYearTlds = parseNextDomainCondition(
responseCart.next_domain_condition
);
}

// Order domains from most expensive to least expensive
domainItems.sort( ( a, b ) => {
// Put the bundled domain at the top, if there's one
Expand All @@ -117,15 +104,9 @@ export const useWPCOMDomainSearchCart = ( {
! item.extra?.premium &&
! item.extra?.domain_bundle_group_id
);
let freeDomainName: string | undefined;
if ( forceFirstNonPremiumDomainToBeFree && firstNonPremiumDomain?.meta ) {
const isBundledTld =
! effectiveFreeForFirstYearTlds ||
effectiveFreeForFirstYearTlds.some( ( tld ) =>
firstNonPremiumDomain.meta.endsWith( '.' + tld )
);
freeDomainName = isBundledTld ? firstNonPremiumDomain.meta : undefined;
}
const freeDomainName = forceFirstNonPremiumDomainToBeFree
? firstNonPremiumDomain?.meta
: undefined;

const rawTotal = domainItems.reduce(
( acc, item ) => acc + ( freeDomainName === item.meta ? 0 : item.item_subtotal_integer ),
Expand Down Expand Up @@ -282,16 +263,12 @@ export const useWPCOMDomainSearchCart = ( {
},
};

const isNextDomainFree = forceFirstNonPremiumDomainToBeFree
? freeDomainName === undefined
: responseCart.next_domain_is_free;

return {
cart,
isNextDomainFree,
isNextDomainFree: forceFirstNonPremiumDomainToBeFree
? freeDomainName === undefined
: responseCart.next_domain_is_free,
freeDomainName,
// Only restrict by TLD while the credit is actually available.
freeForFirstYearTlds: isNextDomainFree ? effectiveFreeForFirstYearTlds : undefined,
onContinue: () => onContinue( domainItems ),
};
}, [
Expand All @@ -300,7 +277,6 @@ export const useWPCOMDomainSearchCart = ( {
replaceProductsInCart,
flowName,
isFirstDomainFreeForFirstYear,
freeForFirstYearTlds,
flowAllowsMultipleDomainsInCart,
onContinue,
beforeAddDomainToCart,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,14 @@ export const useWPCOMDomainSearchProps = ( {
[ dispatch, analyticsSection, externalOnContinue ]
);

const { cart, isNextDomainFree, freeDomainName, freeForFirstYearTlds, onContinue } =
useWPCOMDomainSearchCart( {
cartKey: getCartKey( { isLoggedIn, currentSiteId } ),
flowName,
isFirstDomainFreeForFirstYear,
freeForFirstYearTlds: externalConfig?.priceRules?.freeForFirstYearTlds,
flowAllowsMultipleDomainsInCart,
onContinue: onContinueWithStepSubmissionTracking,
beforeAddDomainToCart: externalBeforeAddDomainToCart,
} );
const { cart, isNextDomainFree, freeDomainName, onContinue } = useWPCOMDomainSearchCart( {
cartKey: getCartKey( { isLoggedIn, currentSiteId } ),
flowName,
isFirstDomainFreeForFirstYear,
flowAllowsMultipleDomainsInCart,
onContinue: onContinueWithStepSubmissionTracking,
beforeAddDomainToCart: externalBeforeAddDomainToCart,
} );

const config = useMemo( () => {
// Bundles are fixed one-year registrations of multiple TLDs, so they
Expand All @@ -99,10 +97,9 @@ export const useWPCOMDomainSearchProps = ( {
// Keep the already-added free domain showing as $0 in the suggestion list,
// matching what the user saw when they clicked and what appears in their cart.
freeForFirstYearDomains: freeDomainName ? [ freeDomainName ] : undefined,
freeForFirstYearTlds,
},
};
}, [ externalConfig, isNextDomainFree, freeDomainName, freeForFirstYearTlds, flowName ] );
}, [ externalConfig, isNextDomainFree, freeDomainName, flowName ] );

const analyticsEvents = useWPCOMDomainSearchEvents( {
vendor: config.vendor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
isNewHostedSiteCreationFlow,
isNewsletterFlow,
isOnboardingFlow,
EDUCATION_FLOW,
Step,
StepContainer,
} from '@automattic/onboarding';
Expand Down Expand Up @@ -59,7 +58,6 @@ import type { HelpCenterSelect, OnboardSelect } from '@automattic/data-stores';
import type { MinimalRequestCartProduct } from '@automattic/shopping-cart';

const HUNDRED_YEAR_DOMAIN_TLDS = [ 'com', 'net', 'org', 'blog' ];
const EDUCATION_BUNDLED_TLDS = [ 'blog', 'art' ];

const HELP_CENTER_STORE = HelpCenter.register();

Expand Down Expand Up @@ -190,7 +188,6 @@ const DomainSearchStep: StepType< {
priceRules: {
hidePrice: isHundredYearPlanFlow( flow ),
oneTimePrice: isHundredYearDomainFlow( flow ),
freeForFirstYearTlds: flow === EDUCATION_FLOW ? EDUCATION_BUNDLED_TLDS : undefined,
},
skippable:
! isHundredYearPlanFlow( flow ) &&
Expand Down
6 changes: 2 additions & 4 deletions client/lib/cart-values/cart-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import {
} from '@automattic/calypso-products';
import { getTld } from '@automattic/domain-search';
import { isDomainForGravatarFlow, isHundredYearDomainFlow } from '@automattic/onboarding';
import { parseNextDomainCondition } from '@automattic/shopping-cart';
import { isWpComProductRenewal as isRenewal } from '@automattic/wpcom-checkout';
import { domainProductSlugs } from 'calypso/lib/domains/constants';
import type { WithCamelCaseSlug, WithSnakeCaseSlug } from '@automattic/calypso-products';
Expand Down Expand Up @@ -709,9 +708,8 @@ export function isNextDomainFree( cart?: ResponseCart, domain = '' ): boolean {
return false;
}

if ( cart.next_domain_condition ) {
const eligibleTlds = parseNextDomainCondition( cart.next_domain_condition );
if ( ! eligibleTlds.includes( getTld( domain ) ) ) {
if ( cart.next_domain_condition === 'blog' ) {
if ( getTld( domain ) !== 'blog' ) {
return false;
}
}
Expand Down
24 changes: 0 additions & 24 deletions client/lib/cart-values/test/cart-items.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,30 +227,6 @@ describe( 'isNextDomainFree()', () => {
)
).toBe( true );
} );
test( 'should return true when condition is "blog,art" and requested domain is .blog', () => {
expect(
isNextDomainFree(
{ next_domain_is_free: true, next_domain_condition: 'blog,art' },
'domain.blog'
)
).toBe( true );
} );
test( 'should return true when condition is "blog,art" and requested domain is .art', () => {
expect(
isNextDomainFree(
{ next_domain_is_free: true, next_domain_condition: 'blog,art' },
'domain.art'
)
).toBe( true );
} );
test( 'should return false when condition is "blog,art" and requested domain is .com', () => {
expect(
isNextDomainFree(
{ next_domain_is_free: true, next_domain_condition: 'blog,art' },
'domain.com'
)
).toBe( false );
} );
test( 'should return false when cart.next_domain_is_free is false', () => {
expect( isNextDomainFree( { next_domain_is_free: false } ) ).toBe( false );
} );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,67 +137,6 @@ describe( 'DomainSuggestionPrice', () => {
expect( await screen.findByLabelText( 'Sale price: $0' ) ).toBeInTheDocument();
} );

it( 'renders FREE_FOR_FIRST_YEAR when the domain TLD is in priceRules.freeForFirstYearTlds', async () => {
mockGetSuggestionsQuery( {
params: { query: 'test-free-tld.blog' },
suggestions: [
buildSuggestion( {
domain_name: 'test-free-tld.blog',
cost: '$5',
} ),
],
} );

render(
<TestDomainSearchWithSuggestions
query="test-free-tld.blog"
config={ {
priceRules: {
freeForFirstYearTlds: [ 'blog', 'art' ],
},
} }
>
<DomainSuggestionsList>
<DomainSuggestionPrice domainName="test-free-tld.blog" />
</DomainSuggestionsList>
</TestDomainSearchWithSuggestions>
);

expect( await screen.findByLabelText( 'Original price: $5' ) ).toBeInTheDocument();
expect( await screen.findByLabelText( 'Sale price: $0' ) ).toBeInTheDocument();
} );

it( 'renders the regular price when the domain TLD is not in priceRules.freeForFirstYearTlds', async () => {
mockGetSuggestionsQuery( {
params: { query: 'test-not-free-tld.com' },
suggestions: [
buildSuggestion( {
domain_name: 'test-not-free-tld.com',
cost: '$5',
sale_cost: 1,
} ),
],
} );

render(
<TestDomainSearchWithSuggestions
query="test-not-free-tld.com"
config={ {
priceRules: {
freeForFirstYearTlds: [ 'blog', 'art' ],
},
} }
>
<DomainSuggestionsList>
<DomainSuggestionPrice domainName="test-not-free-tld.com" />
</DomainSuggestionsList>
</TestDomainSearchWithSuggestions>
);

expect( await screen.findByLabelText( 'Original price: $5' ) ).toBeInTheDocument();
expect( await screen.findByLabelText( 'Sale price: $1' ) ).toBeInTheDocument();
} );

it( 'renders the renew price if priceRule is FREE_FOR_FIRST_YEAR and renew cost is provided', async () => {
mockGetSuggestionsQuery( {
params: { query: 'test-free-for-first-year-renew-cost.com' },
Expand Down
22 changes: 4 additions & 18 deletions packages/domain-search/src/hooks/use-suggestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ export interface PriceRulesConfig {
* the suggestion list after it has been added to the cart with a free-domain promotion.
*/
freeForFirstYearDomains?: string[];
/**
* When set, only domains whose TLD is in this list get FREE_FOR_FIRST_YEAR pricing.
* All other TLDs show their real price. Takes precedence over freeForFirstYear.
*/
freeForFirstYearTlds?: string[];
}

const getPriceRuleForSuggestion = ( {
Expand All @@ -52,19 +47,10 @@ const getPriceRuleForSuggestion = ( {
return DomainPriceRule.PRICE;
}

if ( priceRules.freeForFirstYearDomains?.includes( suggestion.domain_name ) ) {
return DomainPriceRule.FREE_FOR_FIRST_YEAR;
}

if ( priceRules.freeForFirstYearTlds ) {
return priceRules.freeForFirstYearTlds.some( ( tld ) =>
suggestion.domain_name.endsWith( '.' + tld )
)
? DomainPriceRule.FREE_FOR_FIRST_YEAR
: DomainPriceRule.PRICE;
}

if ( priceRules.freeForFirstYear ) {
if (
priceRules.freeForFirstYear ||
priceRules.freeForFirstYearDomains?.includes( suggestion.domain_name )
) {
return DomainPriceRule.FREE_FOR_FIRST_YEAR;
}

Expand Down
Loading
Loading