From 3d01d4e1f8d37f000fc7f54f969f5fe193a3bd1d Mon Sep 17 00:00:00 2001 From: Louis Laugesen Date: Sat, 7 Dec 2024 05:10:20 +1100 Subject: [PATCH] Stats: add statTypeToPlan to map stat types to plan in stats upsells (#97159) * Add statTypeToPlan to map stat types to plan in stats upsells * Fix statType for non-modal upsell --- client/my-sites/stats/stat-type-to-plan.ts | 30 ++++++++++++++++ .../stats/stats-upsell-modal/index.tsx | 6 ++-- client/my-sites/stats/stats-upsell/index.tsx | 10 +++--- .../stats/stats-upsell/insights-upsell.tsx | 9 ++--- .../stats/stats-upsell/traffic-upsell.tsx | 9 ++--- .../my-sites/stats/test/stat-type-to-plan.ts | 36 +++++++++++++++++++ 6 files changed, 79 insertions(+), 21 deletions(-) create mode 100644 client/my-sites/stats/stat-type-to-plan.ts create mode 100644 client/my-sites/stats/test/stat-type-to-plan.ts diff --git a/client/my-sites/stats/stat-type-to-plan.ts b/client/my-sites/stats/stat-type-to-plan.ts new file mode 100644 index 0000000000000..a1542dd8ef447 --- /dev/null +++ b/client/my-sites/stats/stat-type-to-plan.ts @@ -0,0 +1,30 @@ +import config from '@automattic/calypso-config'; +import { PLAN_PERSONAL, PLAN_PREMIUM } from '@automattic/calypso-products'; +import { + STATS_TYPE_DEVICE_STATS, + STATS_FEATURE_UTM_STATS, + STAT_TYPE_SEARCH_TERMS, + STAT_TYPE_VIDEO_PLAYS, + STAT_TYPE_TOP_AUTHORS, +} from './constants'; + +export function statTypeToPlan( statType: string ) { + if ( ! config.isEnabled( 'stats/paid-wpcom-v3' ) ) { + return PLAN_PREMIUM; + } + + // Commercial stats features that require the premium plan + if ( + [ + STAT_TYPE_TOP_AUTHORS, + STAT_TYPE_SEARCH_TERMS, + STAT_TYPE_VIDEO_PLAYS, + STATS_FEATURE_UTM_STATS, + STATS_TYPE_DEVICE_STATS, + ].includes( statType ) + ) { + return PLAN_PREMIUM; + } + + return PLAN_PERSONAL; +} diff --git a/client/my-sites/stats/stats-upsell-modal/index.tsx b/client/my-sites/stats/stats-upsell-modal/index.tsx index bd9e9a1b404b1..92e8936260520 100644 --- a/client/my-sites/stats/stats-upsell-modal/index.tsx +++ b/client/my-sites/stats/stats-upsell-modal/index.tsx @@ -1,6 +1,5 @@ import { recordTracksEvent } from '@automattic/calypso-analytics'; import { isEnabled } from '@automattic/calypso-config'; -import { PLAN_PERSONAL, PLAN_PREMIUM } from '@automattic/calypso-products'; import page from '@automattic/calypso-router'; import { Gridicon, PlanPrice } from '@automattic/components'; import { Plans } from '@automattic/data-stores'; @@ -16,6 +15,7 @@ import { getSiteOption } from 'calypso/state/sites/selectors'; import { toggleUpsellModal } from 'calypso/state/stats/paid-stats-upsell/actions'; import { getUpsellModalStatType } from 'calypso/state/stats/paid-stats-upsell/selectors'; import { getSelectedSiteId, getSelectedSiteSlug } from 'calypso/state/ui/selectors'; +import { statTypeToPlan } from '../stat-type-to-plan'; import './style.scss'; @@ -25,7 +25,8 @@ export default function StatsUpsellModal( { siteId }: { siteId: number } ) { const selectedSiteId = useSelector( getSelectedSiteId ); const siteSlug = useSelector( getSelectedSiteSlug ); const plans = Plans.usePlans( { coupon: undefined } ); - const planKey = isEnabled( 'stats/paid-wpcom-v3' ) ? PLAN_PERSONAL : PLAN_PREMIUM; + const statType = useSelector( ( state ) => getUpsellModalStatType( state, siteId ) ); + const planKey = statTypeToPlan( statType ); const plan = plans?.data?.[ planKey ]; const pricing = Plans.usePricingMetaForGridPlans( { planSlugs: [ planKey ], @@ -41,7 +42,6 @@ export default function StatsUpsellModal( { siteId }: { siteId: number } ) { const isSimpleClassic = useSelector( ( state ) => getSiteOption( state, selectedSiteId, 'is_wpcom_simple' ) ); - const statType = useSelector( ( state ) => getUpsellModalStatType( state, siteId ) ); const closeModal = () => { dispatch( toggleUpsellModal( siteId, statType ) ); diff --git a/client/my-sites/stats/stats-upsell/index.tsx b/client/my-sites/stats/stats-upsell/index.tsx index 5ff5f2aee3cd0..cfef3333b419a 100644 --- a/client/my-sites/stats/stats-upsell/index.tsx +++ b/client/my-sites/stats/stats-upsell/index.tsx @@ -1,6 +1,5 @@ import { recordTracksEvent } from '@automattic/calypso-analytics'; import { isEnabled } from '@automattic/calypso-config'; -import { PLAN_PERSONAL, PLAN_PREMIUM } from '@automattic/calypso-products'; import page from '@automattic/calypso-router'; import { Gridicon } from '@automattic/components'; import { Plans, HelpCenter } from '@automattic/data-stores'; @@ -13,26 +12,26 @@ import { useTranslate } from 'i18n-calypso'; import TrackComponentView from 'calypso/lib/analytics/track-component-view'; import useCheckPlanAvailabilityForPurchase from 'calypso/my-sites/plans-features-main/hooks/use-check-plan-availability-for-purchase'; import { useSelector } from 'calypso/state'; -import { getUpsellModalStatType } from 'calypso/state/stats/paid-stats-upsell/selectors'; import { getSelectedSiteId, getSelectedSiteSlug } from 'calypso/state/ui/selectors'; +import { statTypeToPlan } from '../stat-type-to-plan'; import './style.scss'; const HELP_CENTER_STORE = HelpCenter.register(); interface Props { - siteId: number; title: string; features: string[]; image: string; + statType: string; } -export default function StatsUpsell( { siteId, title, features, image }: Props ) { +export default function StatsUpsell( { title, features, image, statType }: Props ) { const translate = useTranslate(); const selectedSiteId = useSelector( getSelectedSiteId ); const siteSlug = useSelector( getSelectedSiteSlug ); const plans = Plans.usePlans( { coupon: undefined } ); - const planKey = isEnabled( 'stats/paid-wpcom-v3' ) ? PLAN_PERSONAL : PLAN_PREMIUM; + const planKey = statTypeToPlan( statType ); const plan = plans?.data?.[ planKey ]; const pricing = Plans.usePricingMetaForGridPlans( { planSlugs: [ planKey ], @@ -45,7 +44,6 @@ export default function StatsUpsell( { siteId, title, features, image }: Props ) const isLoading = plans.isLoading || ! pricing; const isOdysseyStats = isEnabled( 'is_running_in_jetpack_site' ); const eventPrefix = isOdysseyStats ? 'jetpack_odyssey' : 'calypso'; - const statType = useSelector( ( state ) => getUpsellModalStatType( state, siteId ) ); const { setShowHelpCenter, setShowSupportDoc } = useDataStoreDispatch( HELP_CENTER_STORE ); const localizeUrl = useLocalizeUrl(); diff --git a/client/my-sites/stats/stats-upsell/insights-upsell.tsx b/client/my-sites/stats/stats-upsell/insights-upsell.tsx index 7387db4b21c2c..bd6a9824263bc 100644 --- a/client/my-sites/stats/stats-upsell/insights-upsell.tsx +++ b/client/my-sites/stats/stats-upsell/insights-upsell.tsx @@ -1,17 +1,14 @@ import { useTranslate } from 'i18n-calypso'; import statsFeaturesPNG from 'calypso/assets/images/stats/paid-features-2.png'; +import { STATS_FEATURE_PAGE_INSIGHTS } from '../constants'; import StatsUpsell from './index'; -interface Props { - siteId: number; -} - -const InsightsUpsell: React.FC< Props > = ( { siteId } ) => { +const InsightsUpsell: React.FC = () => { const translate = useTranslate(); return ( = ( { siteId } ) => { +const TrafficUpsell: React.FC = () => { const translate = useTranslate(); return ( { + const config = () => 'development'; + config.isEnabled = jest.fn(); + return config; +} ); + +describe( 'statTypeToPlan', () => { + it( 'should always return premium when stats/paid-wpcom-v3 is not enabled', () => { + ( config.isEnabled as jest.Mock ).mockImplementation( () => false ); + // Search terms is a commercial stats feature that requires the premium plan + expect( statTypeToPlan( STAT_TYPE_SEARCH_TERMS ) ).toEqual( PLAN_PREMIUM ); + // Clicks is a paid stats feature that requires the personal plan, test the fallback on premium anyway when v3 is disabled. + expect( statTypeToPlan( STAT_TYPE_CLICKS ) ).toEqual( PLAN_PREMIUM ); + // 7 Days is a free plan feature, this should not be gated but test we default to premium when the stat type doesn't make sense to query + expect( statTypeToPlan( STATS_FEATURE_DATE_CONTROL_LAST_7_DAYS ) ).toEqual( PLAN_PREMIUM ); + } ); + + it( 'should return personal when stats/paid-wpcom-v3 is enabled and the stat type is a personal plan feature', () => { + ( config.isEnabled as jest.Mock ).mockImplementation( () => true ); + // Search terms is a commercial stats feature that requires the premium plan + expect( statTypeToPlan( STAT_TYPE_SEARCH_TERMS ) ).toEqual( PLAN_PREMIUM ); + // Clicks is a paid stats feature that requires the personal plan + expect( statTypeToPlan( STAT_TYPE_CLICKS ) ).toEqual( PLAN_PERSONAL ); + // 7 Days is a free plan feature, this should not be gated but test we default to personal when the stat type doesn't make sense to query + expect( statTypeToPlan( STATS_FEATURE_DATE_CONTROL_LAST_7_DAYS ) ).toEqual( PLAN_PERSONAL ); + } ); +} );