Skip to content

Commit

Permalink
My Jetpack: AI detail table feature (#35910)
Browse files Browse the repository at this point in the history
* add AI product page on My Jetpack app

* adapt AI interstitial to handle both scenarios (w/o tiers)

* update AI product class details and manage URL

* update AI product class to conditionally (use filter) return well formed tier data for new pricing table and page

* refine some styles across pricing table and product page

* changelog

* override card case can_upgrade to point to product page (#35915)

* My Jetpack: Jetpack AI product page styles update (#35992)

* update product page styles according to design and fix responsive issues

* fix video rows wrapping

* use proper case for allowFullScreen attribute

* Update video title

Co-authored-by: Douglas Henri <[email protected]>

---------

Co-authored-by: Douglas Henri <[email protected]>

* My Jetpack: Fix Jetpack AI responsive styles (#36036)

* remove deprecated frameborder attribute

* add translation, use admin page with background

* use some media queries to deal with paddings and spacing/gaps

* changelog

* give video side text a min width so it doesn't collapse on strange screen widths

* My Jetpack: AI product page plan/tier information and CTAs (#36035)

* add ai assistant feature data, change basic flows for CTAs and components

* fix unlimited/free logic for contact us button

* changelog

* fix condition to not show upgrade/contact button to unlimited plans

* My Jetpack: add Jetpack AI product page notices (#36090)

* add notices on product page for exhausted free/tier requests

* extract ternaries off the jsx markup

* really remove all ternaries from i18n

* update versions

* My Jetpack: add links on product page (#36079)

* add 'ai' slug on products to run its 'initialization' step. Add 2 filters and script on this initialization

* add actual links on product page

* add changelog entry

* remove debug call

* prepare variables outside markup for defaulted values

* fix wrongly defaulted vars

* restore page visit tracking event

* restore more requests component render

* fix margin-top on AI interstitial (#36206)

* adapt to new react-query store shape

* My Jetpack: fix AI free flow (#36235)

* add class methods to refer to Jetpack plugin

* when the user CAN upgrade, we just call it 'View' as the customer will be taken to the product page

* use default interstitial (ditch the AI extension one)

* show Connect to... instead of create link when Jetpack is disconnected

* force direct checkout false on Jetpack AI interstitial

* add changelog entry

* use a proper varname for the cta URL

* add feedback link redirect (#36251)

* fix some styles overlapping the padding/spacings (#36286)

* My Jetpack: direct straight into AI product page once opted for the free version (#36265)

* add ctaCallback prop on ProductInterstitial, optionally triggered on the products clickHandler

* add ctaCallback on Jetpack AI interstitial

* allow AI card to detect if user has already opted for free version

* changelog entry

* remove unused commented code

* Janitorial: Remove Jetpack AI unused code (#36294)

* remove unused code

* add changelog entry

* update video guids

* fix versions

* remove redundant changelog entries

* allow and handle null value on get_pricing_for_ui_by_usage_tier

* versions fix

* specify WP_Post root class param type

* declare and hard type WP_Post  param

* remove filter, just enable things once it's merged

* versions fix

---------

Co-authored-by: Douglas Henri <[email protected]>
  • Loading branch information
CGastrell and dhasilva authored Mar 19, 2024
1 parent 28d33a2 commit 9a49ead
Show file tree
Hide file tree
Showing 42 changed files with 992 additions and 58 deletions.
3 changes: 3 additions & 0 deletions projects/packages/my-jetpack/_inc/admin.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
VideoPressInterstitial,
StatsInterstitial,
} from './components/product-interstitial';
import JetpackAiProductPage from './components/product-interstitial/jetpack-ai/product-page';
import RedeemTokenScreen from './components/redeem-token-screen';
import { MyJetpackRoutes } from './constants';
import NoticeContextProvider from './context/notices/noticeContext';
Expand Down Expand Up @@ -83,6 +84,8 @@ const MyJetpack = () => {
<Route path={ MyJetpackRoutes.AddLicense } element={ <AddLicenseScreen /> } />
) }
<Route path={ MyJetpackRoutes.RedeemToken } element={ <RedeemTokenScreen /> } />
<Route path="/redeem-token" element={ <RedeemTokenScreen /> } />
<Route path="/jetpack-ai" element={ <JetpackAiProductPage /> } />
</Routes>
</HashRouter>
</QueryClientProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import { useConnection } from '@automattic/jetpack-connection';
import { __ } from '@wordpress/i18n';
import PropTypes from 'prop-types';
import React from 'react';
import { useRef } from 'react';
import ProductCard from '../connected-product-card';
import { PRODUCT_STATUSES } from '../product-card/action-button';

const AiCard = ( { admin } ) => {
return <ProductCard admin={ admin } slug="jetpack-ai" upgradeInInterstitial={ true } />;
const { userConnectionData } = useConnection();
const { currentUser } = userConnectionData;
const { wpcomUser } = currentUser;
const userId = currentUser?.id || 0;
const blogId = currentUser?.blogId || 0;
const wpcomUserId = wpcomUser?.ID || 0;
const userOptKey = `jetpack_ai_optfree_${ userId }_${ blogId }_${ wpcomUserId }`;
const userOptFree = useRef( localStorage.getItem( userOptKey ) );

const userOverrides = {
[ PRODUCT_STATUSES.CAN_UPGRADE ]: {
href: '#/jetpack-ai',
label: __( 'View', 'jetpack-my-jetpack' ),
},
[ PRODUCT_STATUSES.NEEDS_PURCHASE ]: {
href: userOptFree.current ? '#/jetpack-ai' : '#/add-jetpack-ai',
},
};

return (
<ProductCard
admin={ admin }
slug="jetpack-ai"
upgradeInInterstitial={ true }
primaryActionOverride={ userOverrides }
/>
);
};

AiCard.propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import videoPressImage from './videopress.png';
* @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
* @param {boolean} [props.highlightLastFeature] - Whether to highlight the last feature in the list of features
* @param {object} [props.ctaCallback] - Callback when the product CTA is clicked. Triggered before any activation/checkout process occurs
* @returns {object} ProductInterstitial react component.
*/
export default function ProductInterstitial( {
Expand All @@ -61,6 +62,7 @@ export default function ProductInterstitial( {
quantity = null,
directCheckout = false,
highlightLastFeature = false,
ctaCallback = null,
} ) {
const { detail } = useProduct( slug );
const { activate, isPending: isActivating } = useActivate( slug );
Expand Down Expand Up @@ -118,6 +120,8 @@ export default function ProductInterstitial( {
? product?.postCheckoutUrl
: myJetpackCheckoutUri;

ctaCallback?.( { slug, product, tier } );

if ( product?.isBundle || directCheckout ) {
// Get straight to the checkout page.
checkout?.();
Expand Down Expand Up @@ -165,7 +169,14 @@ export default function ProductInterstitial( {
}
);
},
[ directCheckout, activate, navigateToMyJetpackOverviewPage, slug, myJetpackCheckoutUri ]
[
directCheckout,
activate,
navigateToMyJetpackOverviewPage,
slug,
myJetpackCheckoutUri,
ctaCallback,
]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
*/
import { useConnection } from '@automattic/jetpack-connection';
import debugFactory from 'debug';
import { useCallback } from 'react';
/**
* Internal dependencies
*/
import ProductInterstitial from '../';
import useProduct from '../../../data/products/use-product';
import { useGoBack } from '../../../hooks/use-go-back';
import jetpackAiImage from '../jetpack-ai.png';
import { JetpackAIInterstitialMoreRequests } from './more-requests';
import styles from './style.module.scss';

const debug = debugFactory( 'my-jetpack:jetpack-ai-interstitial' );
const debug = debugFactory( 'my-jetpack:product-interstitial:jetpack-ai' );
/**
* JetpackAiInterstitial component
*
Expand All @@ -22,37 +21,31 @@ const debug = debugFactory( 'my-jetpack:jetpack-ai-interstitial' );
export default function JetpackAiInterstitial() {
const slug = 'jetpack-ai';
const { detail } = useProduct( slug );
const { onClickGoBack } = useGoBack( { slug } );
const { isRegistered } = useConnection();
debug( detail );
const nextTier = detail?.aiAssistantFeature?.nextTier || null;

const { hasRequiredPlan } = detail;
const { userConnectionData } = useConnection();
const { currentUser } = userConnectionData;
const { wpcomUser } = currentUser;
const userId = currentUser?.id || 0;
const blogId = currentUser?.blogId || 0;
const wpcomUserId = wpcomUser?.ID || 0;
const userOptKey = `jetpack_ai_optfree_${ userId }_${ blogId }_${ wpcomUserId }`;

// The user has a plan and there is not a next tier
if ( isRegistered && hasRequiredPlan && ! nextTier ) {
debug( 'user is on top tier' );
// TODO: handle this on the pricing table and the product page
return <JetpackAIInterstitialMoreRequests onClickGoBack={ onClickGoBack } />;
}

// Default to 100 requests if the site is not registered/connected.
const nextTierValue = isRegistered ? nextTier?.value : 100;
// Decide the quantity value for the upgrade, but ignore the unlimited tier.
const quantity = nextTierValue !== 1 ? nextTierValue : null;

// Highlight the last feature in the table for all the tiers except the unlimited one.
const highlightLastFeature = nextTier?.value !== 1;
const ctaClickHandler = useCallback(
( { tier } ) => {
tier === 'free' && localStorage.setItem( userOptKey, true );
},
[ userOptKey ]
);

return (
<ProductInterstitial
slug="jetpack-ai"
installsPlugin={ true }
imageContainerClassName={ styles.aiImageContainer }
hideTOS={ true }
quantity={ quantity }
directCheckout={ hasRequiredPlan }
highlightLastFeature={ highlightLastFeature }
directCheckout={ false }
ctaCallback={ ctaClickHandler }
>
<img src={ jetpackAiImage } alt="Search" />
</ProductInterstitial>
Expand Down
Loading

0 comments on commit 9a49ead

Please sign in to comment.