diff --git a/client/components/formatted-header/index.jsx b/client/components/formatted-header/index.jsx index d8d24e9b7d1f0..f7b1196a2130f 100644 --- a/client/components/formatted-header/index.jsx +++ b/client/components/formatted-header/index.jsx @@ -1,5 +1,6 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; +import InfoPopover from 'calypso/components/info-popover'; import { preventWidows } from 'calypso/lib/formatting'; import './style.scss'; @@ -9,6 +10,7 @@ function FormattedHeader( { id, headerText, subHeaderText, + tooltipText, className, compactOnMobile, align, @@ -24,11 +26,24 @@ function FormattedHeader( { } ); const headerClasses = classNames( 'formatted-header__title', { 'wp-brand-font': brandFont } ); + const tooltip = tooltipText && ( + + { tooltipText } + + ); return (
- { ! isSecondary &&

{ preventWidows( headerText, 2 ) }

} - { isSecondary &&

{ preventWidows( headerText, 2 ) }

} + { ! isSecondary && ( +

+ { preventWidows( headerText, 2 ) } { tooltip } +

+ ) } + { isSecondary && ( +

+ { preventWidows( headerText, 2 ) } { tooltip } +

+ ) } { subHeaderText && (

{ preventWidows( subHeaderText, 2 ) }

) } @@ -42,6 +57,7 @@ FormattedHeader.propTypes = { brandFont: PropTypes.bool, headerText: PropTypes.node, subHeaderText: PropTypes.node, + tooltipText: PropTypes.node, compactOnMobile: PropTypes.bool, isSecondary: PropTypes.bool, align: PropTypes.oneOf( [ 'center', 'left', 'right' ] ), @@ -53,6 +69,7 @@ FormattedHeader.defaultProps = { className: '', brandFont: false, subHeaderText: '', + tooltipText: '', compactOnMobile: false, isSecondary: false, align: 'center', diff --git a/client/jetpack-connect/test/__snapshots__/auth-form-header.js.snap b/client/jetpack-connect/test/__snapshots__/auth-form-header.js.snap index 968705ce36d98..9b52529c5697a 100644 --- a/client/jetpack-connect/test/__snapshots__/auth-form-header.js.snap +++ b/client/jetpack-connect/test/__snapshots__/auth-form-header.js.snap @@ -11,6 +11,7 @@ exports[`AuthFormHeader renders as expected 1`] = ` id="" isSecondary={false} subHeaderText="You are moments away from a better WordPress." + tooltipText="" /> = ( { diff --git a/client/my-sites/plans-comparison/plans-comparison-features.tsx b/client/my-sites/plans-comparison/plans-comparison-features.tsx index 234a12771b1cb..e4b1140289179 100644 --- a/client/my-sites/plans-comparison/plans-comparison-features.tsx +++ b/client/my-sites/plans-comparison/plans-comparison-features.tsx @@ -3,11 +3,9 @@ import { FEATURE_100K_VISITS, FEATURE_500MB_STORAGE, FEATURE_50GB_STORAGE, - FEATURE_ADDITIONAL_SITES, FEATURE_UNLIMITED_POSTS_PAGES, FEATURE_UNLIMITED_ADMINS, FEATURE_INSTALL_PLUGINS, - FEATURE_COMMUNITY_SUPPORT, FEATURE_EMAIL_LIVE_CHAT_SUPPORT_ALL_DAYS, FEATURE_PAYMENT_BLOCKS, FEATURE_WOOCOMMERCE, @@ -15,10 +13,11 @@ import { FEATURE_NO_ADS, FEATURE_SFTP_DATABASE, FEATURE_SITE_BACKUPS_AND_RESTORE, + FEATURE_CUSTOM_DOMAIN, + FEATURE_PREMIUM_THEMES, } from '@automattic/calypso-products'; import { Gridicon } from '@automattic/components'; import { translate, numberFormat } from 'i18n-calypso'; -import { getFeatureByKey } from 'calypso/lib/plans/features-list'; import type { TranslateResult, TranslateOptionsPlural } from 'i18n-calypso'; export interface PlanComparisonFeature { @@ -89,25 +88,111 @@ function defaultGetCellText( export const planComparisonFeatures: PlanComparisonFeature[] = [ { - title: translate( 'Sites' ), - description: translate( 'Popup text placeholder' ), - features: [ FEATURE_ADDITIONAL_SITES ], - getCellText: ( feature ) => { - const siteCount = 1; - const title = translate( '%(siteCount)s site', '%(siteCount)s sites', { - count: siteCount, - args: { siteCount }, - } ); - const desc = feature - ? translate( 'You can purchase more sites.' ) - : translate( 'You can’t purchase more sites.' ); + title: translate( 'Custom Domain Name' ), + description: translate( + 'Get a personalized online address that’s easy to remember and easy to share.' + ), + features: [ FEATURE_CUSTOM_DOMAIN ], + getCellText: ( feature, isMobile = false ) => { + if ( ! isMobile ) { + if ( feature ) { + return ( + <> + + { translate( 'Free for one year!' ) } + + ); + } - return [ title, desc ]; + return ( + <> + + { translate( 'Not included' ) } + + ); + } + + return feature + ? translate( 'Custom Domain Name is free for one year!' ) + : translate( 'Custom Domain Name is not included' ); }, }, { - title: translate( 'Visits' ), - description: translate( 'Popup text placeholder' ), + title: translate( 'Premium themes' ), + description: translate( + 'Gain access to advanced, professional & beautiful premium design templates including themes specifically tailored for businesses.' + ), + features: [ FEATURE_PREMIUM_THEMES ], + getCellText: defaultGetCellText( translate( 'Premium themes' ) ), + }, + { + title: translate( 'Unlimited Email and Live Chat Support' ), + description: translate( + 'Customer service isn’t just something we offer. It’s who we are. Over 30% of WordPress.com is dedicated to service. We call it Happiness—real support delivered by real human beings who specialize in launching and fine-tuning WordPress sites. ' + ), + features: [ FEATURE_EMAIL_LIVE_CHAT_SUPPORT_ALL_DAYS ], + getCellText: defaultGetCellText( translate( 'Unlimited Email and Live Chat Support' ) ), + }, + { + title: translate( 'WordPress Plugins' ), + subtitle: translate( 'Use any WordPress plugins on your site' ), + description: translate( + 'Install WordPress plugins and extend functionality for your site with access to more than 50,000 WordPress plugins' + ), + features: [ FEATURE_INSTALL_PLUGINS ], + getCellText: ( feature, isMobile = false ) => { + const pluginCount = 0; + + if ( ! isMobile ) { + return feature ? translate( 'Unlimited' ) : String( pluginCount ); + } + + return feature + ? translate( 'Unlimited WordPress Plugins' ) + : translate( '%(pluginCount)s WordPress Plugin', '%(pluginCount)s WordPress Plugins', { + count: pluginCount, + args: { pluginCount: numberFormat( pluginCount, 0 ) }, + } ); + }, + }, + { + title: translate( 'Storage space' ), + description: translate( + 'The free plan allows a maximum storage of 500MB, which equals to approximately 100 high quality images, whilst with Managed WordPress you may go all the way up to 50GB, enough space for 10,000 high quality images of the same size.' + ), + features: [ FEATURE_500MB_STORAGE, FEATURE_50GB_STORAGE ], + getCellText: ( feature, isMobile = false ) => { + let storageSize = '0.5'; + + if ( feature === FEATURE_50GB_STORAGE ) { + storageSize = '50'; + } + + if ( isMobile ) { + return translate( '%sGB of storage', { + args: [ storageSize ], + } ); + } + + return translate( '%sGB', { + args: [ storageSize ], + comment: '%s is a number of gigabytes.', + } ); + }, + }, + { + title: translate( 'Sell products with WooCommerce' ), + description: translate( + 'Includes one-click payments, premium store designs and personalized expert support.' + ), + features: [ FEATURE_WOOCOMMERCE ], + getCellText: defaultGetCellText( translate( 'Sell products with WooCommerce' ) ), + }, + { + title: translate( 'Visits per month' ), + description: translate( + "WordPress Managed bundles up to 100,000 visits a month to help you rest assured traffic won't be a concern." + ), features: [ FEATURE_10K_VISITS, FEATURE_100K_VISITS ], getCellText: ( feature, isMobile = false ) => { let visitCount = 0; @@ -159,80 +244,12 @@ export const planComparisonFeatures: PlanComparisonFeature[] = [ } ); }, }, - { - title: translate( 'WordPress plugins' ), - subtitle: translate( 'Be able to add forms, calendar, etc.' ), - features: [ FEATURE_INSTALL_PLUGINS ], - getCellText: ( feature, isMobile = false ) => { - const pluginCount = 0; - - if ( ! isMobile ) { - return feature ? translate( 'Unlimited' ) : String( pluginCount ); - } - - return feature - ? translate( 'Unlimited WordPress plugins' ) - : translate( '%(pluginCount)s WordPress plugin', '%(pluginCount)s WordPress plugins', { - count: pluginCount, - args: { pluginCount: numberFormat( pluginCount, 0 ) }, - } ); - }, - }, - { - title: translate( 'Storage' ), - description: translate( 'Upload more images, videos, audio, and documents to your website.' ), - features: [ FEATURE_500MB_STORAGE, FEATURE_50GB_STORAGE ], - getCellText: ( feature, isMobile = false ) => { - let storageSize = '0.5'; - - if ( feature === FEATURE_50GB_STORAGE ) { - storageSize = '50'; - } - - if ( isMobile ) { - return translate( '%sGB of storage', { - args: [ storageSize ], - } ); - } - - return translate( '%sGB', { - args: [ storageSize ], - comment: '%s is a number of gigabytes.', - } ); - }, - }, - { - title: translate( 'Support' ), - description: translate( 'Popup text placeholder' ), - features: [ FEATURE_COMMUNITY_SUPPORT, FEATURE_EMAIL_LIVE_CHAT_SUPPORT_ALL_DAYS ], - getCellText: ( feature ) => { - if ( feature === FEATURE_COMMUNITY_SUPPORT ) { - return [ - getFeatureByKey( FEATURE_COMMUNITY_SUPPORT ).getTitle(), - getFeatureByKey( FEATURE_COMMUNITY_SUPPORT ).getDescription(), - ]; - } - - return [ - getFeatureByKey( FEATURE_EMAIL_LIVE_CHAT_SUPPORT_ALL_DAYS ).getTitle(), - getFeatureByKey( FEATURE_EMAIL_LIVE_CHAT_SUPPORT_ALL_DAYS ).getDescription(), - ]; - }, - }, { title: translate( 'Payment blocks' ), description: translate( 'Popup text placeholder' ), features: [ FEATURE_PAYMENT_BLOCKS ], getCellText: defaultGetCellText( translate( 'Payment blocks' ) ), }, - { - title: translate( 'WooCommerce' ), - description: translate( - 'WooCommerce is a customizable, open-source eCommerce platform built on WordPress.' - ), - features: [ FEATURE_WOOCOMMERCE ], - getCellText: defaultGetCellText( translate( 'WooCommerce' ) ), - }, { title: translate( 'Jetpack' ), description: translate( diff --git a/client/my-sites/plans-comparison/plans-comparison-row-header.tsx b/client/my-sites/plans-comparison/plans-comparison-row-header.tsx index 13f97402b7333..a833188a7c9d2 100644 --- a/client/my-sites/plans-comparison/plans-comparison-row-header.tsx +++ b/client/my-sites/plans-comparison/plans-comparison-row-header.tsx @@ -9,28 +9,36 @@ interface Props { scope?: 'row' | 'col'; } +const Details = styled.div` + html[dir='ltr'] & { + margin-left: 6px; + } + html[dir='rtl'] & { + margin-right: 6px; + } +`; const Wrapper = styled.div` display: flex; - flex-direction: column; - margin-left: 21px; + flex-direction: row; min-height: 100%; + align-items: center; + + .gridicon { + display: block; + color: var( --studio-gray-30 ); + } `; const Title = styled.div` display: flex; flex-direction: row; gap: 5px; - font-weight: 600; - margin-left: -21px; - - .gridicon { - display: block; - color: var( --studio-gray-30 ); - } + font-weight: 500; + align-items: center; `; const Subtitle = styled.div` - color: var( --studio-gray-30 ); + color: var( --studio-gray-40 ); font-size: 0.75rem; font-weight: 300; `; @@ -44,13 +52,13 @@ export const PlansComparisonRowHeader: React.FunctionComponent< Props > = ( { return ( - - <InfoPopover position="top" iconSize={ 16 } showOnHover={ true }> - { description } - </InfoPopover> - { title } - - { subtitle && { subtitle } } + + { description } + +
+ { title } + { subtitle && { subtitle } } +
); diff --git a/client/my-sites/plans-comparison/plans-comparison-row.tsx b/client/my-sites/plans-comparison/plans-comparison-row.tsx index d39ab5517db81..49372150369d3 100644 --- a/client/my-sites/plans-comparison/plans-comparison-row.tsx +++ b/client/my-sites/plans-comparison/plans-comparison-row.tsx @@ -1,6 +1,6 @@ import styled from '@emotion/styled'; import { intersection } from 'lodash'; -import { SCREEN_BREAKPOINT } from './constant'; +import { SCREEN_BREAKPOINT_SIGNUP, SCREEN_BREAKPOINT_PLANS } from './constant'; import { PlansComparisonRowHeader } from './plans-comparison-row-header'; import type { PlanComparisonFeature } from './plans-comparison-features'; import type { WPComPlan } from '@automattic/calypso-products'; @@ -14,29 +14,49 @@ const DesktopContent = styled.div` display: flex; flex-direction: column; - @media screen and ( max-width: ${ SCREEN_BREAKPOINT }px ) { - display: none; + @media screen and ( max-width: ${ SCREEN_BREAKPOINT_SIGNUP }px ) { + .is-section-signup & { + display: none; + } + } + + @media screen and ( max-width: ${ SCREEN_BREAKPOINT_PLANS }px ) { + .is-section-plans & { + display: none; + } } `; const MobileContent = styled.div` display: none; + font-weight: 500; + + @media screen and ( max-width: ${ SCREEN_BREAKPOINT_SIGNUP }px ) { + .is-section-signup & { + display: block; + } + } - @media screen and ( max-width: ${ SCREEN_BREAKPOINT }px ) { - display: flex; - flex-direction: column; + @media screen and ( max-width: ${ SCREEN_BREAKPOINT_PLANS }px ) { + .is-section-plans & { + display: block; + } } `; const Title = styled.div` - display: flex; - flex-direction: row; - align-items: center; gap: 0.5rem; - .gridicon { - width: 1em; - height: 1em; + .gridicon.gridicon { + width: 1.1em; + height: 1.1em; + + html[dir='ltr'] & { + margin: 0 5px -2px 0; + } + html[dir='rtl'] & { + margin: 0 0 -2px 5px; + } } .gridicons-checkmark { @@ -44,14 +64,15 @@ const Title = styled.div` } .gridicons-cross { - fill: var( --studio-gray-30 ); + fill: #d63638; } `; const Description = styled.p` font-size: 0.75rem; - color: var( --studio-gray-30 ); + color: var( --studio-gray-40 ); margin: 0; + font-weight: 400; `; function renderContent( content: ReturnType< PlanComparisonFeature[ 'getCellText' ] > ) { diff --git a/client/my-sites/plans-comparison/plans-comparison.tsx b/client/my-sites/plans-comparison/plans-comparison.tsx index b2ffd3eb668b8..6b042349a112f 100644 --- a/client/my-sites/plans-comparison/plans-comparison.tsx +++ b/client/my-sites/plans-comparison/plans-comparison.tsx @@ -6,14 +6,17 @@ import { TYPE_FLEXIBLE, TYPE_MANAGED, } from '@automattic/calypso-products'; -import { Global } from '@emotion/react'; +import { Gridicon } from '@automattic/components'; +import { css } from '@emotion/react'; import styled from '@emotion/styled'; +import classNames from 'classnames'; import { useTranslate } from 'i18n-calypso'; +import { useCallback, useState } from 'react'; import { useSelector } from 'react-redux'; import { getManagePurchaseUrlFor } from 'calypso/my-sites/purchases/paths'; import { getCurrentUserCurrencyCode } from 'calypso/state/currency-code/selectors'; import { getSitePlan } from 'calypso/state/sites/selectors'; -import { SCREEN_BREAKPOINT } from './constant'; +import { SCREEN_BREAKPOINT_SIGNUP, SCREEN_BREAKPOINT_PLANS } from './constant'; import { PlansComparisonAction } from './plans-comparison-action'; import { PlansComparisonColHeader } from './plans-comparison-col-header'; import { planComparisonFeatures } from './plans-comparison-features'; @@ -27,25 +30,260 @@ interface TableProps { planCount: number; } +const getRowMobileLayout = ( breakpoint: number, pageClass: string ) => ` + @media screen and ( max-width: ${ breakpoint }px ) { + ${ pageClass } & { + th.is-first, + td.is-first { + display: none; + } + + th, + td { + width: ${ ( { planCount }: { planCount: number } ) => `${ 100 / planCount }%` }; + } + } + } +`; + +export const globalOverrides = css` + #content.layout__content { + overflow: unset; + min-height: 100vh !important; + background: #fdfdfd; + padding-left: 0; + padding-right: 0; + padding-top: 47px; + } + + .layout__secondary { + box-shadow: 0 1px 0 1px rgba( 0, 0, 0, 0.1 ); + } + + .is-nav-unification .sidebar .sidebar__heading::after, + .is-nav-unification .sidebar .sidebar__menu-link::after { + html[dir='ltr'] & { + margin-right: -1px; + border-right-color: #fdfdfd; + } + html[dir='rtl'] & { + margin-left: -1px; + border-left-color: #fdfdfd; + } + } + + .main.is-wide-layout.is-wide-layout { + max-width: 100%; + } + + .formatted-header__title.formatted-header__title { + font-size: 1rem; + font-family: inherit !important; + font-weight: 600; + margin: 0 auto; + max-width: 1040px; + + .gridicon { + margin-bottom: -2px; + fill: rgba( 140, 143, 148, 1 ); + } + } + + .formatted-header__subtitle { + display: none; + } + + .formatted-header.formatted-header { + border-bottom: 1px solid #dcdcde; + padding-bottom: 24px; + margin: 0; + + html[dir='ltr'] & { + padding: 12px 24px 24px calc( var( --sidebar-width-min ) + 24px + 1px ); + } + html[dir='rtl'] & { + padding: 12px calc( var( --sidebar-width-min ) + 24px + 1px ) 24px 24px; + } + + @media ( max-width: 782px ) { + html[dir='ltr'] &, + html[dir='rtl'] & { + padding: 24px 16px; + } + } + } + + .plans, + .current-plan__content { + max-width: 1040px; + margin: auto; + + html[dir='ltr'] & { + padding: 0 24px 0 calc( var( --sidebar-width-min ) + 24px + 1px ); + } + html[dir='rtl'] & { + padding: 0 calc( var( --sidebar-width-min ) + 24px + 1px ) 0 24px; + } + + @media ( max-width: 782px ) { + html[dir='ltr'] &, + html[dir='rtl'] & { + padding: 0; + } + } + } + + .section-nav.section-nav { + box-shadow: none; + background: none; + margin: 16px 0 32px; + } + + .section-nav-tab { + opacity: 0.7; + } + + .section-nav-tab.is-selected, + .section-nav-tab:hover { + opacity: 1; + } + + .section-nav-tab__link { + font-size: 16px; + } + + .section-nav-tab__link, + .section-nav-tab__link:hover, + .section-nav-tab__link:focus, + .section-nav-tab__link:active { + color: inherit !important; + background: none !important; + } + + .section-nav-tab:hover:not( .is-selected ) { + border-bottom-color: transparent; + } + + .my-plan-card__icon { + display: none; + } + + .my-plan-card__title { + font-family: Recoleta; + font-size: 1.5rem; + margin-bottom: 0.5rem; + } + + .notice.notice { + color: inherit; + } + + .notice.is-info { + background: #f6f7f7; + } + + .notice__content.notice__content { + html[dir='ltr'] & { + padding: 10px 10px 10px 0; + } + html[dir='rtl'] & { + padding: 10px 0 10px 10px; + } + } + + .notice.is-info .notice__icon-wrapper.notice__icon-wrapper { + background: none; + width: 40px; + } + + .notice .gridicons-info-outline { + fill: #008a20; + } + + .my-plan-card.my-plan-card.card { + flex-direction: column; + justify-content: stretch; + } + + .my-plan-card__primary.my-plan-card__primary { + min-width: 60%; + } + + .my-plan-card__details.my-plan-card__details { + display: none; + } + + .popover__arrow { + display: none; + } + .popover.info-popover__tooltip .popover__inner.popover__inner { + background: var( --studio-gray-100 ); + color: #fff; + border: none; + padding: 8px 10px; + border-radius: 4px; + font-size: 0.75rem; + } +`; + const ComparisonTable = styled.table< TableProps >` - max-width: 100%; border-collapse: collapse; - margin: 0 auto; + + .is-section-plans & { + max-width: 950px; + html[dir='ltr'] & { + margin-left: auto; + } + html[dir='rtl'] & { + margin-right: auto; + } + } th, td { - background: var( --studio-white ); - border-bottom: 1px solid var( --studio-gray-0 ); - padding: 1rem; + background: #fdfdfd; + border-bottom: 1px solid rgba( 220, 220, 222, 0.2 ); + padding: 1.25rem; min-height: 2rem; width: ${ ( { firstColWidth, planCount } ) => `${ ( 100 - firstColWidth ) / planCount }%` }; - font-size: 1rem; + font-size: 0.875rem; + vertical-align: middle; + + @media screen and ( max-width: ${ SCREEN_BREAKPOINT_SIGNUP }px ) { + .is-section-signup & { + width: 50%; + font-size: 0.75rem; + } + } + + @media screen and ( max-width: ${ SCREEN_BREAKPOINT_PLANS }px ) { + .is-section-plans & { + width: 50%; + font-size: 0.75rem; + } + } + } + + thead th, + thead td { vertical-align: top; + border-bottom: none; + @media screen and ( min-width: ${ SCREEN_BREAKPOINT_SIGNUP + 1 }px ) { + .is-section-signup & { + padding-bottom: 3.6rem; + } + } + + @media screen and ( min-width: ${ SCREEN_BREAKPOINT_PLANS + 1 }px ) { + .is-section-plans & { + padding-bottom: 3.6rem; + } + } } th:nth-of-type( even ), td:nth-of-type( even ) { - background: var( --studio-blue-0 ); + background: #f0f7fc; } th.is-first, @@ -53,20 +291,48 @@ const ComparisonTable = styled.table< TableProps >` width: ${ ( { firstColWidth } ) => `${ firstColWidth }%` }; } - .button { + th .button { width: 100%; border-radius: 4px; + font-weight: 500; } - @media screen and ( max-width: ${ SCREEN_BREAKPOINT }px ) { - th.is-first, - td.is-first { - display: none; - } + th:last-child .button { + background: #0675c4; + border-color: #0675c4; + } + + th:last-child .button .button:hover { + background: #055d9c; + border-color: #055d9c; + } + .plans-comparison__rows tr:last-child { th, td { - width: ${ ( { planCount } ) => `${ 100 / planCount }%` }; + border-bottom: none; + } + } + + ${ getRowMobileLayout( SCREEN_BREAKPOINT_SIGNUP, '.is-section-signup' ) } + ${ getRowMobileLayout( SCREEN_BREAKPOINT_PLANS, '.is-section-plans' ) } + + .plans-comparison__collapsible-rows { + display: none; + border-top: 1px solid rgba( 220, 220, 222, 0.2 ); + } + + .plans-comparison__collapsible-rows.is-active { + display: table-row-group; + animation: fade-in-rows 0.3s ease; + } + + @keyframes fade-in-rows { + 0% { + opacity: 0; + } + 100% { + opacity: 1; } } `; @@ -76,6 +342,64 @@ const THead = styled.thead< { isInSignup: boolean } >` top: ${ ( { isInSignup } ) => ( isInSignup ? '0' : `var( --masterbar-height )` ) }; `; +const PlanComparisonToggle = styled.tr` + th, + td { + padding: 0; + border-bottom: none; + } + + ${ getRowMobileLayout( SCREEN_BREAKPOINT_SIGNUP, '.is-section-signup' ) } + ${ getRowMobileLayout( SCREEN_BREAKPOINT_PLANS, '.is-section-plans' ) } + + button { + background: rgba( 246, 247, 247, 0.5 ); + display: block; + text-align: center; + border-radius: 2px; + padding: 15px; + width: 100%; + margin: 25px 0; + cursor: pointer; + + .gridicon.gridicon { + html[dir='ltr'] & { + margin-right: 4px; + } + html[dir='rtl'] & { + margin-left: 4px; + } + } + } +`; + +const MobileComparePlansHeader = styled.td` + display: none; + + h3 { + font-size: 1.5rem; + font-family: Recoleta; + line-height: 2; + margin-top: 0.5rem; + } + + p { + font-size: 0.875rem; + } + + @media screen and ( max-width: ${ SCREEN_BREAKPOINT_SIGNUP }px ) { + .is-section-signup & { + display: table-cell; + } + } + + @media screen and ( max-width: ${ SCREEN_BREAKPOINT_PLANS }px ) { + .is-section-plans & { + display: table-cell; + } + } +`; + interface Props { isInSignup?: boolean; selectedSiteId?: number; @@ -103,21 +427,28 @@ export const PlansComparison: React.FunctionComponent< Props > = ( { onSelectPlan, } ) => { const sitePlan = useSelector( ( state ) => getSitePlan( state, selectedSiteId || null ) ); + const [ showCollapsibleRows, setShowCollapsibleRows ] = useState( false ); const currencyCode = useSelector( getCurrentUserCurrencyCode ) ?? ''; const plans = [ getPlan( PLAN_WPCOM_FLEXIBLE ), getPlan( PLAN_WPCOM_MANAGED ) ] as WPComPlan[]; const prices: PlanPrices[] = [ { price: 0 }, usePlanPrices( plans[ 1 ], selectedSiteId ) ]; const translate = useTranslate(); + const toggleCollapsibleRows = useCallback( () => { + setShowCollapsibleRows( ! showCollapsibleRows ); + }, [ showCollapsibleRows ] ); + const manageHref = selectedSiteSlug && purchaseId ? getManagePurchaseUrlFor( selectedSiteSlug, purchaseId ) : `/plans/${ selectedSiteSlug || '' }`; + const collapsibleRowsclassName = classNames( + 'plans-comparison__rows', + 'plans-comparison__collapsible-rows', + { 'is-active': showCollapsibleRows } + ); return ( - { ! isInSignup && ( - - ) } @@ -145,11 +476,43 @@ export const PlansComparison: React.FunctionComponent< Props > = ( { ) ) } - - { planComparisonFeatures.map( ( feature ) => ( + + + +

{ translate( 'Compare plans' ) }

+

{ 'Lorem ipsum dolor sit amet, consectetur dolor sit amet adipiscing elit.' }

+
+ + { planComparisonFeatures.slice( 0, 6 ).map( ( feature ) => ( + + ) ) } + + + { planComparisonFeatures.slice( 6 ).map( ( feature ) => ( ) ) } + + + { /* eslint-disable-next-line wpcalypso/jsx-classname-namespace */ } + + + + + +
); }; diff --git a/client/my-sites/plans/current-plan/index.jsx b/client/my-sites/plans/current-plan/index.jsx index f0090a1ef7886..0553c17de164d 100644 --- a/client/my-sites/plans/current-plan/index.jsx +++ b/client/my-sites/plans/current-plan/index.jsx @@ -18,6 +18,7 @@ import { isManaged, } from '@automattic/calypso-products'; import { Dialog } from '@automattic/components'; +import { Global } from '@emotion/react'; import classNames from 'classnames'; import { localize } from 'i18n-calypso'; import PropTypes from 'prop-types'; @@ -39,7 +40,7 @@ import TrackComponentView from 'calypso/lib/analytics/track-component-view'; import { isCloseToExpiration } from 'calypso/lib/purchases'; import { getPurchaseByProductSlug } from 'calypso/lib/purchases/utils'; import DomainWarnings from 'calypso/my-sites/domains/components/domain-warnings'; -import { isEligibleForManagedPlan } from 'calypso/my-sites/plans-comparison'; +import { globalOverrides, isEligibleForManagedPlan } from 'calypso/my-sites/plans-comparison'; import JetpackChecklist from 'calypso/my-sites/plans/current-plan/jetpack-checklist'; import PlanRenewalMessage from 'calypso/my-sites/plans/jetpack-plans/plan-renewal-message'; import PlansNavigation from 'calypso/my-sites/plans/navigation'; @@ -200,6 +201,7 @@ class CurrentPlan extends Component { return (
+ { eligibleForManagedPlan && } - { selectedSiteId && ( - // key={ selectedSiteId } ensures data is refetched for changing selectedSiteId - - ) } - - - - { shouldQuerySiteDomains && } - - { showThankYou && ! this.state.hideThankYouModal && ( - - { this.renderThankYou() } - - ) } - - - - { showDomainWarnings && ( - - ) } - - { showExpiryNotice && ( - } showDismiss={ false }> - - { translate( 'View plans' ) } - - - ) } - - { showLegacyPlanNotice && ( - - ) } - - - - { showJetpackChecklist && ( - - - - - ) } - -
-

{ planFeaturesHeader }

-
+
+ { selectedSiteId && ( + // key={ selectedSiteId } ensures data is refetched for changing selectedSiteId + + ) } + + + + { shouldQuerySiteDomains && } + + { showThankYou && ! this.state.hideThankYouModal && ( + + { this.renderThankYou() } + + ) } - + + + { showDomainWarnings && ( + + ) } + + { showExpiryNotice && ( + } showDismiss={ false }> + + { translate( 'View plans' ) } + + + ) } - + { showLegacyPlanNotice && ( + + ) } + + + + { showJetpackChecklist && ( + + + + + ) } + + { ! eligibleForManagedPlan && ( + <> +
+

{ planFeaturesHeader }

+
+ + + ) } + +
); } diff --git a/client/my-sites/plans/current-plan/purchases-listing.jsx b/client/my-sites/plans/current-plan/purchases-listing.jsx index b942b791cf143..628f67f2f4e12 100644 --- a/client/my-sites/plans/current-plan/purchases-listing.jsx +++ b/client/my-sites/plans/current-plan/purchases-listing.jsx @@ -34,6 +34,7 @@ import { } from 'calypso/lib/purchases'; import { managePurchase } from 'calypso/me/purchases/paths'; import OwnerInfo from 'calypso/me/purchases/purchase-item/owner-info'; +import { isEligibleForManagedPlan } from 'calypso/my-sites/plans-comparison'; import { getManagePurchaseUrlFor } from 'calypso/my-sites/purchases/paths'; import { getCurrentUserId } from 'calypso/state/current-user/selectors'; import { getSitePurchases } from 'calypso/state/purchases/selectors'; @@ -173,7 +174,7 @@ class PurchasesListing extends Component { } getActionButton( purchase ) { - const { selectedSiteSlug, translate, currentUserId } = this.props; + const { selectedSiteSlug, translate, currentUserId, eligibleForManagedPlan } = this.props; // No action button if there's no site selected. if ( ! selectedSiteSlug || ! purchase ) { @@ -227,7 +228,7 @@ class PurchasesListing extends Component { : '#' } disabled={ ! userIsPurchaseOwner } - compact + compact={ ! eligibleForManagedPlan } > { label }   @@ -333,13 +334,15 @@ class PurchasesListing extends Component { } renderPlan() { - const { currentPlan, isPlanExpiring, translate } = this.props; + const { currentPlan, isPlanExpiring, translate, eligibleForManagedPlan } = this.props; return ( - - { translate( 'My Plan' ) } - + { ! eligibleForManagedPlan && ( + + { translate( 'My Plan' ) } + + ) } { this.isLoading() ? ( ) : ( @@ -423,5 +426,6 @@ export default connect( ( state ) => { selectedSiteSlug: getSelectedSiteSlug( state ), isCloudEligible: isJetpackCloudEligible( state, selectedSiteId ), currentUserId: getCurrentUserId( state ), + eligibleForManagedPlan: isEligibleForManagedPlan( state, selectedSiteId ), }; } )( localize( withLocalizedMoment( PurchasesListing ) ) ); diff --git a/client/my-sites/plans/main.jsx b/client/my-sites/plans/main.jsx index 489b180d415be..c2e5343cd3106 100644 --- a/client/my-sites/plans/main.jsx +++ b/client/my-sites/plans/main.jsx @@ -6,6 +6,7 @@ import { PLAN_WPCOM_MANAGED, PLAN_WPCOM_FLEXIBLE, } from '@automattic/calypso-products'; +import { Global } from '@emotion/react'; import styled from '@emotion/styled'; import { localize } from 'i18n-calypso'; import page from 'page'; @@ -24,7 +25,10 @@ import TrackComponentView from 'calypso/lib/analytics/track-component-view'; import withTrackingTool from 'calypso/lib/analytics/with-tracking-tool'; import { useExperiment } from 'calypso/lib/explat'; import { PerformanceTrackerStop } from 'calypso/lib/performance-tracking'; -import PlansComparison, { isEligibleForManagedPlan } from 'calypso/my-sites/plans-comparison'; +import PlansComparison, { + globalOverrides, + isEligibleForManagedPlan, +} from 'calypso/my-sites/plans-comparison'; import PlansFeaturesMain from 'calypso/my-sites/plans-features-main'; import PlansNavigation from 'calypso/my-sites/plans/navigation'; import P2PlansMain from 'calypso/my-sites/plans/p2-plans-main'; @@ -139,7 +143,7 @@ class Plans extends Component { }; renderPlansMain() { - const { currentPlan, selectedSite, isWPForTeamsSite } = this.props; + const { currentPlan, selectedSite, isWPForTeamsSite, eligibleForManagedPlan } = this.props; if ( ! this.props.plansLoaded || ! currentPlan ) { // Maybe we should show a loading indicator here? @@ -159,7 +163,7 @@ class Plans extends Component { } if ( - this.props.isEligibleForManagedPlan && + eligibleForManagedPlan && [ PLAN_FREE, PLAN_WPCOM_FLEXIBLE, PLAN_WPCOM_MANAGED ].includes( currentPlan?.productSlug ) ) { return ( @@ -192,17 +196,26 @@ class Plans extends Component { } render() { - const { selectedSite, translate, canAccessPlans } = this.props; + const { + selectedSite, + translate, + canAccessPlans, + currentPlan, + eligibleForManagedPlan, + } = this.props; - if ( ! selectedSite || this.isInvalidPlanInterval() ) { + if ( ! selectedSite || this.isInvalidPlanInterval() || ! currentPlan ) { return this.renderPlaceholder(); } - + const description = translate( + 'See and compare the features available on each WordPress.com plan.' + ); return (
{ selectedSite.ID && } + { eligibleForManagedPlan && } @@ -219,9 +232,8 @@ class Plans extends Component {
@@ -255,6 +267,6 @@ export default connect( ( state ) => { isSiteEligibleForMonthlyPlan: isEligibleForWpComMonthlyPlan( state, selectedSiteId ), showTreatmentPlansReorderTest: isTreatmentPlansReorderTest( state ), plansLoaded: Boolean( getPlanSlug( state, getPlan( PLAN_FREE )?.getProductId() || 0 ) ), - isEligibleForManagedPlan: isEligibleForManagedPlan( state, selectedSiteId ), + eligibleForManagedPlan: isEligibleForManagedPlan( state, selectedSiteId ), }; } )( localize( withTrackingTool( 'HotJar' )( Plans ) ) ); diff --git a/client/my-sites/plans/navigation.jsx b/client/my-sites/plans/navigation.jsx index 9e541433c0c48..35c4dd3240d38 100644 --- a/client/my-sites/plans/navigation.jsx +++ b/client/my-sites/plans/navigation.jsx @@ -39,7 +39,13 @@ class PlansNavigation extends Component { } render() { - const { site, shouldShowMyPlan, shouldShowPlans, translate } = this.props; + const { + site, + shouldShowMyPlan, + shouldShowPlans, + translate, + eligibleForManagedPlan, + } = this.props; const path = sectionify( this.props.path ); const sectionTitle = this.getSectionTitle( path ); const hasPinnedItems = isMobile() && site; @@ -63,7 +69,7 @@ class PlansNavigation extends Component { path === '/plans' || path === '/plans/monthly' || path === '/plans/yearly' } > - { translate( 'Plans' ) } + { eligibleForManagedPlan ? translate( 'New Plans' ) : translate( 'Plans' ) } ) } diff --git a/client/signup/steps/plans/index.jsx b/client/signup/steps/plans/index.jsx index 6abf64ec61d83..8e8bd3627a30b 100644 --- a/client/signup/steps/plans/index.jsx +++ b/client/signup/steps/plans/index.jsx @@ -136,6 +136,7 @@ export class PlansStep extends Component { showTreatmentPlansReorderTest, isInVerticalScrollingPlansExperiment, isReskinned, + eligibleForManagedPlan, } = this.props; let errorDisplay; @@ -153,7 +154,7 @@ export class PlansStep extends Component { return this.renderLoading(); } - if ( this.props.isEligibleForManagedPlan ) { + if ( eligibleForManagedPlan ) { return (
{ errorDisplay } @@ -278,7 +279,11 @@ export class PlansStep extends Component { } getHeaderText() { - const { headerText, translate } = this.props; + const { headerText, translate, eligibleForManagedPlan } = this.props; + + if ( eligibleForManagedPlan ) { + return translate( 'Managed WordPress made just for you' ); + } if ( this.state.isDesktop ) { return translate( 'Choose a plan' ); @@ -288,9 +293,13 @@ export class PlansStep extends Component { } getSubHeaderText() { - const { hideFreePlan, subHeaderText, translate } = this.props; + const { hideFreePlan, subHeaderText, translate, eligibleForManagedPlan } = this.props; + + if ( eligibleForManagedPlan ) { + return translate( 'Try risk-free with a 14-day money back guarantee' ); + } - if ( ! hideFreePlan && ! this.props.isEligibleForManagedPlan ) { + if ( ! hideFreePlan ) { if ( this.state.isDesktop ) { return translate( "Pick one that's right for you and unlock features that help you grow. Or {{link}}start with a free site{{/link}}.", @@ -447,10 +456,7 @@ export default connect( // treatment for the `vertical_plan_listing_v2` experiment is implemented. isInVerticalScrollingPlansExperiment: true, plansLoaded: Boolean( getPlanSlug( state, getPlan( PLAN_FREE )?.getProductId() || 0 ) ), - isEligibleForManagedPlan: isEligibleForManagedPlan( - state, - getSiteBySlug( state, siteSlug )?.ID - ), + eligibleForManagedPlan: isEligibleForManagedPlan( state, getSiteBySlug( state, siteSlug )?.ID ), } ), { recordTracksEvent, saveSignupStep, submitSignupStep } )( localize( PlansStep ) ); diff --git a/packages/calypso-products/src/plans-list.tsx b/packages/calypso-products/src/plans-list.tsx index 5aea166f8c19b..3bfe4ac9bd15a 100644 --- a/packages/calypso-products/src/plans-list.tsx +++ b/packages/calypso-products/src/plans-list.tsx @@ -1619,5 +1619,7 @@ PLANS_LIST[ PLAN_WPCOM_MANAGED ] = { FEATURE_NO_ADS, FEATURE_SFTP_DATABASE, FEATURE_SITE_BACKUPS_AND_RESTORE, + FEATURE_PREMIUM_THEMES, + FEATURE_CUSTOM_DOMAIN, ], };