Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Fix jetpack ai unlimited tier props #39277

Draft
wants to merge 5 commits into
base: trunk
Choose a base branch
from
Draft
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
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Change unlimited tier plan props to reflect the fair usage limit
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { useState, useEffect, useCallback, useRef } from 'react';
* Internal dependencies
*/
import {
DEFAULT_LOGO_COST,
EVENT_MODAL_OPEN,
EVENT_FEEDBACK,
EVENT_MODAL_CLOSE,
Expand Down Expand Up @@ -117,8 +116,6 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {

const hasHistory = ! isLogoHistoryEmpty( String( siteId ) );

const logoCost = feature?.costs?.[ 'jetpack-ai-logo-generator' ]?.logo ?? DEFAULT_LOGO_COST;
const promptCreationCost = 1;
const currentLimit = feature?.currentTier?.limit || 0;
const currentValue = feature?.currentTier?.value || 0;
const currentUsage = feature?.usagePeriod?.requestsCount || 0;
Expand All @@ -127,12 +124,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {

// The user needs an upgrade immediately if they have no logos and not enough requests remaining for one prompt and one logo generation.
const siteNeedsMoreRequests =
! isUnlimited &&
! hasNoNextTier &&
! hasHistory &&
( tierPlansEnabled
? currentLimit - currentUsage < logoCost + promptCreationCost
: currentLimit < currentUsage );
! isUnlimited && ! hasNoNextTier && ! hasHistory && currentLimit < currentUsage;

// If the site requires an upgrade, show the upgrade screen immediately.
setNeedsFeature( currentValue === 0 );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import { useCheckout } from '../hooks/use-checkout.js';
import useLogoGenerator from '../hooks/use-logo-generator.js';
import useRequestErrors from '../hooks/use-request-errors.js';
import { FairUsageNotice } from './fair-usage-notice.js';
import { UpgradeNudge } from './upgrade-nudge.js';
import './prompt.scss';
/**
* Types
Expand Down Expand Up @@ -59,7 +58,6 @@ export const Prompt = ( { initialPrompt = '' }: PromptProps ) => {
getAiAssistantFeature,
requireUpgrade,
context,
tierPlansEnabled,
imageStyles,
guessStyle,
} = useLogoGenerator();
Expand Down Expand Up @@ -273,8 +271,7 @@ export const Prompt = ( { initialPrompt = '' }: PromptProps ) => {
</Tooltip>
</div>
) }
{ requireUpgrade && tierPlansEnabled && <UpgradeNudge /> }
{ requireUpgrade && ! tierPlansEnabled && <FairUsageNotice /> }
{ requireUpgrade && <FairUsageNotice /> }
{ enhancePromptFetchError && (
<div className="jetpack-ai-logo-generator__prompt-error">
{ __( 'Error enhancing prompt. Please try again.', 'jetpack-ai-client' ) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ import { STORE_NAME } from '../store/index.js';
import type { Selectors } from '../store/types.js';

export const useCheckout = () => {
const { nextTier, tierPlansEnabled } = useSelect( select => {
const { nextTier } = useSelect( select => {
const selectors: Selectors = select( STORE_NAME );
return {
nextTier: selectors.getAiAssistantFeature().nextTier,
tierPlansEnabled: selectors.getAiAssistantFeature().tierPlansEnabled,
};
}, [] );

Expand All @@ -42,10 +41,7 @@ export const useCheckout = () => {
const checkoutUrl = new URL( `https://jetpack.com/redirect/` );
checkoutUrl.searchParams.set( 'source', redirectSource );
checkoutUrl.searchParams.set( 'site', siteFragment );
checkoutUrl.searchParams.set(
'path',
tierPlansEnabled ? `jetpack_ai_yearly:-q-${ nextTier?.limit }` : 'jetpack_ai_yearly'
);
checkoutUrl.searchParams.set( 'path', 'jetpack_ai_yearly' );

// For Jetpack sites, the redirect_to parameter is handled by the Jetpack redirect source
if ( ! isJetpackSite ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export function mapAiFeatureResponseToAiFeatureProps(
response: AiAssistantFeatureEndpointResponseProps
): AiFeatureProps {
return {
hasFeature: !! response[ 'has-feature' ],
isOverLimit: !! response[ 'is-over-limit' ],
requestsCount: response[ 'requests-count' ],
requestsLimit: response[ 'requests-limit' ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const INITIAL_STATE: LogoGeneratorStateProp = {
siteDetails: {},
features: {
aiAssistantFeature: {
hasFeature: true,
isOverLimit: false,
requestsCount: 0,
requestsLimit: FREE_PLAN_REQUESTS_LIMIT,
Expand Down
29 changes: 6 additions & 23 deletions projects/js-packages/ai-client/src/logo-generator/store/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
ACTION_STORE_AI_ASSISTANT_FEATURE,
ASYNC_REQUEST_COUNTDOWN_INIT_VALUE,
FREE_PLAN_REQUESTS_LIMIT,
UNLIMITED_PLAN_REQUESTS_LIMIT,
ACTION_SET_TIER_PLANS_ENABLED,
ACTION_SET_SITE_DETAILS,
ACTION_SET_SELECTED_LOGO_INDEX,
Expand Down Expand Up @@ -149,30 +148,15 @@ export default function reducer(
// Current tier value
const currentTierValue = state?.features?.aiAssistantFeature?.currentTier?.value;

const isFreeTierPlan =
( typeof currentTierValue === 'undefined' &&
! state?.features?.aiAssistantFeature?.hasFeature ) ||
currentTierValue === 0;

const isUnlimitedTierPlan =
( typeof currentTierValue === 'undefined' &&
state?.features?.aiAssistantFeature?.hasFeature ) ||
currentTierValue === 1;
const isFreeTierPlan = currentTierValue === 0;

// Request limit defined with the current tier limit by default.
let requestsLimit: TierLimitProp =
const requestsLimit: TierLimitProp =
state?.features?.aiAssistantFeature?.currentTier?.limit || FREE_PLAN_REQUESTS_LIMIT;

if ( isUnlimitedTierPlan ) {
requestsLimit = UNLIMITED_PLAN_REQUESTS_LIMIT;
} else if ( isFreeTierPlan ) {
requestsLimit = state?.features?.aiAssistantFeature?.requestsLimit as TierLimitProp;
}

const currentCount =
isUnlimitedTierPlan || isFreeTierPlan // @todo: update once tier data is available
? requestsCount
: state?.features?.aiAssistantFeature?.usagePeriod?.requestsCount || 0;
const currentCount = isFreeTierPlan
? requestsCount
: state?.features?.aiAssistantFeature?.usagePeriod?.requestsCount || 0;

/**
* Compute the AI Assistant Feature data optimistically,
Expand All @@ -182,8 +166,7 @@ export default function reducer(
const isOverLimit = currentCount >= requestsLimit;

// highest tier holds a soft limit so requireUpgrade is false on that case (nextTier null means highest tier)
const requireUpgrade =
isFreeTierPlan || ( isOverLimit && state?.features?.aiAssistantFeature?.nextTier !== null );
const requireUpgrade = isOverLimit;

return {
...state,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* Types
*/
import { DEFAULT_LOGO_COST } from '../constants.js';
import type { AiFeatureProps, LogoGeneratorStateProp, Logo, RequestError } from './types.js';
import type { SiteDetails } from '../types.js';

Expand Down Expand Up @@ -120,22 +119,7 @@ const selectors = {
* @return {boolean} The requireUpgrade flag.
*/
getRequireUpgrade( state: LogoGeneratorStateProp ): boolean {
const feature = state.features.aiAssistantFeature;

if ( ! feature?.tierPlansEnabled ) {
return feature?.requireUpgrade;
}
const logoCost = feature?.costs?.[ 'jetpack-ai-logo-generator' ]?.logo ?? DEFAULT_LOGO_COST;
const currentLimit = feature?.currentTier?.value || 0;
const currentUsage = feature?.usagePeriod?.requestsCount || 0;
const isUnlimited = currentLimit === 1;
const hasNoNextTier = ! feature?.nextTier; // If there is no next tier, the user cannot upgrade.

// Add a local check on top of the feature flag, based on the current usage and logo cost.
return (
state.features.aiAssistantFeature?.requireUpgrade ||
( ! isUnlimited && ! hasNoNextTier && currentLimit - currentUsage < logoCost )
);
return state.features?.aiAssistantFeature?.requireUpgrade || false;
},

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ export type FeaturesControl = {
};

export type AiFeatureProps = {
hasFeature: boolean;
isOverLimit: boolean;
requestsCount: number;
requestsLimit: number;
Expand Down Expand Up @@ -196,7 +195,6 @@ export type Selectors = {
*/
export type AiAssistantFeatureEndpointResponseProps = {
'is-enabled': boolean;
'has-feature': boolean;
'is-over-limit': boolean;
'requests-count': number;
'requests-limit': number;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Forms: take hasAI value from Jetpack connected status
8 changes: 5 additions & 3 deletions projects/packages/forms/src/dashboard/class-dashboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@ public function render_dashboard() {
require_once JETPACK__PLUGIN_DIR . '_inc/lib/class-jetpack-ai-helper.php';
}

$ai_feature = \Jetpack_AI_Helper::get_ai_assistance_feature();
$has_ai = ! is_wp_error( $ai_feature ) ? $ai_feature['has-feature'] : false;
$ai_feature = \Jetpack_AI_Helper::get_ai_assistance_feature();
$require_upgrade = ! is_wp_error( $ai_feature ) && isset( $ai_feature['site-require-upgrade'] )
? $ai_feature['site-require-upgrade']
: false;

$jetpack_connected = ( defined( 'IS_WPCOM' ) && IS_WPCOM ) || ( new Connection_Manager( 'jetpack-forms' ) )->is_user_connected( get_current_user_id() );
$user_id = (int) get_current_user_id();
Expand All @@ -167,7 +169,7 @@ public function render_dashboard() {
'pluginAssetsURL' => Jetpack_Forms::assets_url(),
'siteURL' => ( new Status() )->get_site_suffix(),
'hasFeedback' => $this->has_feedback(),
'hasAI' => $has_ai,
'hasAI' => ! $require_upgrade,
);
?>
<div id="jp-forms-dashboard" style="min-height: calc(100vh - 100px);" data-config="<?php echo esc_attr( wp_json_encode( $config, JSON_FORCE_OBJECT ) ); ?>"></div>
Expand Down
28 changes: 28 additions & 0 deletions projects/plugins/jetpack/_inc/lib/class-jetpack-ai-helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,11 @@ public static function get_ai_assistance_feature() {
return $cache;
}

if ( ! apply_filters( 'jetpack_ai_enabled', true ) ) {
// if user has disabled AI, don't waste request/computing cycles and return default payload.
return self::get_default_feature_payload();
}

if ( null !== static::$ai_assistant_failed_request ) {
return static::$ai_assistant_failed_request;
}
Expand Down Expand Up @@ -453,4 +458,27 @@ public static function get_ai_assistance_feature() {
return $error;
}
}

/**
* Get the default feature payload for when the feature is NOT available for a site.
* This is a default response for consistency.
*/
private static function get_default_feature_payload() {
return array(
'has-feature' => false,
'is-over-limit' => false,
'requests-count' => 0,
'requests-limit' => 20,
'usage-period' => array(),
'site-require-upgrade' => false,
'upgrade-type' => 'default',
'upgrade-url' => '',
'current-tier' => null,
'next-tier' => null,
'tier-plans' => array(),
'tier-plans-enabled' => false,
'costs' => array(),
'features-control' => array(),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: other

Change unlimited tier plan props to reflect the fair usage limit
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/*
* External dependencies
*/
import { getRedirectUrl } from '@automattic/jetpack-components';
import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
import { Notice } from '@wordpress/components';
import { createInterpolateElement, useCallback } from '@wordpress/element';
Expand Down Expand Up @@ -97,7 +96,7 @@ const DefaultUpgradePrompt = ( {

const { checkoutUrl } = useAICheckout();
const canUpgrade = canUserPurchasePlan();
const { nextTier, tierPlansEnabled, currentTier, requestsCount } = useAiFeature();
const { currentTier, requestsCount } = useAiFeature();

const { tracks } = useAnalytics();

Expand All @@ -110,13 +109,6 @@ const DefaultUpgradePrompt = ( {
} );
}, [ currentTier, requestsCount, tracks, placement ] );

const handleContactUsClick = useCallback( () => {
debug( 'contact us', placement );
tracks.recordEvent( 'jetpack_ai_upgrade_contact_us', {
placement: placement,
} );
}, [ tracks, placement ] );

if ( ! canUpgrade ) {
const cantUpgradeDescription = createInterpolateElement(
__(
Expand All @@ -141,64 +133,6 @@ const DefaultUpgradePrompt = ( {
);
}

if ( tierPlansEnabled ) {
if ( ! nextTier ) {
const contactHref = getRedirectUrl( 'jetpack-ai-tiers-more-requests-contact' );
const contactUsDescription = __(
'You have reached the request limit for your current plan.',
'jetpack'
);

return (
<Nudge
buttonText={ __( 'Contact Us', 'jetpack' ) }
description={ description || contactUsDescription }
className={ 'jetpack-ai-upgrade-banner' }
checkoutUrl={ contactHref }
visible={ true }
align={ null }
title={ null }
context={ null }
goToCheckoutPage={ handleContactUsClick }
target="_blank"
/>
);
}

const upgradeDescription = createInterpolateElement(
sprintf(
/* Translators: number of requests */
__(
'You have reached the requests limit for your current plan. <strong>Upgrade now to increase your requests limit to %d.</strong>',
'jetpack'
),
nextTier.limit
),
{
strong: <strong />,
}
);

return (
<Nudge
buttonText={ sprintf(
/* Translators: number of requests */
__( 'Upgrade to %d requests', 'jetpack' ),
nextTier.limit
) }
checkoutUrl={ checkoutUrl }
className={ 'jetpack-ai-upgrade-banner' }
description={ description || upgradeDescription }
goToCheckoutPage={ handleUpgradeClick }
visible={ true }
align={ 'center' }
title={ null }
context={ null }
target="_blank"
/>
);
}

return (
<Nudge
buttonText={ 'Upgrade' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export default function AIAssistantEdit( { attributes, setAttributes, clientId,
requestsLimit,
currentTier,
loading: loadingAiFeature,
tierPlansEnabled,
} = useAiFeature();
const requestsRemaining = Math.max( requestsLimit - requestsCount, 0 );

Expand Down Expand Up @@ -370,8 +369,7 @@ export default function AIAssistantEdit( { attributes, setAttributes, clientId,
{ __( 'Discover all features', 'jetpack' ) }
</ExternalLink>
</div>
{ ( planType === PLAN_TYPE_FREE ||
( tierPlansEnabled && planType !== PLAN_TYPE_UNLIMITED ) ) && (
{ planType === PLAN_TYPE_FREE && (
<PanelBody initialOpen={ true }>
<PanelRow>
<UsagePanel placement={ USAGE_PANEL_PLACEMENT_BLOCK_SETTINGS_SIDEBAR } />
Expand Down
Loading
Loading