Skip to content
Open
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 @@ -19,6 +19,7 @@ import getSite from 'calypso/state/sites/selectors/get-site';
import { setSelectedSiteId } from 'calypso/state/ui/actions';
import ClientCheckoutError from './checkout-error';
import ClientCheckoutPlaceholder from './checkout-placeholder';
import getPurchasedWPCOMPlanSlug from './lib/get-purchased-wpcom-plan-slug';
import getSuccessRedirectUrl from './lib/get-success-redirect-url';
import type { ShoppingCartItem } from '../types';

Expand Down Expand Up @@ -253,7 +254,8 @@ function BillingDragonCheckoutContent( {
sitelessCheckoutType="a4a"
redirectTo={ getSuccessRedirectUrl(
window.location.origin,
shouldClearCartOnSuccess && ! isPlanCheckout
shouldClearCartOnSuccess && ! isPlanCheckout,
isPlanCheckout ? null : getPurchasedWPCOMPlanSlug( cartItems )
) }
customizedPreviousPath="/marketplace"
siteSlug={ siteSlug ?? '' }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { isWPCOMHostingProduct } from '../../lib/hosting';
import type { ShoppingCartItem } from '../../types';

/**
* A cart holding a WordPress.com plan lands on the "Needs setup" page rather
* than the licenses list, so the agency can provision the site right away. The
* returned slug is what that page's confirmation banner reports to Tracks.
*/
export default function getPurchasedWPCOMPlanSlug( cartItems: ShoppingCartItem[] ): string | null {
return cartItems.find( ( { slug } ) => isWPCOMHostingProduct( slug ) )?.slug ?? null;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import {
A4A_LICENSES_LINK,
A4A_SITES_LINK_NEEDS_SETUP,
} from 'calypso/a8c-for-agencies/components/sidebar-menu/lib/constants';

/**
* The checkout pending page replaces `:receiptId` with the real receipt ID, but
* only when the transaction succeeds — failed or cancelled payments are sent
* back to checkout instead. This makes `receipt_id` on the licenses page a
* back to checkout instead. This makes `receipt_id` on the landing page a
* reliable "successful purchase" signal used to clear the persisted mini-cart.
*/
export const RECEIPT_ID_PLACEHOLDER = ':receiptId';

export default function getSuccessRedirectUrl(
origin: string,
shouldClearCartOnSuccess: boolean
shouldClearCartOnSuccess: boolean,
wpcomPlanSlug?: string | null
): string {
const url = `${ origin }/purchases/licenses`;
const url = `${ origin }${ wpcomPlanSlug ? A4A_SITES_LINK_NEEDS_SETUP : A4A_LICENSES_LINK }`;

const queryArgs = [
...( wpcomPlanSlug
? [ `wpcom_creator_purchased=${ encodeURIComponent( wpcomPlanSlug ) }` ]
: [] ),
// Built by hand rather than with `addQueryArgs`, which would percent-encode
// the colon the pending page looks for when interpolating the receipt ID.
...( shouldClearCartOnSuccess ? [ `receipt_id=${ RECEIPT_ID_PLACEHOLDER }` ] : [] ),
];

return shouldClearCartOnSuccess ? `${ url }?receipt_id=${ RECEIPT_ID_PLACEHOLDER }` : url;
return queryArgs.length ? `${ url }?${ queryArgs.join( '&' ) }` : url;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import getPurchasedWPCOMPlanSlug from '../get-purchased-wpcom-plan-slug';
import type { ShoppingCartItem } from '../../../types';

const cartItem = ( slug: string ) => ( { slug } ) as ShoppingCartItem;

describe( 'getPurchasedWPCOMPlanSlug', () => {
it( 'returns the slug of the purchased WordPress.com plan', () => {
expect( getPurchasedWPCOMPlanSlug( [ cartItem( 'wpcom-hosting-business' ) ] ) ).toBe(
'wpcom-hosting-business'
);
} );

it( 'matches a WordPress.com plan alongside other products, as the legacy flow did', () => {
expect(
getPurchasedWPCOMPlanSlug( [
cartItem( 'jetpack-backup' ),
cartItem( 'wpcom-hosting-business' ),
] )
).toBe( 'wpcom-hosting-business' );
} );

it( 'returns null when no WordPress.com plan is in the cart', () => {
expect(
getPurchasedWPCOMPlanSlug( [ cartItem( 'jetpack-backup' ), cartItem( 'pressable-build' ) ] )
).toBeNull();
} );

it( 'returns null for an empty cart', () => {
expect( getPurchasedWPCOMPlanSlug( [] ) ).toBeNull();
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,26 @@ describe( 'getSuccessRedirectUrl', () => {
`receipt_id=${ RECEIPT_ID_PLACEHOLDER }`
);
} );

it( 'sends WordPress.com purchases to the needs setup page with the purchased plan', () => {
expect(
getSuccessRedirectUrl( 'https://agencies.automattic.com', false, 'wpcom-hosting-business' )
).toBe(
'https://agencies.automattic.com/sites/need-setup?wpcom_creator_purchased=wpcom-hosting-business'
);
} );

it( 'keeps the receipt ID placeholder alongside the purchased plan', () => {
expect(
getSuccessRedirectUrl( 'https://agencies.automattic.com', true, 'wpcom-hosting-business' )
).toBe(
'https://agencies.automattic.com/sites/need-setup?wpcom_creator_purchased=wpcom-hosting-business&receipt_id=:receiptId'
);
} );

it( 'falls back to the licenses URL when no WordPress.com plan was purchased', () => {
expect( getSuccessRedirectUrl( 'https://agencies.automattic.com', false, null ) ).toBe(
'https://agencies.automattic.com/purchases/licenses'
);
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useCreateWPCOMSiteMutation from 'calypso/a8c-for-agencies/data/sites/use-
import useFetchPendingSites from 'calypso/a8c-for-agencies/data/sites/use-fetch-pending-sites';
import useSiteCreatedCallback from 'calypso/a8c-for-agencies/hooks/use-site-created-callback';
import useTrackProvisioningSites from 'calypso/a8c-for-agencies/hooks/use-track-provisioning-sites';
import useClearCartOnCheckoutSuccess from 'calypso/a8c-for-agencies/sections/marketplace/hooks/use-clear-cart-on-checkout-success';
import LayoutColumn from 'calypso/layout/hosting-dashboard/column';
import LayoutHeader, {
LayoutHeaderTitle as Title,
Expand Down Expand Up @@ -47,6 +48,8 @@ export default function NeedSetup( { licenseKey }: Props ) {
null
);

useClearCartOnCheckoutSuccess();

const closeModal = () => setCurrentSiteConfigurationId( null );

const title = translate( 'Sites' );
Expand Down
Loading