Skip to content

Commit

Permalink
Global Styles on Personal AB: Calypso changes (#98538)
Browse files Browse the repository at this point in the history
* Calypso is now aware of the GS on Personal AB experiment code and reacts accordingly

* Removed pre intitialization requirement

* Fixed test

* Fixed tests

* Fixed the global isGlobalStylesOnPersonal check so that it does not trigger an error in some circumstances

* On the Design Picker, we now use the global isGlobalStylesOnPersonal global as default value to avoid prop drilling into the package.

* Added window interface to comply with TS

* Updated comment to better describe the functionality

* Add the global styles experiment status to the window object by using useEffect

* Simplified the withSiteGlobalStylesOnPersonal hoc

* Removed an unused import

* We now support the LiTS with no site selected as part of the experiment

* Added final experiment key
  • Loading branch information
rcrdortiz authored Jan 28, 2025
1 parent 09df749 commit 14761a3
Show file tree
Hide file tree
Showing 20 changed files with 208 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { isEnabled } from '@automattic/calypso-config';
import { PLAN_PERSONAL, PLAN_PREMIUM } from '@automattic/calypso-products';
import { Button, Gridicon, Dialog, ScreenReaderText, PlanPrice } from '@automattic/components';
import { Plans } from '@automattic/data-stores';
Expand All @@ -10,6 +9,7 @@ import { LoadingEllipsis } from 'calypso/components/loading-ellipsis';
import useCheckPlanAvailabilityForPurchase from 'calypso/my-sites/plans-features-main/hooks/use-check-plan-availability-for-purchase';
import { useSelector } from 'calypso/state';
import { getProductBySlug } from 'calypso/state/products-list/selectors';
import { useSiteGlobalStylesOnPersonal } from 'calypso/state/sites/hooks/use-site-global-styles-on-personal';
import { getSelectedSiteId } from 'calypso/state/ui/selectors';
import useGlobalStylesUpgradeTranslations from './use-global-styles-upgrade-translations';
import './style.scss';
Expand All @@ -34,9 +34,7 @@ export default function PremiumGlobalStylesUpgradeModal( {
}: PremiumGlobalStylesUpgradeModalProps ) {
const translate = useTranslate();
// @TODO Cleanup once the test phase is over.
const upgradeToPlan = isEnabled( 'global-styles/on-personal-plan' )
? PLAN_PERSONAL
: PLAN_PREMIUM;
const upgradeToPlan = useSiteGlobalStylesOnPersonal() ? PLAN_PERSONAL : PLAN_PREMIUM;
const premiumPlanProduct = useSelector( ( state ) => getProductBySlug( state, upgradeToPlan ) );
const selectedSiteId = useSelector( getSelectedSiteId );
const translations = useGlobalStylesUpgradeTranslations( { numOfSelectedGlobalStyles } );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { isEnabled } from '@automattic/calypso-config';
import { PLAN_PERSONAL, PLAN_PREMIUM } from '@automattic/calypso-products';
import { Plans } from '@automattic/data-stores';
import { useHasEnTranslation } from '@automattic/i18n-utils';
import { useTranslate } from 'i18n-calypso';
import { useSiteGlobalStylesOnPersonal } from 'calypso/state/sites/hooks/use-site-global-styles-on-personal';

interface Props {
numOfSelectedGlobalStyles?: number;
Expand All @@ -14,9 +14,7 @@ const useGlobalStylesUpgradeTranslations = ( { numOfSelectedGlobalStyles = 1 }:
const plans = Plans.usePlans( { coupon: undefined } );

// @TODO Cleanup once the test phase is over.
const upgradeToPlan = isEnabled( 'global-styles/on-personal-plan' )
? PLAN_PERSONAL
: PLAN_PREMIUM;
const upgradeToPlan = useSiteGlobalStylesOnPersonal() ? PLAN_PERSONAL : PLAN_PREMIUM;

const planTitle = plans?.data?.[ upgradeToPlan ]?.productNameShort ?? '';

Expand All @@ -43,7 +41,7 @@ const useGlobalStylesUpgradeTranslations = ( { numOfSelectedGlobalStyles = 1 }:
featuresTitle: translate( 'Included with your %(planTitle)s plan', {
args: { planTitle },
} ),
features: isEnabled( 'global-styles/on-personal-plan' ) ? personalFeatures : premiumFeatures,
features: useSiteGlobalStylesOnPersonal() ? personalFeatures : premiumFeatures,
description: translate(
'You’ve selected a premium style that will only be visible to visitors after upgrading to the %(planTitle)s plan or higher.',
'You’ve selected premium styles that will only be visible to visitors after upgrading to the %(planTitle)s plan or higher.',
Expand Down
1 change: 1 addition & 0 deletions client/components/theme-tier/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const getIncludedWithLabel = ( planSlug ) => {

export const THEME_TIER_PREMIUM = 'premium';
export const THEME_TIER_PARTNER = 'partner';
export const THEME_TIER_FREE = 'free';

/**
* @typedef {Object} THEME_TIERS
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/** @jest-environment jsdom */
import { getPlan } from '@automattic/calypso-products';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useSelector } from 'calypso/state';
Expand All @@ -12,6 +13,23 @@ describe( 'ThemeTierStyleVariationBadge', () => {
const siteSlug = 'example.wordpress.com';
let originalWindowLocation;

// Create a QueryClient instance
const createTestQueryClient = () =>
new QueryClient( {
defaultOptions: {
queries: {
retry: false, // Disable retries for tests
cacheTime: 0, // Disable cache
},
},
} );

// Utility to wrap component with QueryClientProvider
const renderWithQueryClient = ( ui ) => {
const queryClient = createTestQueryClient();
return render( <QueryClientProvider client={ queryClient }>{ ui }</QueryClientProvider> );
};

beforeEach( () => {
jest.clearAllMocks();

Expand All @@ -30,7 +48,7 @@ describe( 'ThemeTierStyleVariationBadge', () => {
} );

test( 'should render upgrade label', () => {
render( <ThemeTierStyleVariationBadge /> );
renderWithQueryClient( <ThemeTierStyleVariationBadge /> );

const upgradeLabel = screen.getByText( 'Upgrade' );
expect( upgradeLabel ).toBeInTheDocument();
Expand All @@ -44,7 +62,7 @@ describe( 'ThemeTierStyleVariationBadge', () => {
getPathSlug: () => pathSlug,
} ) );

render( <ThemeTierStyleVariationBadge /> );
renderWithQueryClient( <ThemeTierStyleVariationBadge /> );

userEvent.hover( screen.getByText( 'Upgrade' ) );

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { isEnabled } from '@automattic/calypso-config';
import { PLAN_PREMIUM, getPlan, PLAN_PERSONAL } from '@automattic/calypso-products';
import { PremiumBadge } from '@automattic/components';
import { createInterpolateElement } from '@wordpress/element';
import { useTranslate } from 'i18n-calypso';
import { useSiteGlobalStylesOnPersonal } from 'calypso/state/sites/hooks/use-site-global-styles-on-personal';
import ThemeTierBadgeCheckoutLink from './theme-tier-badge-checkout-link';
import ThemeTierTooltipTracker from './theme-tier-tooltip-tracker';

export default function ThemeTierStyleVariationBadge() {
const translate = useTranslate();

// @TODO Cleanup once the test phase is over.
const upgradeToPlan = isEnabled( 'global-styles/on-personal-plan' )
const upgradeToPlan = useSiteGlobalStylesOnPersonal()
? getPlan( PLAN_PERSONAL )
: getPlan( PLAN_PREMIUM );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { recordTracksEvent } from 'calypso/state/analytics/actions';
import { infoNotice } from 'calypso/state/notices/actions';
import useProductsQuery from 'calypso/state/partner-portal/licenses/hooks/use-products-query';
import { doesPartnerRequireAPaymentMethod } from 'calypso/state/partner-portal/partner/selectors';
import { useSiteGlobalStylesOnPersonal } from 'calypso/state/sites/hooks/use-site-global-styles-on-personal';
import FeatureItem from './feature-item';
import './style.scss';

Expand Down Expand Up @@ -48,6 +49,9 @@ export default function CardContent( {
const { data: agencyProducts } = useProductsQuery();
const paymentMethodRequired = useSelector( doesPartnerRequireAPaymentMethod );

// Set a prop on the window object on whether Global Styles is available on the Personal plan.
useSiteGlobalStylesOnPersonal();

const getLogo = ( planSlug: string ) => {
switch ( planSlug ) {
case PLAN_BUSINESS:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ const renderComponent = ( component, initialState = {} ) => {
const store = mockStore( {
purchases: {},
sites: {},
ui: { selectedSiteId: 'anySiteId' },
...initialState,
} );

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { isEnabled } from '@automattic/calypso-config';
import {
TERM_ANNUALLY,
TERM_MONTHLY,
Expand Down Expand Up @@ -41,6 +40,7 @@ import {
THEME_TIERS,
THEME_TIER_PARTNER,
THEME_TIER_PREMIUM,
THEME_TIER_FREE,
} from 'calypso/components/theme-tier/constants';
import ThemeTierBadge from 'calypso/components/theme-tier/theme-tier-badge';
import { ThemeUpgradeModal as UpgradeModal } from 'calypso/components/theme-upgrade-modal';
Expand All @@ -57,6 +57,7 @@ import {
getProductsByBillingSlug,
} from 'calypso/state/products-list/selectors';
import { hasPurchasedDomain } from 'calypso/state/purchases/selectors/has-purchased-domain';
import { useSiteGlobalStylesOnPersonal } from 'calypso/state/sites/hooks/use-site-global-styles-on-personal';
import { useSiteGlobalStylesStatus } from 'calypso/state/sites/hooks/use-site-global-styles-status';
import { getSiteSlug } from 'calypso/state/sites/selectors';
import { setActiveTheme, activateOrInstallThenActivate } from 'calypso/state/themes/actions';
Expand Down Expand Up @@ -144,6 +145,8 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow, stepName } ) => {
const siteDescription = site?.description;
const { shouldLimitGlobalStyles } = useSiteGlobalStylesStatus( site?.ID );
const { data: siteActiveTheme } = useActiveThemeQuery( site?.ID ?? 0, !! site?.ID );
// @TODO Cleanup once the test phase is over.
const isGlobalStylesOnPersonal = useSiteGlobalStylesOnPersonal( site?.ID );

const isDesignFirstFlow =
flow === DESIGN_FIRST_FLOW || queryParams.get( 'flowToReturnTo' ) === DESIGN_FIRST_FLOW;
Expand Down Expand Up @@ -581,16 +584,13 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow, stepName } ) => {
} )
);

// @TODO Cleanup once the test phase is over.
const upgradeToPlan = isEnabled( 'global-styles/on-personal-plan' ) ? 'personal' : 'premium';

goToCheckout( {
flowName: flow,
stepName,
siteSlug: siteSlug || urlToSlug( site?.URL || '' ) || '',
// When the user is done with checkout, send them back to the current url
destination: window.location.href.replace( window.location.origin, '' ),
plan: upgradeToPlan,
plan: isGlobalStylesOnPersonal ? 'personal' : 'premium',
} );

setShowPremiumGlobalStylesModal( false );
Expand Down Expand Up @@ -736,7 +736,7 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow, stepName } ) => {
} );
}
function getPrimaryActionButtonAction(): () => void {
if ( isEnabled( 'global-styles/on-personal-plan' ) ) {
if ( isGlobalStylesOnPersonal ) {
if ( isLockedTheme ) {
return upgradePlan;
}
Expand Down Expand Up @@ -841,12 +841,16 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow, stepName } ) => {
placeholder={ null }
previewUrl={ previewUrl }
splitDefaultVariation={
! ( selectedDesign?.design_tier === THEME_TIER_PREMIUM ) &&
! isBundled &&
! isPremiumThemeAvailable &&
! didPurchaseSelectedTheme &&
! isPluginBundleEligible &&
shouldLimitGlobalStyles
( isGlobalStylesOnPersonal &&
selectedDesign?.design_tier === THEME_TIER_FREE &&
shouldLimitGlobalStyles ) ||
( ! ( selectedDesign?.design_tier === THEME_TIER_PREMIUM ) &&
! isBundled &&
! isPremiumThemeAvailable &&
! didPurchaseSelectedTheme &&
! isPluginBundleEligible &&
! isGlobalStylesOnPersonal &&
shouldLimitGlobalStyles )
}
needsUpgrade={ shouldLimitGlobalStyles || isLockedTheme }
title={ headerDesignTitle }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PLAN_PREMIUM } from '@automattic/calypso-products';
import { PLAN_PERSONAL, PLAN_PREMIUM } from '@automattic/calypso-products';
import { Badge, CircularProgressBar, Gridicon, Tooltip } from '@automattic/components';
import {
OnboardSelect,
Expand All @@ -25,6 +25,7 @@ import { TYPE_TIER } from 'calypso/my-sites/earn/memberships/constants';
import { useSelector } from 'calypso/state';
import { isCurrentUserEmailVerified } from 'calypso/state/current-user/selectors';
import { getConnectUrlForSiteId } from 'calypso/state/memberships/settings/selectors';
import { useSiteGlobalStylesOnPersonal } from 'calypso/state/sites/hooks/use-site-global-styles-on-personal';
import { useSiteGlobalStylesStatus } from 'calypso/state/sites/hooks/use-site-global-styles-status';
import { getEnhancedTasks } from './task-definitions';
import { getLaunchpadTranslations } from './translations';
Expand Down Expand Up @@ -107,6 +108,9 @@ const Sidebar = ( {
);

const displayGlobalStylesWarning = globalStylesInUse && shouldLimitGlobalStyles;
const globalStylesMinimumPlan = useSiteGlobalStylesOnPersonal( site?.ID )
? PLAN_PERSONAL
: PLAN_PREMIUM;

let checklist = launchpadChecklist;
if ( selectedDesign?.default ) {
Expand All @@ -129,7 +133,7 @@ const Sidebar = ( {
site,
submit,
displayGlobalStylesWarning,
globalStylesMinimumPlan: PLAN_PREMIUM,
globalStylesMinimumPlan,
setShowPlansModal,
queryClient,
goToStep,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import { isEnabled } from '@automattic/calypso-config';
import {
FEATURE_STYLE_CUSTOMIZATION,
isFreePlanProduct,
PLAN_PERSONAL,
} from '@automattic/calypso-products';
import { FEATURE_STYLE_CUSTOMIZATION, isFreePlanProduct } from '@automattic/calypso-products';
import { updateLaunchpadSettings } from '@automattic/data-stores/src/queries/use-launchpad';
import { localizeUrl } from '@automattic/i18n-utils';
import { Task } from '@automattic/launchpad';
Expand Down Expand Up @@ -54,13 +49,6 @@ export const getPlanSelectedTask: TaskAction = ( task, flow, context ): Task =>
const { siteSlug, displayGlobalStylesWarning, globalStylesMinimumPlan, hasSkippedCheckout } =
context;

// @TODO Cleanup once the test phase is over.
const upgradeToPlan = isEnabled( 'global-styles/on-personal-plan' )
? PLAN_PERSONAL
: globalStylesMinimumPlan;

const shouldDisplayWarning = displayGlobalStylesWarning;

return {
...task,
actionDispatch: () => {
Expand All @@ -71,8 +59,8 @@ export const getPlanSelectedTask: TaskAction = ( task, flow, context ): Task =>
}
},
calypso_path: addQueryArgs( `/plans/${ siteSlug }`, {
...( shouldDisplayWarning && {
plan: upgradeToPlan,
...( displayGlobalStylesWarning && {
plan: globalStylesMinimumPlan,
feature: FEATURE_STYLE_CUSTOMIZATION,
} ),
} ),
Expand Down
19 changes: 11 additions & 8 deletions client/my-sites/theme/main.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getTracksAnonymousUserId } from '@automattic/calypso-analytics';
import config, { isEnabled } from '@automattic/calypso-config';
import config from '@automattic/calypso-config';
import {
FEATURE_UPLOAD_THEMES,
PLAN_BUSINESS,
Expand Down Expand Up @@ -66,6 +66,7 @@ import isSiteWPForTeams from 'calypso/state/selectors/is-site-wpforteams';
import isVipSite from 'calypso/state/selectors/is-vip-site';
import siteHasFeature from 'calypso/state/selectors/site-has-feature';
import { useSiteGlobalStylesStatus } from 'calypso/state/sites/hooks/use-site-global-styles-status';
import { withSiteGlobalStylesOnPersonal } from 'calypso/state/sites/hooks/with-site-global-styles-on-personal';
import { getCurrentPlan, isSiteOnECommerceTrial } from 'calypso/state/sites/plans/selectors';
import { getSiteSlug, isJetpackSite } from 'calypso/state/sites/selectors';
import {
Expand Down Expand Up @@ -677,28 +678,28 @@ class ThemeSheet extends Component {
isBundledSoftwareSet,
} = this.props;

const isGlobalStylesEnabled = isEnabled( 'global-styles/on-personal-plan' );
const isGlobalStylesOnPersonal = this.props.isGlobalStylesOnPersonal;

const isFreeTier = isFreePlan && themeTier?.slug === 'free';
const hasLimitedFeatures =
! isExternallyManagedTheme &&
! isBundledSoftwareSet &&
! isThemePurchased &&
! isGlobalStylesEnabled &&
! isGlobalStylesOnPersonal &&
! isPremium &&
shouldLimitGlobalStyles;

const shouldSplitDefaultVariation = isFreeTier || hasLimitedFeatures;

const needsUpgrade = isGlobalStylesEnabled
? isFreePlan
const needsUpgrade = isGlobalStylesOnPersonal
? isFreePlan || shouldLimitGlobalStyles
: shouldLimitGlobalStyles || ( isPremium && ! isThemePurchased );

return (
styleVariations.length > 0 && (
<ThemeStyleVariations
description={ this.getStyleVariationDescription() }
splitDefaultVariation={ shouldSplitDefaultVariation }
splitDefaultVariation={ shouldSplitDefaultVariation || needsUpgrade }
selectedVariation={ this.getSelectedStyleVariation() }
variations={ styleVariations }
needsUpgrade={ needsUpgrade }
Expand Down Expand Up @@ -1077,7 +1078,7 @@ class ThemeSheet extends Component {
params.append( 'redirect_to', window.location.href.replace( window.location.origin, '' ) );

this.setState( { showUnlockStyleUpgradeModal: false } );
const upgradeToPlan = isEnabled( 'global-styles/on-personal-plan' ) ? 'personal' : 'premium';
const upgradeToPlan = this.props.isGlobalStylesOnPersonal ? 'personal' : 'premium';

page( `/checkout/${ this.props.siteSlug || '' }/${ upgradeToPlan }?${ params.toString() }` );
};
Expand Down Expand Up @@ -1485,4 +1486,6 @@ export default connect(
themeStartActivationSync: themeStartActivationSyncAction,
errorNotice,
}
)( withSiteGlobalStylesStatus( localize( ThemeSheetWithOptions ) ) );
)(
withSiteGlobalStylesStatus( withSiteGlobalStylesOnPersonal( localize( ThemeSheetWithOptions ) ) )
);
3 changes: 3 additions & 0 deletions client/my-sites/theme/theme-style-variations/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import AsyncLoad from 'calypso/components/async-load';
import { useSiteGlobalStylesOnPersonal } from 'calypso/state/sites/hooks/use-site-global-styles-on-personal';
import type { StyleVariation } from '@automattic/design-picker/src/types';
import type { TranslateResult } from 'i18n-calypso';
import './style.scss';
Expand All @@ -20,6 +21,7 @@ const ThemeStyleVariations = ( {
needsUpgrade,
onClick,
}: ThemeStyleVariationsProps ) => {
const isGlobalStylesOnPersonal = useSiteGlobalStylesOnPersonal();
return (
<div className="theme__sheet-style-variations">
{ !! description && <p>{ description }</p> }
Expand All @@ -35,6 +37,7 @@ const ThemeStyleVariations = ( {
showOnlyHoverViewDefaultVariation={ false }
needsUpgrade={ needsUpgrade }
onSelect={ onClick }
isGlobalStylesOnPersonal={ isGlobalStylesOnPersonal }
/>
</div>
</div>
Expand Down
Loading

0 comments on commit 14761a3

Please sign in to comment.