diff --git a/client/my-sites/themes/activation-modal.jsx b/client/my-sites/themes/activation-modal.jsx index e7c57d75d99c..7be1afb10847 100644 --- a/client/my-sites/themes/activation-modal.jsx +++ b/client/my-sites/themes/activation-modal.jsx @@ -1,25 +1,30 @@ import { recordTracksEvent } from '@automattic/calypso-analytics'; -import { Dialog, Gridicon, Button, ScreenReaderText } from '@automattic/components'; +import { getPlan } from '@automattic/calypso-products'; +import { Button, Dialog, Gridicon, ScreenReaderText } from '@automattic/components'; import { Onboard } from '@automattic/data-stores'; import { localizeUrl } from '@automattic/i18n-utils'; +import { CheckboxControl } from '@wordpress/components'; import { translate } from 'i18n-calypso'; import PropTypes from 'prop-types'; import { Component } from 'react'; import { connect } from 'react-redux'; +import { THEME_TIERS } from 'calypso/components/theme-tier/constants'; import TrackComponentView from 'calypso/lib/analytics/track-component-view'; import { getSiteDomain } from 'calypso/state/sites/selectors'; import { acceptActivationModal, - dismissActivationModal, activate as activateTheme, + dismissActivationModal, } from 'calypso/state/themes/actions'; import { + getActiveTheme, getCanonicalTheme, + getThemeIdToActivate, + getThemeTierForTheme, isActivatingTheme, isThemeActive, + isThemeAllowedOnSite, shouldShowActivationModal, - getThemeIdToActivate, - getActiveTheme, } from 'calypso/state/themes/selectors'; import { getSelectedSiteId } from 'calypso/state/ui/selectors'; @@ -45,21 +50,43 @@ export class ActivationModal extends Component { newThemeId: PropTypes.string, }; + constructor( props ) { + super( props ); + const { isCurrentThemeAllowedOnSite } = props; + + this.state = { + checkboxChecked: isCurrentThemeAllowedOnSite, + }; + } + + onCheckboxChange = ( isChecked ) => { + this.setState( { checkboxChecked: isChecked } ); + }; + closeModalHandler = ( action = 'dismiss' ) => () => { - const { newThemeId, siteId, source } = this.props; + const { newThemeId, activeTheme, siteId, source, isCurrentThemeAllowedOnSite } = this.props; if ( 'activeTheme' === action ) { this.props.acceptActivationModal( newThemeId ); + const eventName = ! isCurrentThemeAllowedOnSite + ? 'calypso_theme_switch_plan_warning_accepted' + : 'calypso_theme_autoloading_homepage_modal_activate_click'; - recordTracksEvent( 'calypso_theme_autoloading_homepage_modal_activate_click', { + recordTracksEvent( eventName, { theme: newThemeId, + activeTheme: activeTheme.id, } ); return this.props.activateTheme( newThemeId, siteId, { source } ); } else if ( 'dismiss' === action ) { - recordTracksEvent( 'calypso_theme_autoloading_homepage_modal_dismiss', { + const eventName = ! isCurrentThemeAllowedOnSite + ? 'calypso_theme_switch_plan_warning_declined' + : 'calypso_theme_autoloading_homepage_modal_dismiss'; + + recordTracksEvent( eventName, { action: 'escape', theme: newThemeId, + activeTheme: activeTheme.id, } ); return this.props.dismissActivationModal(); } @@ -67,6 +94,8 @@ export class ActivationModal extends Component { render() { const { + isCurrentThemeAllowedOnSite, + activeThemeRequiredPlan, newTheme, activeTheme, isActivating, @@ -89,6 +118,10 @@ export class ActivationModal extends Component { return null; } + const eventName = ! isCurrentThemeAllowedOnSite + ? 'calypso_theme_switch_plan_warning_modal_view' + : 'calypso_theme_autoloading_homepage_modal_view'; + const isAIAssembler = siteIntent === SiteIntent.AIAssembler && activeTheme.id === 'assembler'; const translationArgs = { args: { @@ -127,8 +160,8 @@ export class ActivationModal extends Component { onClose={ this.closeModalHandler( 'dismiss' ) } > { message } + { ! isCurrentThemeAllowedOnSite && ( + + ) } - + { translate( 'Activate %(themeName)s', { args: { themeName: newTheme.name }, } ) } @@ -163,6 +222,11 @@ export default connect( const siteId = getSelectedSiteId( state ); const newThemeId = getThemeIdToActivate( state ); const activeThemeId = getActiveTheme( state, siteId ); + const isCurrentThemeAllowedOnSite = isThemeAllowedOnSite( state, siteId, activeThemeId ); + const activeThemeTier = getThemeTierForTheme( state, activeThemeId ); + const activeThemeMinimumUpsellPlan = THEME_TIERS[ activeThemeTier?.slug ]?.minimumUpsellPlan; + const activeThemeRequiredPlan = + activeThemeMinimumUpsellPlan && getPlan( activeThemeMinimumUpsellPlan ); return { siteId, @@ -173,6 +237,8 @@ export default connect( isActivating: !! isActivatingTheme( state, siteId ), isCurrentTheme: isThemeActive( state, newThemeId, siteId ), isVisible: shouldShowActivationModal( state, newThemeId ), + isCurrentThemeAllowedOnSite, + activeThemeRequiredPlan, }; }, { diff --git a/client/my-sites/themes/activation-modal.scss b/client/my-sites/themes/activation-modal.scss index c064a03b0173..312e21b23975 100644 --- a/client/my-sites/themes/activation-modal.scss +++ b/client/my-sites/themes/activation-modal.scss @@ -13,6 +13,10 @@ } } +.activation-modal__lower-tier-warning { + margin-bottom: 36px; +} + .themes__activation-modal-close-icon { position: absolute; top: 4px; diff --git a/client/state/themes/hooks/use-is-theme-allowed-on-site.ts b/client/state/themes/hooks/use-is-theme-allowed-on-site.ts index 1b3cc7e9d58e..eba970b568e7 100644 --- a/client/state/themes/hooks/use-is-theme-allowed-on-site.ts +++ b/client/state/themes/hooks/use-is-theme-allowed-on-site.ts @@ -1,17 +1,8 @@ import { useSelector } from 'calypso/state'; -import siteHasFeature from 'calypso/state/selectors/site-has-feature'; -import { getThemeTierForTheme } from 'calypso/state/themes/selectors'; +import { isThemeAllowedOnSite } from 'calypso/state/themes/selectors/is-theme-allowed-on-site'; export function useIsThemeAllowedOnSite( siteId: number | null, themeId: string ) { - return useSelector( ( state ) => { - const themeTier = getThemeTierForTheme( state, themeId ); - const features = themeTier?.featureList ?? [ themeTier?.feature ]; - - return features.some( - ( feature: string | null | undefined ) => - ! feature || siteHasFeature( state, siteId, feature ) - ); - } ); + return useSelector( ( state ) => isThemeAllowedOnSite( state, siteId, themeId ) ); /* @SEE https://github.com/Automattic/dotcom-forge/issues/8028 const retainedBenefits = useTierRetainedBenefitsQuery( siteId, themeId ); diff --git a/client/state/themes/selectors/index.js b/client/state/themes/selectors/index.js index ab5623e4f6fc..f30cad5937f8 100644 --- a/client/state/themes/selectors/index.js +++ b/client/state/themes/selectors/index.js @@ -65,6 +65,7 @@ export { isSiteEligibleForBundledSoftware } from 'calypso/state/themes/selectors export { isSiteEligibleForManagedExternalThemes } from 'calypso/state/themes/selectors/is-site-eligible-for-managed-external-themes'; export { isThemeActivationSyncStarted } from 'calypso/state/themes/selectors/is-theme-activation-sync-started'; export { isThemeActive } from 'calypso/state/themes/selectors/is-theme-active'; +export { isThemeAllowedOnSite } from 'calypso/state/themes/selectors/is-theme-allowed-on-site'; export { isThemeGutenbergFirst } from 'calypso/state/themes/selectors/is-theme-gutenberg-first'; export { isThemePremium } from 'calypso/state/themes/selectors/is-theme-premium'; export { isThemePurchased } from 'calypso/state/themes/selectors/is-theme-purchased'; diff --git a/client/state/themes/selectors/is-theme-allowed-on-site.ts b/client/state/themes/selectors/is-theme-allowed-on-site.ts new file mode 100644 index 000000000000..eb5ef6949c1f --- /dev/null +++ b/client/state/themes/selectors/is-theme-allowed-on-site.ts @@ -0,0 +1,12 @@ +import siteHasFeature from 'calypso/state/selectors/site-has-feature'; +import { getThemeTierForTheme } from 'calypso/state/themes/selectors'; +import { IAppState } from 'calypso/state/types'; + +export function isThemeAllowedOnSite( state: IAppState, siteId: number | null, themeId: string ) { + const themeTier = getThemeTierForTheme( state, themeId ); + const features = themeTier?.featureList ?? [ themeTier?.feature ]; + + return features.some( + ( feature: string | null | undefined ) => ! feature || siteHasFeature( state, siteId, feature ) + ); +}
{ message }