Skip to content

Commit

Permalink
My Jetpack: Add direct checkout support for products with quantity-ba…
Browse files Browse the repository at this point in the history
…sed plans (#34177)

* add quantity to product checkout workflow hook and product detail card

* pass quantity from jetpack ai to product interstitial

* simplify click handler

* add direct checkout for products with usage tiers

* changelog
  • Loading branch information
dhasilva authored Nov 17, 2023
1 parent 5821eca commit b610d62
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Connection: Add optional quantity to product checkout workflow hook
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@ const defaultAdminUrl =
* Custom hook that performs the needed steps
* to concrete the checkout workflow.
*
* @param {object} props - The props passed to the hook.
* @param {string} props.productSlug - The WordPress product slug.
* @param {string} props.redirectUrl - The URI to redirect to after checkout.
* @param {string} [props.siteSuffix] - The site suffix.
* @param {string} [props.adminUrl] - The site wp-admin url.
* @param {boolean} props.connectAfterCheckout - Whether or not to conect after checkout if not connected (default false - connect before).
* @param {object} props - The props passed to the hook.
* @param {string} props.productSlug - The WordPress product slug.
* @param {string} props.redirectUrl - The URI to redirect to after checkout.
* @param {string} [props.siteSuffix] - The site suffix.
* @param {string} [props.adminUrl] - The site wp-admin url.
* @param {boolean} props.connectAfterCheckout - Whether or not to conect after checkout if not connected (default false - connect before).
* @param {Function} props.siteProductAvailabilityHandler - The function used to check whether the site already has the requested product. This will be checked after registration and the checkout page will be skipped if the promise returned resloves true.
* @param {Function} props.from - The plugin slug initiated the flow.
* @returns {Function} - The useEffect hook.
* @param {Function} props.from - The plugin slug initiated the flow.
* @param {number} [props.quantity] - The quantity of the product to purchase.
* @returns {Function} The useEffect hook.
*/
export default function useProductCheckoutWorkflow( {
productSlug,
Expand All @@ -38,6 +39,7 @@ export default function useProductCheckoutWorkflow( {
adminUrl = defaultAdminUrl,
connectAfterCheckout = false,
siteProductAvailabilityHandler = null,
quantity = null,
from,
} = {} ) {
debug( 'productSlug is %s', productSlug );
Expand All @@ -61,7 +63,11 @@ export default function useProductCheckoutWorkflow( {
? 'checkout/jetpack/'
: `checkout/${ siteSuffix }/`;

const productCheckoutUrl = new URL( `${ origin }${ checkoutPath }${ productSlug }` );
const quantitySuffix = quantity != null ? `:-q-${ quantity }` : '';

const productCheckoutUrl = new URL(
`${ origin }${ checkoutPath }${ productSlug }${ quantitySuffix }`
);

if ( shouldConnectAfterCheckout ) {
productCheckoutUrl.searchParams.set( 'connect_after_checkout', true );
Expand All @@ -87,14 +93,15 @@ export default function useProductCheckoutWorkflow( {

return productCheckoutUrl;
}, [
connectAfterCheckout,
isRegistered,
isUserConnected,
connectAfterCheckout,
siteSuffix,
quantity,
productSlug,
adminUrl,
from,
redirectUrl,
isUserConnected,
adminUrl,
] );

debug( 'isRegistered is %s', isRegistered );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ function Price( { value, currency, isOld } ) {
* @param {React.ReactNode} props.supportingInfo - Complementary links or support/legal text
* @param {string} [props.ctaButtonLabel] - The label for the Call To Action button
* @param {boolean} [props.hideTOS] - Whether to hide the Terms of Service text
* @param {number} [props.quantity] - The quantity of the product to purchase
* @returns {object} ProductDetailCard react component.
*/
const ProductDetailCard = ( {
Expand All @@ -78,6 +79,7 @@ const ProductDetailCard = ( {
supportingInfo,
ctaButtonLabel = null,
hideTOS = false,
quantity = null,
} ) => {
const { fileSystemWriteAccess, siteSuffix, adminUrl, myJetpackUrl } =
window?.myJetpackInitialState ?? {};
Expand Down Expand Up @@ -131,6 +133,7 @@ const ProductDetailCard = ( {
adminUrl,
connectAfterCheckout: true,
from: 'my-jetpack',
quantity,
} );

const { run: trialCheckoutRedirect, hasCheckoutStarted: hasTrialCheckoutStarted } =
Expand All @@ -139,6 +142,7 @@ const ProductDetailCard = ( {
redirectUrl: myJetpackUrl,
siteSuffix,
from: 'my-jetpack',
quantity,
} );

// Suppported products icons.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import videoPressImage from './videopress.png';
* @param {string} props.imageContainerClassName - Append a class to the image container
* @param {string} [props.ctaButtonLabel] - The label for the Call To Action button
* @param {boolean} [props.hideTOS] - Whether to hide the Terms of Service text
* @param {number} [props.quantity] - The quantity of the product to purchase
* @param {number} [props.directCheckout] - Whether to go straight to the checkout page, e.g. for products with usage tiers
* @returns {object} ProductInterstitial react component.
*/
export default function ProductInterstitial( {
Expand All @@ -52,6 +54,8 @@ export default function ProductInterstitial( {
imageContainerClassName = '',
ctaButtonLabel = null,
hideTOS = false,
quantity = null,
directCheckout = false,
} ) {
const { activate, detail } = useProduct( slug );
const { isUpgradableByBundle, tiers } = detail;
Expand Down Expand Up @@ -80,15 +84,13 @@ export default function ProductInterstitial( {

const clickHandler = useCallback(
( checkout, product, tier ) => {
const activateOrCheckout = () => ( product?.isBundle ? Promise.resolve() : activate() );

activateOrCheckout().finally( () => {
if ( product?.isBundle ) {
// Get straight to the checkout page.
checkout?.();
return;
}
if ( product?.isBundle || directCheckout ) {
// Get straight to the checkout page.
checkout?.();
return;
}

activate().finally( () => {
const postActivationUrl = product?.postActivationUrl;
const hasRequiredPlan = tier
? product?.hasRequiredTier?.[ tier ]
Expand All @@ -113,7 +115,7 @@ export default function ProductInterstitial( {
checkout?.();
} );
},
[ navigateToMyJetpackOverviewPage, activate ]
[ directCheckout, activate, navigateToMyJetpackOverviewPage ]
);

return (
Expand Down Expand Up @@ -166,6 +168,7 @@ export default function ProductInterstitial( {
preferProductName={ preferProductName }
ctaButtonLabel={ ctaButtonLabel }
hideTOS={ hideTOS }
quantity={ quantity }
/>
</Col>
<Col
Expand All @@ -180,6 +183,7 @@ export default function ProductInterstitial( {
trackButtonClick={ trackBundleClick }
onClick={ clickHandler }
className={ isUpgradableByBundle ? styles.container : null }
quantity={ quantity }
/>
) : (
children
Expand Down Expand Up @@ -273,7 +277,9 @@ export function JetpackAIInterstitial() {
const { onClickGoBack } = useGoBack( { slug } );

const currentTier = detail?.[ 'ai-assistant-feature' ]?.[ 'current-tier' ]?.value;
const hasNextTier = ! [ 1, 500 ].includes( currentTier );
const nextTier = detail?.[ 'ai-assistant-feature' ]?.[ 'next-tier' ]?.value;
const hasNextTier = !! nextTier && ! [ 1, 500 ].includes( currentTier );
const quantity = hasNextTier ? nextTier : null;

if ( ! hasNextTier ) {
return <JetpackAIInterstitialMoreRequests onClickGoBack={ onClickGoBack } />;
Expand All @@ -289,6 +295,8 @@ export function JetpackAIInterstitial() {
imageContainerClassName={ styles.aiImageContainer }
ctaButtonLabel={ ctaLabel }
hideTOS={ true }
quantity={ quantity }
directCheckout={ hasRequiredPlan }
>
<img src={ jetpackAiImage } alt="Jetpack AI" />
</ProductInterstitial>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

My Jetpack: Add direct checkout support for products with quantity-based plans

0 comments on commit b610d62

Please sign in to comment.