/*
* External dependencies
*/
import getRedirectUrl from '@automattic/jetpack-components/tools/jp-redirect';
import { useAnalytics, canUserPurchasePlan } from '@automattic/jetpack-shared-extension-utils';
import { Nudge as StandardNudge } from '@automattic/jetpack-shared-extension-utils/components';
import { Notice } from '@wordpress/components';
import { createInterpolateElement, useCallback } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import debugFactory from 'debug';
/*
* Internal dependencies
*/
import useAICheckout from '../../hooks/use-ai-checkout/index.ts';
import useAiFeature from '../../hooks/use-ai-feature/index.ts';
import { LightNudge } from './light-nudge.tsx';
import type { ReactElement } from 'react';
import './style.scss';
type QuotaExceededMessageProps = {
placement?: string;
description?: string;
useLightNudge?: boolean;
};
const debug = debugFactory( 'jetpack-ai-client:upgrade-prompt' );
/**
* The fair usage notice message for the AI Assistant block.
* @return {ReactElement} the fair usage notice message, with the proper link and date.
*/
const useFairUsageNoticeMessage = () => {
const { usagePeriod } = useAiFeature();
const getFormattedUsagePeriodStartDate = planUsagePeriod => {
if ( ! planUsagePeriod?.nextStart ) {
return null;
}
const nextUsagePeriodStartDate = new Date( planUsagePeriod.nextStart );
return (
nextUsagePeriodStartDate.toLocaleString( 'default', { month: 'long' } ) +
' ' +
nextUsagePeriodStartDate.getDate()
);
};
const getFairUsageNoticeMessage = resetDateString => {
const fairUsageMessage = __(
"You've reached this month's request limit, per our fair usage policy.",
'jetpack-ai-client'
);
if ( ! resetDateString ) {
return fairUsageMessage;
}
// Translators: %s is the date when the requests will reset.
const dateMessage = __( 'Requests will reset on %s.', 'jetpack-ai-client' );
const formattedDateMessage = sprintf( dateMessage, resetDateString );
return `${ fairUsageMessage } ${ formattedDateMessage }`;
};
const nextUsagePeriodStartDateString = getFormattedUsagePeriodStartDate( usagePeriod );
// Get the proper template based on the presence of the next usage period start date.
const fairUsageNoticeMessage = getFairUsageNoticeMessage( nextUsagePeriodStartDateString );
const fairUsageNoticeMessageElement = createInterpolateElement( fairUsageNoticeMessage, {
link: (
),
span: ,
} );
return fairUsageNoticeMessageElement;
};
/**
* The default upgrade prompt for the AI Assistant block, containing the Upgrade button and linking
* to the checkout page or the Jetpack AI interstitial page.
*
* @param {QuotaExceededMessageProps} props - Component props.
* @return {ReactElement} the Nudge component with the prompt.
*/
const DefaultUpgradePrompt = ( {
placement = null,
description = null,
useLightNudge = false,
}: QuotaExceededMessageProps ): ReactElement => {
const Nudge = useLightNudge ? LightNudge : StandardNudge;
const { checkoutUrl } = useAICheckout();
const canUpgrade = canUserPurchasePlan();
const { nextTier, tierPlansEnabled, currentTier, requestsCount } = useAiFeature();
const { tracks } = useAnalytics();
const handleUpgradeClick = useCallback( () => {
debug( 'upgrade', placement );
tracks.recordEvent( 'jetpack_ai_upgrade_button', {
current_tier_slug: currentTier?.slug,
requests_count: requestsCount,
placement: placement,
} );
}, [ 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(
__(
'Congratulations on exploring Jetpack AI and reaching the free requests limit! Reach out to the site administrator to upgrade and keep using Jetpack AI.',
'jetpack-ai-client'
),
{
strong: ,
}
);
return (
);
}
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-ai-client'
);
return (
);
}
const upgradeDescription = createInterpolateElement(
sprintf(
/* Translators: %d: the number of requests allowed */
__(
'You have reached the requests limit for your current plan. Upgrade now to increase your requests limit to %d.',
'jetpack-ai-client'
),
nextTier.limit
),
{
strong: ,
}
);
return (
);
}
return (
Upgrade now to keep using it.',
'jetpack-ai-client'
),
{
strong: ,
}
) }
goToCheckoutPage={ handleUpgradeClick }
visible={ true }
align={ null }
title={ null }
context={ null }
target="_blank"
/>
);
};
/**
* The VIP upgrade prompt, with a single text message recommending that the user reach
* out to their VIP account team.
*
* @param {object} props - Component props.
* @param {string} props.description - The description to display in the prompt.
* @param {boolean} props.useLightNudge - Wheter to use the light variant of the nudge, or the standard one.
* @return {ReactElement} the Nudge component with the prompt.
*/
const VIPUpgradePrompt = ( {
description = null,
useLightNudge = false,
}: {
description?: string;
useLightNudge?: boolean;
} ): ReactElement => {
const Nudge = useLightNudge ? LightNudge : StandardNudge;
const vipDescription = createInterpolateElement(
__(
"You've reached the Jetpack AI rate limit. Please reach out to your VIP account team.",
'jetpack-ai-client'
),
{
strong: ,
}
);
return (
);
};
type FairUsageNoticeProps = {
variant?: 'error' | 'muted';
};
/**
* The fair usage notice component.
* @param {FairUsageNoticeProps} props - Fair usage notice component props.
* @param {FairUsageNoticeProps.variant} props.variant - The variant of the notice to render.
* @return {ReactElement} the Notice component with the fair usage message.
*/
export const FairUsageNotice = ( { variant = 'error' }: FairUsageNoticeProps ) => {
const useFairUsageNoticeMessageElement = useFairUsageNoticeMessage();
if ( variant === 'muted' ) {
return (
{ useFairUsageNoticeMessageElement }
);
}
if ( variant === 'error' ) {
return (
{ useFairUsageNoticeMessageElement }
);
}
return null;
};
const QuotaExceededMessage = props => {
const { upgradeType, currentTier } = useAiFeature();
// Return notice component for the fair usage limit message, on unlimited plans.
if ( currentTier?.value === 1 ) {
return ;
}
// If the user is on a VIP site, show the VIP upgrade prompt.
if ( upgradeType === 'vip' ) {
return VIPUpgradePrompt( {
description: props.description,
useLightNudge: props?.useLightNudge,
} );
}
return DefaultUpgradePrompt( props );
};
export default QuotaExceededMessage;