From 81e9177a17d410c28b914afafe3d0cb8f02fc802 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 24 Nov 2020 14:47:52 -0500 Subject: [PATCH 01/30] Create ghostery-search promo in plan view --- _locales/en/messages.json | 15 ++++++ app/hub/Views/PlanView/PlanView.jsx | 53 ++++++++++++++++++ app/hub/Views/PlanView/PlanView.scss | 81 ++++++++++++++++++++++++++++ app/hub/Views/PlanView/index.jsx | 35 ++++++++++++ app/hub/index.jsx | 3 +- app/images/hub/PlanView/search.svg | 1 + app/scss/hub.scss | 1 + 7 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 app/hub/Views/PlanView/PlanView.jsx create mode 100644 app/hub/Views/PlanView/PlanView.scss create mode 100644 app/hub/Views/PlanView/index.jsx create mode 100644 app/images/hub/PlanView/search.svg diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 041d0b141..bc8d65ba6 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1734,6 +1734,21 @@ "hub_create_account_toast_error": { "message": "That email address is already in use. Please choose another." }, + "hub_plan_view_your_privacy_plan": { + "message": "Your Privacy Plan" + }, + "hub_plan_view_based_on_your_privacy_preferences": { + "message": "Based on your privacy preferences" + }, + "hub_plan_view_ad_free": { + "message": "Ad-free with Ghostery Plus subscription" + }, + "hub_plan_view_ad_free_promo": { + "message": "40% off for the first 12 months" + }, + "hub_plan_view_ad_free_promo_description": { + "message": "Get to what you want faster. A plus subscription gives Ghostery the support we need to provide YOU with an ad-free experience." + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx new file mode 100644 index 000000000..9f35091ea --- /dev/null +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -0,0 +1,53 @@ +/** + * Plan View Component + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2020 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React, { Fragment, useRef, useEffect } from 'react'; +import ClassNames from 'classnames'; +import PropTypes from 'prop-types'; +import { NavLink } from 'react-router-dom'; +import QueryString from 'query-string'; +// import { BASIC, PLUS, PREMIUM } from './UpgradePlanViewConstants'; +import globals from '../../../../src/classes/Globals'; + +const searchPromo = () => ( +
+
+
{ t('hub_plan_view_ad_free') }
+
{ t('hub_plan_view_ad_free_promo') }
+
{ t('hub_plan_view_ad_free_promo_description') }
+
+); + +const startTrialButton = () => ( +
Start Trial
+); + +const PlanView = () => { + const test = 5; + return ( +
+
{ t('hub_plan_view_your_privacy_plan') }
+
{ t('hub_plan_view_based_on_your_privacy_preferences') }
+ {searchPromo()} + {startTrialButton()} +
+ ); +}; + +// PropTypes ensure we pass required props of the correct type +PlanView.propTypes = {}; + +// Default props used on the Home View +PlanView.defaultProps = {}; + +export default PlanView; diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss new file mode 100644 index 000000000..d37140926 --- /dev/null +++ b/app/hub/Views/PlanView/PlanView.scss @@ -0,0 +1,81 @@ +.PlanView__yourPrivacyPlan { + margin: auto; + font-size: 24px; + display: flex; + justify-content: center; +} + +.PlanView__subtitle { + margin-top: 12px; + display: flex; + justify-content: center; + font-size: 18px; +} +.PlanView__searchPromoContainer { + width: 354px; + height: 381px; + margin: 48px auto 0 auto; + border-radius: 4px; + border: solid 4px #00aef0; +} + +.PlanView__searchLogo { + height: 37px; + width: 193px; + margin: 65px auto 0 auto; + background-image: url('/app/images/hub/PlanView/search.svg'); +} + +.PlanView__adFree { + margin: 16px auto 0 auto; + color: #b8860b; + font-size: 18px; + line-height: 32px; + font-weight: 600; + width: 220px; + text-align: center; +} + +.PlanView__adFreePromo { + margin: auto; + font-size: 18px; + line-height: 32px; + text-align: center; +} + +.PlanView__adFreePromoDescription { + margin: 16px auto 0 auto; + height: 88px; + width: 250px; + font-size: 16px; + line-height: 1.38; + text-align: center; + color: #4a4a4a; +} + +.PlanView__searchCTAButton { + margin: 48px auto 0 auto; + height: 44px; + width: 162px; + padding: 7.7px 14px; + line-height: 22px; + background: linear-gradient( + 45deg, + #ff7e74 50%, + #00aef0 + ); + background-size: 200% 100%; + background-position: 100% 50%; + transition: 0.25s all; + border: none; + &:hover { + background-position: 0% 50%; + transition: 0.25s all; + } + color: #FFF; + font-size: 14.1px; + font-weight: 700; + border-radius: 3.5px; + text-align: center; + line-height: 2.05; +} diff --git a/app/hub/Views/PlanView/index.jsx b/app/hub/Views/PlanView/index.jsx new file mode 100644 index 000000000..c58368caa --- /dev/null +++ b/app/hub/Views/PlanView/index.jsx @@ -0,0 +1,35 @@ +/** + * Point of entry index.js file for PlanView + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2020 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom'; + +import PlanView from './PlanView'; + +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => ({ ...state.upgrade, ...state.account }); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof SetupContainers + */ +const mapDispatchToProps = dispatch => ({}); + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PlanView)); diff --git a/app/hub/index.jsx b/app/hub/index.jsx index 7e3a19a3c..5177d2044 100644 --- a/app/hub/index.jsx +++ b/app/hub/index.jsx @@ -31,6 +31,7 @@ import CreateAccountView from './Views/CreateAccountView'; import ForgotPasswordView from '../shared-components/ForgotPassword/ForgotPasswordContainer'; import LogInView from './Views/LogInView'; import UpgradePlanView from './Views/UpgradePlanView'; +import PlanView from './Views/PlanView'; const store = createStore(); @@ -43,7 +44,7 @@ const ah = (QueryString.parse(window.location.search).ah === 'true') || false; */ const Hub = () => ( - + diff --git a/app/images/hub/PlanView/search.svg b/app/images/hub/PlanView/search.svg new file mode 100644 index 000000000..1c52a8174 --- /dev/null +++ b/app/images/hub/PlanView/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/scss/hub.scss b/app/scss/hub.scss index 759692615..96231b297 100644 --- a/app/scss/hub.scss +++ b/app/scss/hub.scss @@ -86,6 +86,7 @@ html, body, #root { @import '../hub/Views/LogInView/LogInView.scss'; @import '../hub/Views/CreateAccountView/CreateAccountView.scss'; @import '../hub/Views/UpgradePlanView/UpgradePlanView.scss'; +@import '../hub/Views/PlanView/PlanView.scss'; // Imports from ../shared-components directory @import '../shared-components/ExitButton/ExitButton.scss'; From 0a36f469232771f0084c936702b19d94eba7e7d1 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 24 Nov 2020 15:21:14 -0500 Subject: [PATCH 02/30] Add scroll arrow and cards --- _locales/en/messages.json | 3 + app/hub/Views/PlanView/PlanView.jsx | 100 +++++++++++++++++++++++++-- app/hub/Views/PlanView/PlanView.scss | 25 +++++++ 3 files changed, 123 insertions(+), 5 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index bc8d65ba6..605ebe342 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1749,6 +1749,9 @@ "hub_plan_view_ad_free_promo_description": { "message": "Get to what you want faster. A plus subscription gives Ghostery the support we need to provide YOU with an ad-free experience." }, + "hub_plan_view_see_all_plans": { + "message": "See all plans" + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 9f35091ea..8e477e861 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -16,7 +16,6 @@ import ClassNames from 'classnames'; import PropTypes from 'prop-types'; import { NavLink } from 'react-router-dom'; import QueryString from 'query-string'; -// import { BASIC, PLUS, PREMIUM } from './UpgradePlanViewConstants'; import globals from '../../../../src/classes/Globals'; const searchPromo = () => ( @@ -28,18 +27,109 @@ const searchPromo = () => (
); -const startTrialButton = () => ( -
Start Trial
+const basicCard = () => ( +
+
+
+
+
+
+

Ghostery

+
+

{t('hub_upgrade_plan_free')}

+
+ + {t('hub_upgrade_already_protected')} + +

{t('hub_upgrade_basic_protection')}

+

+ + {t('hub_upgrade_basic_browser_protection')} +

+
+
+); + +const plusCard = mobileView => ( +
+
+
+
+
+

Ghostery Plus

+
+ +

$4.99

+

{t('per_month')}

+
+
+ {/* {plusButtonTop()} */} +

{t('hub_upgrade_additional_protection')}

+

+ + {t('hub_upgrade_basic_browser_protection')} +

+

+ + {t('hub_upgrade_advanced_device_protection')} +

+
+
+); + +const premiumCard = mobileView => ( +
+
+
+
+
+
+

Ghostery Premium

+
+ +

$11.99

+

{t('per_month')}

+
+
+ {/* {premiumButtonTop()} */} +

+ {t('hub_upgrade_maximum_browser_protection')} +

+

+ + {t('hub_upgrade_basic_browser_protection')} +

+

+ + {t('hub_upgrade_advanced_device_protection')} +

+

+ + VPN +

+
+
); const PlanView = () => { - const test = 5; + // Clicking arrow scrolls to Plans + const plansRef = useRef(null); + const scrollToPlans = () => { + plansRef.current.scrollIntoView({ behavior: 'smooth' }); + }; return (
{ t('hub_plan_view_your_privacy_plan') }
{ t('hub_plan_view_based_on_your_privacy_preferences') }
{searchPromo()} - {startTrialButton()} +
Start Trial
+
{t('hub_plan_view_see_all_plans')}
+
+
+ {basicCard()} + {plusCard()} + {premiumCard()} +
); }; diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index d37140926..d051e3fa2 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -78,4 +78,29 @@ border-radius: 3.5px; text-align: center; line-height: 2.05; + cursor: pointer; +} + +.PlanView__seeAllPlans { + margin-top: 48px; + display: flex; + justify-content: center; + color: #00aef0; + font-size: 16px; + text-decoration: underline; + cursor: pointer; +} + +.PlanView__plansContainer { + margin-top: 100px; +} + +.PlanView__arrowDown { + margin: 15px auto 0 auto; + height: 12px; + width: 12px; + transform: rotate(45deg); + border-left: 2px solid #00aef0; + border-top: 2px solid #00aef0; + cursor: pointer; } From 6e38e7c68b2725d3b39a4b1eac71eb7b609fb5cd Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 25 Nov 2020 08:59:09 -0500 Subject: [PATCH 03/30] Add value prop list to cards --- _locales/en/messages.json | 39 ++++- app/hub/Views/PlanView/PlanView.jsx | 154 +++++++++++++------- app/hub/Views/PlanView/PlanView.scss | 209 +++++++++++++++++++++++++++ 3 files changed, 341 insertions(+), 61 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 605ebe342..68121d43d 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1366,6 +1366,9 @@ "hub_upgrade_additional_protection": { "message": "Additional Protection" }, + "hub_upgrade_maximum_protection": { + "message": "Maximum Protection" + }, "hub_upgrade_browser_tracker_blocking": { "message": "Browser Tracker Blocking" }, @@ -1734,24 +1737,48 @@ "hub_create_account_toast_error": { "message": "That email address is already in use. Please choose another." }, - "hub_plan_view_your_privacy_plan": { + "hub_plan_your_privacy_plan": { "message": "Your Privacy Plan" }, - "hub_plan_view_based_on_your_privacy_preferences": { + "hub_plan_based_on_your_privacy_preferences": { "message": "Based on your privacy preferences" }, - "hub_plan_view_ad_free": { + "hub_plan_ad_free_with_ghostery_plus_subscription": { "message": "Ad-free with Ghostery Plus subscription" }, - "hub_plan_view_ad_free_promo": { + "hub_plan_ad_free_promo": { "message": "40% off for the first 12 months" }, - "hub_plan_view_ad_free_promo_description": { + "hub_plan_ad_free_promo_description": { "message": "Get to what you want faster. A plus subscription gives Ghostery the support we need to provide YOU with an ad-free experience." }, - "hub_plan_view_see_all_plans": { + "hub_plan_start_trial": { + "message": "Start Trial" + }, + "hub_plan_see_all_plans": { "message": "See all plans" }, + "hub_plan_private_search": { + "message": "Private search" + }, + "hub_plan_tracker_protection": { + "message": "Tracker protection" + }, + "hub_plan_speedy_page_loads": { + "message": "Speedy page loads" + }, + "hub_plan_intelligence_technology": { + "message": "Intelligence technology" + }, + "hub_plan_ad_free": { + "message": "Ad free" + }, + "hub_plan_supports_ghosterys_mission": { + "message": "Supports Ghostery's Mission" + }, + "hub_plan_unlimited_bandwidth": { + "message": "Unlimited Bandwidth" + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 8e477e861..85cfe4670 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -21,92 +21,135 @@ import globals from '../../../../src/classes/Globals'; const searchPromo = () => (
-
{ t('hub_plan_view_ad_free') }
-
{ t('hub_plan_view_ad_free_promo') }
-
{ t('hub_plan_view_ad_free_promo_description') }
+
{ t('hub_plan_ad_free_with_ghostery_plus_subscription') }
+
{ t('hub_plan_ad_free_promo') }
+
{ t('hub_plan_ad_free_promo_description') }
); const basicCard = () => ( -
-
+
+

Ghostery

-
-

{t('hub_upgrade_plan_free')}

+
+

{t('hub_upgrade_plan_free')}

- - {t('hub_upgrade_already_protected')} -

{t('hub_upgrade_basic_protection')}

-

- - {t('hub_upgrade_basic_browser_protection')} -

+
+
+ {t('hub_plan_private_search')} +
+
+ {t('hub_plan_tracker_protection')} +
+
+ {t('hub_plan_speedy_page_loads')} +
+
+ {t('hub_plan_intelligence_technology')} +
+
); -const plusCard = mobileView => ( -
-
+const plusCard = () => ( +
+

Ghostery Plus

-
+
-

$4.99

-

{t('per_month')}

+

$4.99

+

{t('per_month')}

- {/* {plusButtonTop()} */}

{t('hub_upgrade_additional_protection')}

-

- - {t('hub_upgrade_basic_browser_protection')} -

-

- - {t('hub_upgrade_advanced_device_protection')} -

+
+
+ + {t('hub_plan_private_search')} +
+
+ + {t('hub_plan_tracker_protection')} +
+
+ + {t('hub_plan_speedy_page_loads')} +
+
+ + {t('hub_plan_intelligence_technology')} +
+
+ + {t('hub_plan_ad_free')} +
+
+ + {t('hub_plan_supports_ghosterys_mission')} +
+
); -const premiumCard = mobileView => ( -
-
+const premiumCard = () => ( +
+

Ghostery Premium

-
+
-

$11.99

-

{t('per_month')}

+

$11.99

+

{t('per_month')}

- {/* {premiumButtonTop()} */} -

- {t('hub_upgrade_maximum_browser_protection')} -

-

- - {t('hub_upgrade_basic_browser_protection')} -

-

- - {t('hub_upgrade_advanced_device_protection')} -

-

- - VPN -

+

{t('hub_upgrade_maximum_protection')}

+
+
+ + {t('hub_plan_private_search')} +
+
+ + {t('hub_plan_tracker_protection')} +
+
+ + {t('hub_plan_speedy_page_loads')} +
+
+ + {t('hub_plan_intelligence_technology')} +
+
+ + {t('hub_plan_ad_free')} +
+
+ + {t('hub_plan_supports_ghosterys_mission')} +
+
+ + VPN +
+
+ + {t('hub_plan_unlimited_bandwidth')} +
+
); @@ -119,17 +162,18 @@ const PlanView = () => { }; return (
-
{ t('hub_plan_view_your_privacy_plan') }
-
{ t('hub_plan_view_based_on_your_privacy_preferences') }
+
{ t('hub_plan_your_privacy_plan') }
+
{ t('hub_plan_based_on_your_privacy_preferences') }
{searchPromo()} -
Start Trial
-
{t('hub_plan_view_see_all_plans')}
+
{t('hub_plan_start_trial')}
+
{t('hub_plan_see_all_plans')}
{basicCard()} {plusCard()} {premiumCard()}
+
{t('hub_plan_start_trial')}
); }; diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index d051e3fa2..f9f7d5068 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -93,6 +93,8 @@ .PlanView__plansContainer { margin-top: 100px; + display: flex; + justify-content: center; } .PlanView__arrowDown { @@ -104,3 +106,210 @@ border-top: 2px solid #00aef0; cursor: pointer; } + +.PlanView__cardOuter { + flex-shrink: 3; + padding: 0 20px; + &-remove { + @include breakpoint(large up) { + padding-right: 0; + } + @include breakpoint($medium-large-breakpoint down) { + margin-top: rem-calc(90); + } + } +} + +// Clean up unused CSS +.PlanView__card { + padding-top: 150px; + height: 670px; + box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.5); + margin-bottom: rem-calc(40); + width: 250px; + margin-left: auto; + margin-right: auto; + text-align: center; + // padding-top: rem-calc(3); + padding-bottom: rem-calc(40); + @include breakpoint($medium-large-breakpoint down) { + box-shadow: none; + height: 425px; + } + + @include breakpoint($medium-large-breakpoint down) { + &.basic { + height: 400px; + } + &.plus { + height: 498px; + } + &.premium { + height: 526px; + } + } + h2 { + color: $tundora; + font-family: "Roboto Condensed"; + font-size: 18px; + font-weight: 400; + margin-top: 22px; + margin-bottom: 6px; + } + &-image-top { + margin-top: -76px; + width: 100%; + } + &-sub-header { + margin-bottom: rem-calc(15); + } + &-sub-copy { + display: flex; + align-items: center; + font-size: rem-calc(12); + margin-bottom: 8px; + text-align: left; + padding-left: rem-calc(35); + img { + padding-right: 10px; + } + } + .ghostery-free-image-container { + margin-top: -3px; + width: 250px; + height: 85px; + background-color: rgba(0, 174, 240, .25); + display: flex; + justify-content: center; + align-items: center; + @include breakpoint($medium-large-breakpoint down) { + background-color: #FFF; + } + .ghostery-free-image { + width: 55px; + height: 65px; + background-image: url('/app/images/hub/upgrade/ghostery-basic-card.svg'); + background-repeat: no-repeat; + background-position: center; + } + } + .ghostery-plus-image-container { + margin-top: -3px; + width: 250px; + height: 85px; + background-image: linear-gradient(to right, rgba(240,174,133,.25), rgba(241,216,158,.25)); + @include breakpoint($medium-large-breakpoint down) { + background-image: none; + background-color: #FFF; + } + .ghostery-plus-image { + margin: auto; + width: 225px; + height: 87px; + background-image: url('/app/images/hub/upgrade/ghostery-plus-card.svg') + } + } + .ghostery-premium-image-container { + position: relative; + } + .ghostery-premium-image { + position: absolute; + margin-top: -79px; + margin-left: 9px; + width: 233px; + height: 161px; + background-image: url('/app/images/hub/upgrade/ghostery-premium-card.svg'); + } + .ghostery-premium-image-background { + margin-top: -3px; + width: 250px; + height: 85px; + background-image: linear-gradient(to right, rgba(113,1,116,.25), rgba(90,37,142,.25) 18%, rgba(42,110,194,.25) 57%, rgba(12,156,227,.25) 86%, rgba(0,174,240,.25)); + @include breakpoint($medium-large-breakpoint down) { + background-image: none; + } + } + .button { + margin-top: 10px; + margin-bottom: rem-calc(20); + text-transform: none; + height: 38px; + line-height: 22px; + &.already-protected { + @include breakpoint($medium-large-breakpoint down) { + margin-top: 45px; + } + } + } + .card-sub-header { + font-size: 14px; + } +} + +.PlanView__price { + min-height: 85px; + margin-bottom: rem-calc(20); + &-blue { + color: $price-blue; + } + &-blue-alt { + color: $blue-alt; + } + &-gold { + color: $price-gold; + } + &-purple { + color: $price-purple; + } + p { + margin-bottom: 0; + @include breakpoint($medium-large-breakpoint down) { + &.sub-text:first-child { + margin-top: 4px; + } + } + &.sub-text { + font-weight: 500; + } + } + .price-per-year { + position: relative; + width: 100%; + p { + position: absolute; + width: 100%; + } + } +} + + +.PlanView__valuePropList { + margin: auto; + width: 174px; + + &.basic { + width: 124px; + } +} +.PlanView__cardSubCopy { + display: flex; + justify-content: flex-start; + margin-bottom: 5px; +} + +.check { + display: inline-block; + width: 20px; + height: 20px; + background-repeat: no-repeat; + margin-top: 3px; + &.blue { + background-image: buildCheckIcon($price-blue); + } + &.yellow { + background-image: buildCheckIcon($price-gold); + } + &.purple { + background-image: buildCheckIcon($price-purple); + } +} From 890315db37c72d83474750500157ec5309b7c911 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 29 Nov 2020 19:20:49 -0500 Subject: [PATCH 04/30] Add radio button and hover effects to cards --- app/hub/Views/PlanView/PlanView.jsx | 327 ++++++++++++++++----------- app/hub/Views/PlanView/PlanView.scss | 40 +++- app/scss/hub.scss | 1 + 3 files changed, 229 insertions(+), 139 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 85cfe4670..5a16526e5 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -17,6 +17,11 @@ import PropTypes from 'prop-types'; import { NavLink } from 'react-router-dom'; import QueryString from 'query-string'; import globals from '../../../../src/classes/Globals'; +import RadioButton from '../../../panel/components/BuildingBlocks/RadioButton'; + +const BASIC = 0; +const PLUS = 1; +const PREMIUM = 2; const searchPromo = () => (
@@ -27,156 +32,210 @@ const searchPromo = () => (
); -const basicCard = () => ( -
-
-
-
-
-
-

Ghostery

-
-

{t('hub_upgrade_plan_free')}

-
-

{t('hub_upgrade_basic_protection')}

-
-
- {t('hub_plan_private_search')} -
-
- {t('hub_plan_tracker_protection')} -
-
- {t('hub_plan_speedy_page_loads')} -
-
- {t('hub_plan_intelligence_technology')} +const basicCard = (checked, handleClick) => { + const cardClassNames = ClassNames('PlanView__card basic', { + checked + }); + return ( +
+
+
+ +
+
+
+
+
+

Ghostery

+
+

{t('hub_upgrade_plan_free')}

+
+

{t('hub_upgrade_basic_protection')}

+
+
+ {t('hub_plan_private_search')} +
+
+ {t('hub_plan_tracker_protection')} +
+
+ {t('hub_plan_speedy_page_loads')} +
+
+ {t('hub_plan_intelligence_technology')} +
-
-); + ); +}; -const plusCard = () => ( -
-
-
-
-
-

Ghostery Plus

-
- -

$4.99

-

{t('per_month')}

-
-
-

{t('hub_upgrade_additional_protection')}

-
-
- - {t('hub_plan_private_search')} -
-
- - {t('hub_plan_tracker_protection')} -
-
- - {t('hub_plan_speedy_page_loads')} -
-
- - {t('hub_plan_intelligence_technology')} -
-
- - {t('hub_plan_ad_free')} -
-
- - {t('hub_plan_supports_ghosterys_mission')} +const plusCard = (checked, handleClick) => { + const cardClassNames = ClassNames('PlanView__card plus', { + checked + }); + return ( +
+
+
+ +
+
+
+
+

Ghostery Plus

+
+ +

$4.99

+

{t('per_month')}

+
+
+

{t('hub_upgrade_additional_protection')}

+
+
+ + {t('hub_plan_private_search')} +
+
+ + {t('hub_plan_tracker_protection')} +
+
+ + {t('hub_plan_speedy_page_loads')} +
+
+ + {t('hub_plan_intelligence_technology')} +
+
+ + {t('hub_plan_ad_free')} +
+
+ + {t('hub_plan_supports_ghosterys_mission')} +
-
-); + ); +}; -const premiumCard = () => ( -
-
-
-
-
-
-

Ghostery Premium

-
- -

$11.99

-

{t('per_month')}

-
-
-

{t('hub_upgrade_maximum_protection')}

-
-
- - {t('hub_plan_private_search')} -
-
- - {t('hub_plan_tracker_protection')} -
-
- - {t('hub_plan_speedy_page_loads')} -
-
- - {t('hub_plan_intelligence_technology')} -
-
- - {t('hub_plan_ad_free')} -
-
- - {t('hub_plan_supports_ghosterys_mission')} -
-
- +const premiumCard = (checked, handleClick) => { + const cardClassNames = ClassNames('PlanView__card premium', { + checked + }); + return ( +
+
+
+ +
+
+
+
+
+

Ghostery Premium

+
+ +

$11.99

+

{t('per_month')}

+
+
+

{t('hub_upgrade_maximum_protection')}

+
+
+ + {t('hub_plan_private_search')} +
+
+ + {t('hub_plan_tracker_protection')} +
+
+ + {t('hub_plan_speedy_page_loads')} +
+
+ + {t('hub_plan_intelligence_technology')} +
+
+ + {t('hub_plan_ad_free')} +
+
+ + {t('hub_plan_supports_ghosterys_mission')} +
+
+ VPN
-
- - {t('hub_plan_unlimited_bandwidth')} +
+ + {t('hub_plan_unlimited_bandwidth')} +
-
-); + ) +}; -const PlanView = () => { - // Clicking arrow scrolls to Plans - const plansRef = useRef(null); - const scrollToPlans = () => { - plansRef.current.scrollIntoView({ behavior: 'smooth' }); +class PlanView extends React.Component { + constructor(props) { + super(props); + this.state = { + selectedPlan: 0 + }; + this.plansRef = React.createRef(); + } + + isBasicPlanChecked = () => { + const { selectedPlan } = this.state; + return (selectedPlan === BASIC); }; - return ( -
-
{ t('hub_plan_your_privacy_plan') }
-
{ t('hub_plan_based_on_your_privacy_preferences') }
- {searchPromo()} -
{t('hub_plan_start_trial')}
-
{t('hub_plan_see_all_plans')}
-
-
- {basicCard()} - {plusCard()} - {premiumCard()} + + isPlusPlanChecked = () => { + const { selectedPlan } = this.state; + return (selectedPlan === PLUS); + }; + + isPremiumPlanChecked = () => { + const { selectedPlan } = this.state; + return (selectedPlan === PREMIUM); + }; + + selectBasicPlan = () => this.setState({ selectedPlan: BASIC }); + + selectPlusPlan = () => this.setState({ selectedPlan: PLUS }); + + selectPremiumPlan = () => this.setState({ selectedPlan: PREMIUM }); + + scrollToPlans = () => { + this.plansRef.current.scrollIntoView({ behavior: 'smooth' }); + }; + + render() { + return ( +
+
{t('hub_plan_your_privacy_plan')}
+
{t('hub_plan_based_on_your_privacy_preferences')}
+ {searchPromo()} +
{t('hub_plan_start_trial')}
+
{t('hub_plan_see_all_plans')}
+
+
+ {basicCard(this.isBasicPlanChecked(), this.selectBasicPlan)} + {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan)} + {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)} +
+
{t('hub_plan_start_trial')}
-
{t('hub_plan_start_trial')}
-
- ); -}; + ); + } +} // PropTypes ensure we pass required props of the correct type PlanView.propTypes = {}; diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index f9f7d5068..85d3153a4 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -110,6 +110,7 @@ .PlanView__cardOuter { flex-shrink: 3; padding: 0 20px; + &-remove { @include breakpoint(large up) { padding-right: 0; @@ -122,7 +123,6 @@ // Clean up unused CSS .PlanView__card { - padding-top: 150px; height: 670px; box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.5); margin-bottom: rem-calc(40); @@ -130,8 +130,29 @@ margin-left: auto; margin-right: auto; text-align: center; - // padding-top: rem-calc(3); padding-bottom: rem-calc(40); + border: 4px solid white; + + .checked { + border: 4px solid #00aef0; + .ghostery-free-image-container, + .ghostery-plus-image-container, + .ghostery-premium-image-background { + width: 244px; + margin-left: -1px; + } + } + + &:hover { + border: 4px solid #00aef0; + .ghostery-free-image-container, + .ghostery-plus-image-container, + .ghostery-premium-image-background { + width: 244px; + margin-left: -1px; + } + } + @include breakpoint($medium-large-breakpoint down) { box-shadow: none; height: 425px; @@ -175,13 +196,14 @@ } } .ghostery-free-image-container { - margin-top: -3px; + margin: -3px 0 0 -4px; width: 250px; height: 85px; background-color: rgba(0, 174, 240, .25); display: flex; justify-content: center; align-items: center; + @include breakpoint($medium-large-breakpoint down) { background-color: #FFF; } @@ -194,7 +216,7 @@ } } .ghostery-plus-image-container { - margin-top: -3px; + margin: -3px 0 0 -4px; width: 250px; height: 85px; background-image: linear-gradient(to right, rgba(240,174,133,.25), rgba(241,216,158,.25)); @@ -210,6 +232,7 @@ } } .ghostery-premium-image-container { + margin-left: -4px; position: relative; } .ghostery-premium-image { @@ -221,7 +244,7 @@ background-image: url('/app/images/hub/upgrade/ghostery-premium-card.svg'); } .ghostery-premium-image-background { - margin-top: -3px; + margin: -3px 0 0 -4px; width: 250px; height: 85px; background-image: linear-gradient(to right, rgba(113,1,116,.25), rgba(90,37,142,.25) 18%, rgba(42,110,194,.25) 57%, rgba(12,156,227,.25) 86%, rgba(0,174,240,.25)); @@ -313,3 +336,10 @@ background-image: buildCheckIcon($price-purple); } } + +.PlanView__radioButtonContainer { + padding: 11px; + margin-bottom: 84px; + display: flex; + justify-content: center; +} diff --git a/app/scss/hub.scss b/app/scss/hub.scss index 96231b297..0ab177d73 100644 --- a/app/scss/hub.scss +++ b/app/scss/hub.scss @@ -97,3 +97,4 @@ html, body, #root { @import '../shared-components/ToggleCheckbox/ToggleCheckbox.scss'; @import '../shared-components/ToggleSwitch/ToggleSwitch.scss'; @import '../shared-components/ForgotPassword/ForgotPassword.scss'; +@import './partials/radio_button'; From c475484cc46ecbfde6419e8d56fd998826de22e9 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 29 Nov 2020 19:25:04 -0500 Subject: [PATCH 05/30] Add click handler to full card, not only radio button --- app/hub/Views/PlanView/PlanView.jsx | 12 ++++++------ app/hub/Views/PlanView/PlanView.scss | 12 +----------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 5a16526e5..62ae66cc3 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -38,7 +38,7 @@ const basicCard = (checked, handleClick) => { }); return (
-
+
@@ -76,7 +76,7 @@ const plusCard = (checked, handleClick) => { }); return (
-
+
@@ -128,7 +128,7 @@ const premiumCard = (checked, handleClick) => { }); return (
-
+
@@ -171,8 +171,8 @@ const premiumCard = (checked, handleClick) => {
- VPN -
+ VPN +
{t('hub_plan_unlimited_bandwidth')} @@ -180,7 +180,7 @@ const premiumCard = (checked, handleClick) => {
- ) + ); }; class PlanView extends React.Component { diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index 85d3153a4..39e1acf02 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -133,17 +133,7 @@ padding-bottom: rem-calc(40); border: 4px solid white; - .checked { - border: 4px solid #00aef0; - .ghostery-free-image-container, - .ghostery-plus-image-container, - .ghostery-premium-image-background { - width: 244px; - margin-left: -1px; - } - } - - &:hover { + &:hover, &.checked { border: 4px solid #00aef0; .ghostery-free-image-container, .ghostery-plus-image-container, From 81bf43638ba66ca50555bbe841d7042d33796650 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 29 Nov 2020 21:03:37 -0500 Subject: [PATCH 06/30] Select default plan depending on current plan --- app/hub/Views/PlanView/PlanView.jsx | 53 ++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 62ae66cc3..6fa999147 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -11,12 +11,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -import React, { Fragment, useRef, useEffect } from 'react'; +import React, { Fragment } from 'react'; import ClassNames from 'classnames'; import PropTypes from 'prop-types'; -import { NavLink } from 'react-router-dom'; -import QueryString from 'query-string'; -import globals from '../../../../src/classes/Globals'; import RadioButton from '../../../panel/components/BuildingBlocks/RadioButton'; const BASIC = 0; @@ -38,7 +35,7 @@ const basicCard = (checked, handleClick) => { }); return (
-
+
@@ -187,9 +184,26 @@ class PlanView extends React.Component { constructor(props) { super(props); this.state = { - selectedPlan: 0 + selectedPlan: -1 }; this.plansRef = React.createRef(); + setTimeout(this.setDefaultPlan, 200); + } + + setDefaultPlan = () => { + const { user } = this.props; + const isPlus = (user && user.plusAccess) || false; + const isPremium = (user && user.premiumAccess) || false; + + if (isPremium) { + this.selectPremiumPlan(); + return; + } + if (isPlus) { + this.selectPlusPlan(); + return; + } + this.selectBasicPlan(); } isBasicPlanChecked = () => { @@ -217,18 +231,33 @@ class PlanView extends React.Component { this.plansRef.current.scrollIntoView({ behavior: 'smooth' }); }; + renderTitleText = () => false; + render() { + const shouldShowSearchPromo = false; + const { user } = this.props; + const isPlus = (user && user.plusAccess) || false; + const isPremium = (user && user.premiumAccess) || false; + return (
{t('hub_plan_your_privacy_plan')}
{t('hub_plan_based_on_your_privacy_preferences')}
- {searchPromo()} -
{t('hub_plan_start_trial')}
-
{t('hub_plan_see_all_plans')}
-
+ {shouldShowSearchPromo && ( + + {searchPromo()} +
{t('hub_plan_start_trial')}
+
{t('hub_plan_see_all_plans')}
+
+ + )}
- {basicCard(this.isBasicPlanChecked(), this.selectBasicPlan)} - {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan)} + {!(isPlus || isPremium) && ( + basicCard(this.isBasicPlanChecked(), this.selectBasicPlan) + )} + {!isPremium && ( + plusCard(this.isPlusPlanChecked(), this.selectPlusPlan) + )} {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)}
{t('hub_plan_start_trial')}
From 3609b8e340bcc729a7a2e0128449928691e7b35a Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 29 Nov 2020 21:46:31 -0500 Subject: [PATCH 07/30] Add logic to display title and subtitle texts --- _locales/en/messages.json | 12 ++++++++++++ app/hub/Views/PlanView/PlanView.jsx | 25 ++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 68121d43d..bc686ea7e 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1779,6 +1779,18 @@ "hub_plan_unlimited_bandwidth": { "message": "Unlimited Bandwidth" }, + "hub_plan_already_premium_subscriber": { + "message": "You are already a premium subscriber" + }, + "hub_plan_already_plus_subscriber": { + "message": "You are already a plus subscriber" + }, + "hub_plan_keep_your_current_plan_or_upgrade": { + "message": "Keep your current plan or upgrade" + }, + "hub_plan_choose_an_option": { + "message": "Choose an option" + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 6fa999147..02db11cfb 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -231,7 +231,26 @@ class PlanView extends React.Component { this.plansRef.current.scrollIntoView({ behavior: 'smooth' }); }; - renderTitleText = () => false; + renderTitleText = () => { + const { user } = this.props; + const isPlus = (user && user.plusAccess) || false; + const isPremium = (user && user.premiumAccess) || false; + + if (isPremium) return t('hub_plan_already_premium_subscriber'); + if (isPlus) return t('hub_plan_already_plus_subscriber'); + return t('hub_plan_your_privacy_plan'); + }; + + renderSubtitleText = (fromSearchSelectionScreen) => { + const { user } = this.props; + const isPlus = (user && user.plusAccess) || false; + const isPremium = (user && user.premiumAccess) || false; + + if (fromSearchSelectionScreen) return t('hub_plan_based_on_your_privacy_preferences'); + if (isPremium) return ''; + if (isPlus) return t('hub_plan_keep_your_current_plan_or_upgrade'); + return t('hub_plan_choose_an_option'); + }; render() { const shouldShowSearchPromo = false; @@ -241,8 +260,8 @@ class PlanView extends React.Component { return (
-
{t('hub_plan_your_privacy_plan')}
-
{t('hub_plan_based_on_your_privacy_preferences')}
+
{this.renderTitleText()}
+
{this.renderSubtitleText(shouldShowSearchPromo)}
{shouldShowSearchPromo && ( {searchPromo()} From 8a32f7b2d743796cd44b566755c6abf730219298 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 29 Nov 2020 22:08:50 -0500 Subject: [PATCH 08/30] Style radio button alt design --- app/hub/Views/PlanView/PlanView.jsx | 6 +++--- .../components/BuildingBlocks/RadioButton.jsx | 4 +++- app/scss/partials/_radio_button.scss | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 02db11cfb..73e5bbd3a 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -37,7 +37,7 @@ const basicCard = (checked, handleClick) => {
- +
@@ -75,7 +75,7 @@ const plusCard = (checked, handleClick) => {
- +
@@ -127,7 +127,7 @@ const premiumCard = (checked, handleClick) => {
- +
diff --git a/app/panel/components/BuildingBlocks/RadioButton.jsx b/app/panel/components/BuildingBlocks/RadioButton.jsx index 12924cfb3..63cfba0fe 100644 --- a/app/panel/components/BuildingBlocks/RadioButton.jsx +++ b/app/panel/components/BuildingBlocks/RadioButton.jsx @@ -21,12 +21,14 @@ import ClassNames from 'classnames'; */ const RadioButton = (props) => { - const { checked, handleClick } = props; + const { checked, handleClick, altDesign } = props; const OuterCircleClassNames = ClassNames('RadioButton__outerCircle', { checked, + altDesign }); const InnerCircleClassNames = ClassNames('RadioButton__innerCircle', { checked, + altDesign }); return ( diff --git a/app/scss/partials/_radio_button.scss b/app/scss/partials/_radio_button.scss index 44a33a3fd..53ef30fe0 100644 --- a/app/scss/partials/_radio_button.scss +++ b/app/scss/partials/_radio_button.scss @@ -40,6 +40,14 @@ align-items: center; justify-content: center; box-sizing: border-box; + + &.altDesign { + height: 24px; + width: 24px; + &.checked { + background-color: #00aef0; + } + } &.checked { border: 2px solid #2092bf; } @@ -51,4 +59,14 @@ background-color: #2092bf; border-radius: 50%; } + + &.altDesign { + height: 14px; + width: 14px; + background-image: buildCheckIcon(#FFF); + border: none; + &.checked { + background-color: transparent; + } + } } From cdcef84662f4a14a10d6cd421048524462729420 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 29 Nov 2020 22:11:08 -0500 Subject: [PATCH 09/30] Touch up radio button alt design --- app/scss/partials/_radio_button.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scss/partials/_radio_button.scss b/app/scss/partials/_radio_button.scss index 53ef30fe0..ead8d17fa 100644 --- a/app/scss/partials/_radio_button.scss +++ b/app/scss/partials/_radio_button.scss @@ -44,11 +44,12 @@ &.altDesign { height: 24px; width: 24px; + border: none; &.checked { background-color: #00aef0; } } - &.checked { + &.checked:not(.altDesign) { border: 2px solid #2092bf; } } From 40685f905f0d8d739ec5fe1786cb80a3ef2ef8ca Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 29 Nov 2020 22:22:10 -0500 Subject: [PATCH 10/30] Make responsive --- app/hub/Views/PlanView/PlanView.jsx | 1 + app/hub/Views/PlanView/PlanView.scss | 26 +------------------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 73e5bbd3a..97743fbad 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -187,6 +187,7 @@ class PlanView extends React.Component { selectedPlan: -1 }; this.plansRef = React.createRef(); + // User object doesn't get populated immediately, let's delay the first render setTimeout(this.setDefaultPlan, 200); } diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index 39e1acf02..a2b84f8b6 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -95,6 +95,7 @@ margin-top: 100px; display: flex; justify-content: center; + flex-wrap: wrap; } .PlanView__arrowDown { @@ -110,15 +111,6 @@ .PlanView__cardOuter { flex-shrink: 3; padding: 0 20px; - - &-remove { - @include breakpoint(large up) { - padding-right: 0; - } - @include breakpoint($medium-large-breakpoint down) { - margin-top: rem-calc(90); - } - } } // Clean up unused CSS @@ -143,22 +135,6 @@ } } - @include breakpoint($medium-large-breakpoint down) { - box-shadow: none; - height: 425px; - } - - @include breakpoint($medium-large-breakpoint down) { - &.basic { - height: 400px; - } - &.plus { - height: 498px; - } - &.premium { - height: 526px; - } - } h2 { color: $tundora; font-family: "Roboto Condensed"; From 2e299ccb1f1b894f1e13845b4a490296dec2a818 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 01:02:29 -0500 Subject: [PATCH 11/30] Change CTA button to a button --- app/hub/Views/PlanView/PlanView.jsx | 4 ++-- app/hub/Views/PlanView/PlanView.scss | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 97743fbad..2004face8 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -266,7 +266,7 @@ class PlanView extends React.Component { {shouldShowSearchPromo && ( {searchPromo()} -
{t('hub_plan_start_trial')}
+
{t('hub_plan_see_all_plans')}
@@ -280,7 +280,7 @@ class PlanView extends React.Component { )} {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)}
-
{t('hub_plan_start_trial')}
+
); } diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index a2b84f8b6..673be3b89 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -54,6 +54,8 @@ } .PlanView__searchCTAButton { + display: flex; + justify-content: center; margin: 48px auto 0 auto; height: 44px; width: 162px; From b452c0cf6493834b0ca34b57e93455c04e1ca4e9 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 3 Dec 2020 15:06:07 -0500 Subject: [PATCH 12/30] Add back backgrounds on small screens and add checkmarks for free card --- app/hub/Views/PlanView/PlanView.jsx | 4 ++++ app/hub/Views/PlanView/PlanView.scss | 14 ++------------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 2004face8..b916cd4dd 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -50,15 +50,19 @@ const basicCard = (checked, handleClick) => {

{t('hub_upgrade_basic_protection')}

+ {t('hub_plan_private_search')}
+ {t('hub_plan_tracker_protection')}
+ {t('hub_plan_speedy_page_loads')}
+ {t('hub_plan_intelligence_technology')}
diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index 673be3b89..3c28460ed 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -56,7 +56,7 @@ .PlanView__searchCTAButton { display: flex; justify-content: center; - margin: 48px auto 0 auto; + margin: 48px auto 48px auto; height: 44px; width: 162px; padding: 7.7px 14px; @@ -172,9 +172,6 @@ justify-content: center; align-items: center; - @include breakpoint($medium-large-breakpoint down) { - background-color: #FFF; - } .ghostery-free-image { width: 55px; height: 65px; @@ -188,10 +185,6 @@ width: 250px; height: 85px; background-image: linear-gradient(to right, rgba(240,174,133,.25), rgba(241,216,158,.25)); - @include breakpoint($medium-large-breakpoint down) { - background-image: none; - background-color: #FFF; - } .ghostery-plus-image { margin: auto; width: 225px; @@ -216,9 +209,6 @@ width: 250px; height: 85px; background-image: linear-gradient(to right, rgba(113,1,116,.25), rgba(90,37,142,.25) 18%, rgba(42,110,194,.25) 57%, rgba(12,156,227,.25) 86%, rgba(0,174,240,.25)); - @include breakpoint($medium-large-breakpoint down) { - background-image: none; - } } .button { margin-top: 10px; @@ -279,7 +269,7 @@ width: 174px; &.basic { - width: 124px; + width: 145px; } } .PlanView__cardSubCopy { From 2ab525489c8691f34eefe4ef0d91672fb1365a6b Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 3 Dec 2020 15:58:54 -0500 Subject: [PATCH 13/30] Add working links --- _locales/en/messages.json | 3 +++ app/hub/Views/PlanView/PlanView.jsx | 39 +++++++++++++++++++++++------ app/hub/Views/PlanView/index.jsx | 2 +- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index bc686ea7e..2357c1382 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1752,6 +1752,9 @@ "hub_plan_ad_free_promo_description": { "message": "Get to what you want faster. A plus subscription gives Ghostery the support we need to provide YOU with an ad-free experience." }, + "hub_plan_next_or_start_trial": { + "message": "Next or Start Trial" + }, "hub_plan_start_trial": { "message": "Start Trial" }, diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index b916cd4dd..41c17e72b 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -15,6 +15,7 @@ import React, { Fragment } from 'react'; import ClassNames from 'classnames'; import PropTypes from 'prop-types'; import RadioButton from '../../../panel/components/BuildingBlocks/RadioButton'; +import globals from '../../../../src/classes/Globals'; const BASIC = 0; const PLUS = 1; @@ -258,11 +259,15 @@ class PlanView extends React.Component { }; render() { - const shouldShowSearchPromo = false; - const { user } = this.props; + // Case off of if ghostery search was chosen in previous step + const { user, shouldShowSearchPromo } = this.props; + const { selectedPlan } = this.state; + const isPlus = (user && user.plusAccess) || false; const isPremium = (user && user.premiumAccess) || false; + const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/plus`; + const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/premium`; return (
{this.renderTitleText()}
@@ -270,7 +275,7 @@ class PlanView extends React.Component { {shouldShowSearchPromo && ( {searchPromo()} - + {t('hub_plan_start_trial')}
{t('hub_plan_see_all_plans')}
@@ -284,16 +289,36 @@ class PlanView extends React.Component { )} {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)}
- + {(selectedPlan === BASIC || selectedPlan === -1) && ( + // Change to route to next page + + )} + {selectedPlan === PREMIUM && ( + {t('hub_plan_start_trial')} + )} + {selectedPlan === PLUS && ( + {t('hub_plan_start_trial')} + )}
); } } // PropTypes ensure we pass required props of the correct type -PlanView.propTypes = {}; +PlanView.propTypes = { + user: PropTypes.shape({ + plusAccess: PropTypes.bool, + premiumAccess: PropTypes.bool, + }), + shouldShowSearchPromo: PropTypes.bool.isRequired, +}; -// Default props used on the Home View -PlanView.defaultProps = {}; +// Default props used in the Plus View +PlanView.defaultProps = { + user: { + plusAccess: false, + premiumAccess: false, + }, +}; export default PlanView; diff --git a/app/hub/Views/PlanView/index.jsx b/app/hub/Views/PlanView/index.jsx index c58368caa..fc9041273 100644 --- a/app/hub/Views/PlanView/index.jsx +++ b/app/hub/Views/PlanView/index.jsx @@ -22,7 +22,7 @@ import PlanView from './PlanView'; * @return {function} this function returns a plain object, which will be merged into the component's props * @memberof HubContainers */ -const mapStateToProps = state => ({ ...state.upgrade, ...state.account }); +const mapStateToProps = state => ({ ...state.account }); /** * Bind the component's action creators using Redux's bindActionCreators. From 8dc513b738a75bfa0b361a27c15fe0b9def7c003 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 17:29:40 -0500 Subject: [PATCH 14/30] Refactor basic/plus/premium states --- _locales/en/messages.json | 3 + app/hub/Views/PlanView/PlanView.jsx | 232 +++++++++++++++------------ app/hub/Views/PlanView/PlanView.scss | 31 +++- 3 files changed, 163 insertions(+), 103 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 2357c1382..91fd3e91c 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1752,6 +1752,9 @@ "hub_plan_ad_free_promo_description": { "message": "Get to what you want faster. A plus subscription gives Ghostery the support we need to provide YOU with an ad-free experience." }, + "hub_plan_or": { + "message": "OR" + }, "hub_plan_next_or_start_trial": { "message": "Next or Start Trial" }, diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 41c17e72b..e3de46372 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -72,115 +72,125 @@ const basicCard = (checked, handleClick) => { ); }; -const plusCard = (checked, handleClick) => { +const plusCard = (checked, handleClick, showCTAButton = false) => { const cardClassNames = ClassNames('PlanView__card plus', { checked }); return ( -
-
-
- -
-
-
-
-

Ghostery Plus

-
- -

$4.99

-

{t('per_month')}

-
-
-

{t('hub_upgrade_additional_protection')}

-
-
- - {t('hub_plan_private_search')} -
-
- - {t('hub_plan_tracker_protection')} +
+
+
+
+
-
- - {t('hub_plan_speedy_page_loads')} +
+
-
- - {t('hub_plan_intelligence_technology')} +

Ghostery Plus

+
+ +

$4.99

+

{t('per_month')}

+
-
- - {t('hub_plan_ad_free')} -
-
- - {t('hub_plan_supports_ghosterys_mission')} +

{t('hub_upgrade_additional_protection')}

+
+
+ + {t('hub_plan_private_search')} +
+
+ + {t('hub_plan_tracker_protection')} +
+
+ + {t('hub_plan_speedy_page_loads')} +
+
+ + {t('hub_plan_intelligence_technology')} +
+
+ + {t('hub_plan_ad_free')} +
+
+ + {t('hub_plan_supports_ghosterys_mission')} +
+ {showCTAButton && ( + + )}
); }; -const premiumCard = (checked, handleClick) => { +const premiumCard = (checked, handleClick, showCTAButton = false) => { const cardClassNames = ClassNames('PlanView__card premium', { checked }); return ( -
-
-
- -
-
-
-
-
-

Ghostery Premium

-
- -

$11.99

-

{t('per_month')}

-
-
-

{t('hub_upgrade_maximum_protection')}

-
-
- - {t('hub_plan_private_search')} +
+
+
+
+
-
- - {t('hub_plan_tracker_protection')} +
+
-
- - {t('hub_plan_speedy_page_loads')} +
+

Ghostery Premium

+
+ +

$11.99

+

{t('per_month')}

+
-
- - {t('hub_plan_intelligence_technology')} -
-
- - {t('hub_plan_ad_free')} -
-
- - {t('hub_plan_supports_ghosterys_mission')} -
-
- - VPN -
-
- - {t('hub_plan_unlimited_bandwidth')} +

{t('hub_upgrade_maximum_protection')}

+
+
+ + {t('hub_plan_private_search')} +
+
+ + {t('hub_plan_tracker_protection')} +
+
+ + {t('hub_plan_speedy_page_loads')} +
+
+ + {t('hub_plan_intelligence_technology')} +
+
+ + {t('hub_plan_ad_free')} +
+
+ + {t('hub_plan_supports_ghosterys_mission')} +
+
+ + VPN +
+
+ + {t('hub_plan_unlimited_bandwidth')} +
+ {showCTAButton && ( + + )}
); }; @@ -263,6 +273,7 @@ class PlanView extends React.Component { const { user, shouldShowSearchPromo } = this.props; const { selectedPlan } = this.state; + const isBasic = !user; const isPlus = (user && user.plusAccess) || false; const isPremium = (user && user.premiumAccess) || false; @@ -280,24 +291,41 @@ class PlanView extends React.Component {
)} -
- {!(isPlus || isPremium) && ( - basicCard(this.isBasicPlanChecked(), this.selectBasicPlan) - )} - {!isPremium && ( - plusCard(this.isPlusPlanChecked(), this.selectPlusPlan) - )} - {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)} -
- {(selectedPlan === BASIC || selectedPlan === -1) && ( - // Change to route to next page - - )} - {selectedPlan === PREMIUM && ( - {t('hub_plan_start_trial')} + {(isPlus && !isPremium) ? ( +
+ {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan, (isPlus && !isPremium))} +
{t('hub_plan_or')}
+ {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan, (isPlus && !isPremium))} +
+ ) : ( +
+ {isBasic && ( + basicCard(this.isBasicPlanChecked(), this.selectBasicPlan) + )} + {!isPremium && ( + + {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan)} + + )} + {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)} +
)} - {selectedPlan === PLUS && ( - {t('hub_plan_start_trial')} + {!(isPlus && !isPremium) && ( +
+ {(selectedPlan === BASIC || selectedPlan === -1) && ( + // Change to route to next page + + )} + {selectedPlan === PREMIUM && ( + {t('hub_plan_start_trial')} + )} + {selectedPlan === PLUS && ( + {t('hub_plan_start_trial')} + )} + {(isPlus && !isPremium) && ( + {t('hub_plan_start_trial')} + )} +
)}
); diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index 3c28460ed..0a5631d2c 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -92,13 +92,42 @@ text-decoration: underline; cursor: pointer; } - .PlanView__plansContainer { margin-top: 100px; display: flex; justify-content: center; flex-wrap: wrap; } +.PlanView__orCardContainer { + display: flex; + @include breakpoint($large down) { + flex-direction: column; + height: 50px; + } +} +.PlanView__or { + display: flex; + align-items: center; + padding: 0 66px; + height: 670px; + font-size: 24px; + color: #4a4a4a; +} +.PlanView__cardButtonContainer { + display: flex; + flex-direction: column; + justify-content: center; +} +.PlanView__cardCTAButton { +} +.PlanView__ctaButtonContainer { + display: flex; + justify-content: center; +} +.PlanView__KeepOrUpgradeContainer { + display: flex; + justify-content: space-around; +} .PlanView__arrowDown { margin: 15px auto 0 auto; From ae09663c7e6207ca73e2598eb83d281347b0957b Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 18:08:39 -0500 Subject: [PATCH 15/30] Make cards responsive with OR --- app/hub/Views/PlanView/PlanView.jsx | 22 +++++++++++-------- app/hub/Views/PlanView/PlanView.scss | 33 +++++++++------------------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index e3de46372..30a1b5987 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -77,7 +77,7 @@ const plusCard = (checked, handleClick, showCTAButton = false) => { checked }); return ( -
+
@@ -125,7 +125,7 @@ const plusCard = (checked, handleClick, showCTAButton = false) => { {showCTAButton && ( )} -
+ ); }; @@ -134,7 +134,7 @@ const premiumCard = (checked, handleClick, showCTAButton = false) => { checked }); return ( -
+
@@ -191,7 +191,7 @@ const premiumCard = (checked, handleClick, showCTAButton = false) => { {showCTAButton && ( )} -
+ ); }; @@ -292,13 +292,17 @@ class PlanView extends React.Component { )} {(isPlus && !isPremium) ? ( -
- {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan, (isPlus && !isPremium))} -
{t('hub_plan_or')}
- {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan, (isPlus && !isPremium))} +
+
+ {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan, (isPlus && !isPremium))} +
+
{t('hub_plan_or')}
+
+ {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan, (isPlus && !isPremium))} +
) : ( -
+
{isBasic && ( basicCard(this.isBasicPlanChecked(), this.selectBasicPlan) )} diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index 0a5631d2c..d74ffbb7f 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -56,7 +56,7 @@ .PlanView__searchCTAButton { display: flex; justify-content: center; - margin: 48px auto 48px auto; + margin: auto; height: 44px; width: 162px; padding: 7.7px 14px; @@ -94,32 +94,26 @@ } .PlanView__plansContainer { margin-top: 100px; - display: flex; - justify-content: center; - flex-wrap: wrap; + + .PlanView__cardOuter { + display: flex; + flex-direction: column; + justify-content: center; + margin: 0 15px; + } } .PlanView__orCardContainer { display: flex; - @include breakpoint($large down) { - flex-direction: column; - height: 50px; - } } .PlanView__or { display: flex; align-items: center; + justify-content: center; padding: 0 66px; - height: 670px; + height: 180px; font-size: 24px; color: #4a4a4a; } -.PlanView__cardButtonContainer { - display: flex; - flex-direction: column; - justify-content: center; -} -.PlanView__cardCTAButton { -} .PlanView__ctaButtonContainer { display: flex; justify-content: center; @@ -138,13 +132,6 @@ border-top: 2px solid #00aef0; cursor: pointer; } - -.PlanView__cardOuter { - flex-shrink: 3; - padding: 0 20px; -} - -// Clean up unused CSS .PlanView__card { height: 670px; box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.5); From 61542233030a8bf9f7bf0cbf2136bc65d5ed778a Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 18:27:04 -0500 Subject: [PATCH 16/30] Add padding and change CTA button strings --- _locales/en/messages.json | 6 ++++++ app/hub/Views/PlanView/PlanView.jsx | 12 ++++++------ app/hub/Views/PlanView/PlanView.scss | 5 ++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 91fd3e91c..03f82df48 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1755,6 +1755,12 @@ "hub_plan_or": { "message": "OR" }, + "hub_plan_keep": { + "message": "Keep" + }, + "hub_plan_upgrade": { + "message": "Upgrade" + }, "hub_plan_next_or_start_trial": { "message": "Next or Start Trial" }, diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 30a1b5987..7996b8f61 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -123,7 +123,7 @@ const plusCard = (checked, handleClick, showCTAButton = false) => {
{showCTAButton && ( - + )} ); @@ -189,7 +189,7 @@ const premiumCard = (checked, handleClick, showCTAButton = false) => {
{showCTAButton && ( - + )} ); @@ -292,12 +292,12 @@ class PlanView extends React.Component { )} {(isPlus && !isPremium) ? ( -
-
+
+
{plusCard(this.isPlusPlanChecked(), this.selectPlusPlan, (isPlus && !isPremium))}
-
{t('hub_plan_or')}
-
+
{t('hub_plan_or')}
+
{premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan, (isPlus && !isPremium))}
diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index d74ffbb7f..1dfafdee3 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -118,9 +118,8 @@ display: flex; justify-content: center; } -.PlanView__KeepOrUpgradeContainer { - display: flex; - justify-content: space-around; +.PlanView__keepOrUpgradeContainer { + margin: 40px auto; } .PlanView__arrowDown { From f61e4563bdfa69dd4d93ef72922146f59fb6aadd Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 20:02:03 -0500 Subject: [PATCH 17/30] Add hover effects to search and premium CTA buttons --- app/hub/Views/PlanView/PlanView.jsx | 14 ++++++----- app/hub/Views/PlanView/PlanView.scss | 35 ++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 7996b8f61..f144b9950 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -21,6 +21,9 @@ const BASIC = 0; const PLUS = 1; const PREMIUM = 2; +const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/plus`; +const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/premium`; + const searchPromo = () => (
@@ -123,6 +126,7 @@ const plusCard = (checked, handleClick, showCTAButton = false) => {
{showCTAButton && ( + // Route to next screen )} @@ -189,7 +193,7 @@ const premiumCard = (checked, handleClick, showCTAButton = false) => {
{showCTAButton && ( - + {t('hub_plan_upgrade')} )} ); @@ -274,11 +278,9 @@ class PlanView extends React.Component { const { selectedPlan } = this.state; const isBasic = !user; - const isPlus = (user && user.plusAccess) || false; + const isPlus = (user && user.plusAccess && !user.premiumAccess) || false; const isPremium = (user && user.premiumAccess) || false; - const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/plus`; - const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/premium`; return (
{this.renderTitleText()}
@@ -316,12 +318,12 @@ class PlanView extends React.Component { )} {!(isPlus && !isPremium) && (
- {(selectedPlan === BASIC || selectedPlan === -1) && ( + {(selectedPlan === BASIC) && ( // Change to route to next page )} {selectedPlan === PREMIUM && ( - {t('hub_plan_start_trial')} + {t('hub_plan_start_trial')} )} {selectedPlan === PLUS && ( {t('hub_plan_start_trial')} diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index 1dfafdee3..0696ce9b4 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -56,7 +56,7 @@ .PlanView__searchCTAButton { display: flex; justify-content: center; - margin: auto; + margin: 48px auto 0 auto; height: 44px; width: 162px; padding: 7.7px 14px; @@ -70,10 +70,36 @@ background-position: 100% 50%; transition: 0.25s all; border: none; + color: #FFF; + font-size: 14.1px; + font-weight: 700; + border-radius: 3.5px; + text-align: center; + line-height: 2.05; + cursor: pointer; + &:hover { background-position: 0% 50%; transition: 0.25s all; } +} +.PlanView__premiumCTAButton { + display: flex; + justify-content: center; + margin: 48px auto 0 auto; + height: 44px; + width: 162px; + padding: 7.7px 14px; + line-height: 22px; + background: linear-gradient( + 45deg, + #6c097a 50%, + #03a9ec + ); + background-size: 200% 100%; + background-position: 100% 50%; + transition: 0.25s all; + border: none; color: #FFF; font-size: 14.1px; font-weight: 700; @@ -81,8 +107,13 @@ text-align: center; line-height: 2.05; cursor: pointer; -} + &:hover { + color: $white; + background-position: 0% 50%; + transition: 0.25s all; + } +} .PlanView__seeAllPlans { margin-top: 48px; display: flex; From 0865b2e6d610913ec1df462e264a42e255b8cde6 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 21:25:34 -0500 Subject: [PATCH 18/30] Conditionally show cards based on users subscriptions and refactor arrow to show/hide plan cards instead of scrolling --- _locales/en/messages.json | 3 - app/hub/Views/PlanView/PlanView.jsx | 108 +++++++++++++++------------ app/hub/Views/PlanView/PlanView.scss | 16 +++- 3 files changed, 75 insertions(+), 52 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 03f82df48..e7b5ef93e 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1761,9 +1761,6 @@ "hub_plan_upgrade": { "message": "Upgrade" }, - "hub_plan_next_or_start_trial": { - "message": "Next or Start Trial" - }, "hub_plan_start_trial": { "message": "Start Trial" }, diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index f144b9950..b573cbdb4 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -203,9 +203,9 @@ class PlanView extends React.Component { constructor(props) { super(props); this.state = { - selectedPlan: -1 + selectedPlan: -1, + expanded: false }; - this.plansRef = React.createRef(); // User object doesn't get populated immediately, let's delay the first render setTimeout(this.setDefaultPlan, 200); } @@ -247,8 +247,13 @@ class PlanView extends React.Component { selectPremiumPlan = () => this.setState({ selectedPlan: PREMIUM }); - scrollToPlans = () => { - this.plansRef.current.scrollIntoView({ behavior: 'smooth' }); + toggleSection = () => { + const { expanded } = this.state; + if (expanded) { + this.setState({ expanded: !expanded }); + } else { + this.setState({ expanded: !expanded }); + } }; renderTitleText = () => { @@ -273,63 +278,74 @@ class PlanView extends React.Component { }; render() { - // Case off of if ghostery search was chosen in previous step + // shouldShowSearchPromo should be true if the user did not select ghostery search in the previosu step const { user, shouldShowSearchPromo } = this.props; - const { selectedPlan } = this.state; + const { expanded, selectedPlan } = this.state; const isBasic = !user; const isPlus = (user && user.plusAccess && !user.premiumAccess) || false; const isPremium = (user && user.premiumAccess) || false; + const isBasicOrPremium = isBasic || isPremium; + + const arrowClassNames = ClassNames('PlanView__arrow', { + up: !expanded, + down: expanded + }); return ( -
+
{this.renderTitleText()}
{this.renderSubtitleText(shouldShowSearchPromo)}
- {shouldShowSearchPromo && ( + {/* {shouldShowSearchPromo && ( */} + {true && isBasic && ( {searchPromo()} {t('hub_plan_start_trial')} -
{t('hub_plan_see_all_plans')}
-
+
{t('hub_plan_see_all_plans')}
+
)} - {(isPlus && !isPremium) ? ( -
-
- {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan, (isPlus && !isPremium))} -
-
{t('hub_plan_or')}
-
- {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan, (isPlus && !isPremium))} -
-
- ) : ( -
- {isBasic && ( - basicCard(this.isBasicPlanChecked(), this.selectBasicPlan) - )} - {!isPremium && ( - - {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan)} - - )} - {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)} -
- )} - {!(isPlus && !isPremium) && ( -
- {(selectedPlan === BASIC) && ( - // Change to route to next page - - )} - {selectedPlan === PREMIUM && ( - {t('hub_plan_start_trial')} - )} - {selectedPlan === PLUS && ( - {t('hub_plan_start_trial')} + {(expanded || isPlus || isPremium) && ( +
+ {(isPlus) ? ( +
+
+ {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan, isPlus)} +
+
{t('hub_plan_or')}
+
+ {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan, isPlus)} +
+
+ ) : ( +
+ {isBasic && ( + basicCard(this.isBasicPlanChecked(), this.selectBasicPlan) + )} + {!isPremium && ( + + {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan)} + + )} + {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)} +
)} - {(isPlus && !isPremium) && ( - {t('hub_plan_start_trial')} + {isBasicOrPremium && ( +
+ {(selectedPlan === BASIC) && ( + // Change to route to next page + + )} + {selectedPlan === PREMIUM && ( + {t('next')} + )} + {selectedPlan === PLUS && ( + {t('next')} + )} + {(isPlus && !isPremium) && ( + {t('next')} + )} +
)}
)} diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index 0696ce9b4..d14e925c2 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -1,3 +1,6 @@ +.PlanView { + padding-bottom: 20px; +} .PlanView__yourPrivacyPlan { margin: auto; font-size: 24px; @@ -124,7 +127,8 @@ cursor: pointer; } .PlanView__plansContainer { - margin-top: 100px; + margin-top: 20px; + padding-top: 20px; .PlanView__cardOuter { display: flex; @@ -153,14 +157,20 @@ margin: 40px auto; } -.PlanView__arrowDown { +.PlanView__arrow { margin: 15px auto 0 auto; height: 12px; width: 12px; - transform: rotate(45deg); border-left: 2px solid #00aef0; border-top: 2px solid #00aef0; cursor: pointer; + + &.down { + transform: rotate(45deg); + } + &.up { + transform: rotate(225deg); + } } .PlanView__card { height: 670px; From dbe0507c7597acb9a5507b917507220409cf71c3 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 21:37:34 -0500 Subject: [PATCH 19/30] Fix logic for showing caret --- app/hub/Views/PlanView/PlanView.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index b573cbdb4..c6fad7991 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -296,8 +296,7 @@ class PlanView extends React.Component {
{this.renderTitleText()}
{this.renderSubtitleText(shouldShowSearchPromo)}
- {/* {shouldShowSearchPromo && ( */} - {true && isBasic && ( + {shouldShowSearchPromo && isBasic && ( {searchPromo()} {t('hub_plan_start_trial')} @@ -305,7 +304,7 @@ class PlanView extends React.Component {
)} - {(expanded || isPlus || isPremium) && ( + {((isBasic && !shouldShowSearchPromo) || expanded || isPlus || isPremium) && (
{(isPlus) ? (
From 957a4367252fcf9799c62e48d295961e8bf67130 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 21:46:45 -0500 Subject: [PATCH 20/30] Fix and refactor cta button links --- app/hub/Views/PlanView/PlanView.jsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index c6fad7991..6c3984422 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -329,22 +329,23 @@ class PlanView extends React.Component { {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)}
)} - {isBasicOrPremium && ( + {(isBasic && (
{(selectedPlan === BASIC) && ( // Change to route to next page )} - {selectedPlan === PREMIUM && ( - {t('next')} - )} {selectedPlan === PLUS && ( {t('next')} )} - {(isPlus && !isPremium) && ( - {t('next')} + {selectedPlan === PREMIUM && ( + {t('next')} )}
+ ))} + {isPremium && ( + // Change to route to next page + )}
)} From b56ca6e16f7933a2b03ab0742a32ddf7ef780bd3 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 21:49:09 -0500 Subject: [PATCH 21/30] Fix color of premium CTA button when displaying to a basic user --- app/hub/Views/PlanView/PlanView.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 6c3984422..7abc21820 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -339,7 +339,7 @@ class PlanView extends React.Component { {t('next')} )} {selectedPlan === PREMIUM && ( - {t('next')} + {t('next')} )}
))} From cd0f937e23cfdaf1fca90b0d0825ab2abb192ded Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 21:57:37 -0500 Subject: [PATCH 22/30] Refactor and add comments --- app/hub/Views/PlanView/PlanView.jsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index 7abc21820..efbd055e1 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -278,14 +278,12 @@ class PlanView extends React.Component { }; render() { - // shouldShowSearchPromo should be true if the user did not select ghostery search in the previosu step - const { user, shouldShowSearchPromo } = this.props; + const { user, didNotSelectGhosterySearch } = this.props; const { expanded, selectedPlan } = this.state; const isBasic = !user; const isPlus = (user && user.plusAccess && !user.premiumAccess) || false; const isPremium = (user && user.premiumAccess) || false; - const isBasicOrPremium = isBasic || isPremium; const arrowClassNames = ClassNames('PlanView__arrow', { up: !expanded, @@ -295,16 +293,21 @@ class PlanView extends React.Component { return (
{this.renderTitleText()}
-
{this.renderSubtitleText(shouldShowSearchPromo)}
- {shouldShowSearchPromo && isBasic && ( +
{this.renderSubtitleText(didNotSelectGhosterySearch)}
+ {didNotSelectGhosterySearch && isBasic && ( {searchPromo()} - {t('hub_plan_start_trial')} + {/* TODO: For the CTA button below, + 1. If user is signed in, activate the user’s 7-day free trial for the Ghostery Search Plus plan + and move them to Step 5 if signed in + 2. If user is signed out, clicking this should take them to Step 4b (linked) + */} +
{t('hub_plan_start_trial')}
{t('hub_plan_see_all_plans')}
)} - {((isBasic && !shouldShowSearchPromo) || expanded || isPlus || isPremium) && ( + {((isBasic && !didNotSelectGhosterySearch) || expanded || isPlus || isPremium) && (
{(isPlus) ? (
@@ -360,7 +363,7 @@ PlanView.propTypes = { plusAccess: PropTypes.bool, premiumAccess: PropTypes.bool, }), - shouldShowSearchPromo: PropTypes.bool.isRequired, + didNotSelectGhosterySearch: PropTypes.bool.isRequired, }; // Default props used in the Plus View From 11cbdbe5e1bd049e562ab25acf6dd843bcf025cf Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 22:09:07 -0500 Subject: [PATCH 23/30] Remove unused css --- app/hub/Views/PlanView/PlanView.scss | 44 ---------------------------- 1 file changed, 44 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.scss b/app/hub/Views/PlanView/PlanView.scss index d14e925c2..e928dfc95 100644 --- a/app/hub/Views/PlanView/PlanView.scss +++ b/app/hub/Views/PlanView/PlanView.scss @@ -7,7 +7,6 @@ display: flex; justify-content: center; } - .PlanView__subtitle { margin-top: 12px; display: flex; @@ -21,14 +20,12 @@ border-radius: 4px; border: solid 4px #00aef0; } - .PlanView__searchLogo { height: 37px; width: 193px; margin: 65px auto 0 auto; background-image: url('/app/images/hub/PlanView/search.svg'); } - .PlanView__adFree { margin: 16px auto 0 auto; color: #b8860b; @@ -38,14 +35,12 @@ width: 220px; text-align: center; } - .PlanView__adFreePromo { margin: auto; font-size: 18px; line-height: 32px; text-align: center; } - .PlanView__adFreePromoDescription { margin: 16px auto 0 auto; height: 88px; @@ -55,7 +50,6 @@ text-align: center; color: #4a4a4a; } - .PlanView__searchCTAButton { display: flex; justify-content: center; @@ -156,7 +150,6 @@ .PlanView__keepOrUpgradeContainer { margin: 40px auto; } - .PlanView__arrow { margin: 15px auto 0 auto; height: 12px; @@ -192,7 +185,6 @@ margin-left: -1px; } } - h2 { color: $tundora; font-family: "Roboto Condensed"; @@ -208,17 +200,6 @@ &-sub-header { margin-bottom: rem-calc(15); } - &-sub-copy { - display: flex; - align-items: center; - font-size: rem-calc(12); - margin-bottom: 8px; - text-align: left; - padding-left: rem-calc(35); - img { - padding-right: 10px; - } - } .ghostery-free-image-container { margin: -3px 0 0 -4px; width: 250px; @@ -266,23 +247,10 @@ height: 85px; background-image: linear-gradient(to right, rgba(113,1,116,.25), rgba(90,37,142,.25) 18%, rgba(42,110,194,.25) 57%, rgba(12,156,227,.25) 86%, rgba(0,174,240,.25)); } - .button { - margin-top: 10px; - margin-bottom: rem-calc(20); - text-transform: none; - height: 38px; - line-height: 22px; - &.already-protected { - @include breakpoint($medium-large-breakpoint down) { - margin-top: 45px; - } - } - } .card-sub-header { font-size: 14px; } } - .PlanView__price { min-height: 85px; margin-bottom: rem-calc(20); @@ -309,17 +277,7 @@ font-weight: 500; } } - .price-per-year { - position: relative; - width: 100%; - p { - position: absolute; - width: 100%; - } - } } - - .PlanView__valuePropList { margin: auto; width: 174px; @@ -333,7 +291,6 @@ justify-content: flex-start; margin-bottom: 5px; } - .check { display: inline-block; width: 20px; @@ -350,7 +307,6 @@ background-image: buildCheckIcon($price-purple); } } - .PlanView__radioButtonContainer { padding: 11px; margin-bottom: 84px; From b1c585c1ee8c200e4393f619f546250045685f9b Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 22:17:12 -0500 Subject: [PATCH 24/30] Update plus and premium checkout links to specify english --- app/hub/Views/PlanView/PlanView.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/hub/Views/PlanView/PlanView.jsx b/app/hub/Views/PlanView/PlanView.jsx index efbd055e1..081752bc0 100644 --- a/app/hub/Views/PlanView/PlanView.jsx +++ b/app/hub/Views/PlanView/PlanView.jsx @@ -21,8 +21,8 @@ const BASIC = 0; const PLUS = 1; const PREMIUM = 2; -const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/plus`; -const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/premium`; +const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/en/plus`; +const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/en/premium`; const searchPromo = () => (
From 9fccb044d686459c20658991d1a798f1001d4fec Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 22:42:50 -0500 Subject: [PATCH 25/30] Move RadioButton and RadioButtonGroup to shared components --- .../Step4_ChoosePlanView.jsx | 2 +- app/panel/components/BuildingBlocks/index.js | 4 ---- app/panel/components/Settings/AdBlocker.jsx | 2 +- .../Subscription/SubscriptionThemes.jsx | 2 +- .../RadioButton}/RadioButton.jsx | 0 app/shared-components/RadioButton/index.js | 16 ++++++++++++++++ .../RadioButtonGroup}/RadioButtonGroup.jsx | 2 +- app/shared-components/RadioButtonGroup/index.js | 16 ++++++++++++++++ 8 files changed, 36 insertions(+), 8 deletions(-) rename app/{panel/components/BuildingBlocks => shared-components/RadioButton}/RadioButton.jsx (100%) create mode 100644 app/shared-components/RadioButton/index.js rename app/{panel/components/BuildingBlocks => shared-components/RadioButtonGroup}/RadioButtonGroup.jsx (97%) create mode 100644 app/shared-components/RadioButtonGroup/index.js diff --git a/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.jsx b/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.jsx index 19d5591c1..861555854 100644 --- a/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.jsx +++ b/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.jsx @@ -14,7 +14,7 @@ import React, { Fragment } from 'react'; import ClassNames from 'classnames'; import PropTypes from 'prop-types'; -import RadioButton from '../../../panel/components/BuildingBlocks/RadioButton'; +import RadioButton from '../../../shared-components/RadioButton'; import globals from '../../../../src/classes/Globals'; const BASIC = 0; diff --git a/app/panel/components/BuildingBlocks/index.js b/app/panel/components/BuildingBlocks/index.js index 8f73d6052..edc925cbc 100644 --- a/app/panel/components/BuildingBlocks/index.js +++ b/app/panel/components/BuildingBlocks/index.js @@ -21,8 +21,6 @@ import GhosteryFeature from './GhosteryFeature'; import NotScanned from './NotScanned'; import PauseButton from './PauseButton'; import ToggleSlider from './ToggleSlider'; -import RadioButtonGroup from './RadioButtonGroup'; -import RadioButton from './RadioButton'; import ModalExitButton from './ModalExitButton'; export { @@ -33,7 +31,5 @@ export { NotScanned, PauseButton, ToggleSlider, - RadioButtonGroup, - RadioButton, ModalExitButton }; diff --git a/app/panel/components/Settings/AdBlocker.jsx b/app/panel/components/Settings/AdBlocker.jsx index 2a5466602..dff505050 100644 --- a/app/panel/components/Settings/AdBlocker.jsx +++ b/app/panel/components/Settings/AdBlocker.jsx @@ -13,7 +13,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { RadioButtonGroup } from '../BuildingBlocks'; +import RadioButtonGroup from '../../../shared-components/RadioButtonGroup/RadioButtonGroup'; /** * @class Implement Ad Blocker Settings subview as a React component. diff --git a/app/panel/components/Subscription/SubscriptionThemes.jsx b/app/panel/components/Subscription/SubscriptionThemes.jsx index f486277d6..72087f438 100644 --- a/app/panel/components/Subscription/SubscriptionThemes.jsx +++ b/app/panel/components/Subscription/SubscriptionThemes.jsx @@ -13,7 +13,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { RadioButtonGroup } from '../BuildingBlocks'; +import RadioButtonGroup from '../../../shared-components/RadioButtonGroup/RadioButtonGroup'; /** * @class Implement Themes subview as a React component. diff --git a/app/panel/components/BuildingBlocks/RadioButton.jsx b/app/shared-components/RadioButton/RadioButton.jsx similarity index 100% rename from app/panel/components/BuildingBlocks/RadioButton.jsx rename to app/shared-components/RadioButton/RadioButton.jsx diff --git a/app/shared-components/RadioButton/index.js b/app/shared-components/RadioButton/index.js new file mode 100644 index 000000000..04cf4d177 --- /dev/null +++ b/app/shared-components/RadioButton/index.js @@ -0,0 +1,16 @@ +/** + * Point of entry index.js file for Radio Button + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2019 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import RadioButton from './RadioButton'; + +export default RadioButton; diff --git a/app/panel/components/BuildingBlocks/RadioButtonGroup.jsx b/app/shared-components/RadioButtonGroup/RadioButtonGroup.jsx similarity index 97% rename from app/panel/components/BuildingBlocks/RadioButtonGroup.jsx rename to app/shared-components/RadioButtonGroup/RadioButtonGroup.jsx index 2722ceddc..a91d4b8f4 100644 --- a/app/panel/components/BuildingBlocks/RadioButtonGroup.jsx +++ b/app/shared-components/RadioButtonGroup/RadioButtonGroup.jsx @@ -13,7 +13,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import RadioButton from './RadioButton'; +import RadioButton from '../RadioButton'; /** * @class Implements a radio button group diff --git a/app/shared-components/RadioButtonGroup/index.js b/app/shared-components/RadioButtonGroup/index.js new file mode 100644 index 000000000..a7d9aa0d8 --- /dev/null +++ b/app/shared-components/RadioButtonGroup/index.js @@ -0,0 +1,16 @@ +/** + * Point of entry index.js file for Radio Button Group + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2019 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import RadioButtonGroup from './RadioButtonGroup'; + +export default RadioButtonGroup; From a6d647e50b8dc3229589a187a2f90f36b3c664c8 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 22:49:03 -0500 Subject: [PATCH 26/30] Rename Step4_ChoosePlanView to ChoosePlanView --- .../OnboardingViewContainer.jsx | 2 +- .../Step4_ChoosePlanView/ChoosePlanView.jsx | 365 ++++++++++++++++- .../Step4_ChoosePlanView/ChoosePlanView.scss} | 48 +-- .../Step4_ChoosePlanView/index.js | 16 - .../Step4_ChoosePlanView/index.jsx | 6 +- .../Step4_ChoosePlanView.jsx | 377 ------------------ app/scss/hub.scss | 2 +- 7 files changed, 391 insertions(+), 425 deletions(-) rename app/{hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.scss => ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.scss} (85%) delete mode 100644 app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/index.js rename app/{hub/Views => ghostery-browser-hub/Views/OnboardingViews}/Step4_ChoosePlanView/index.jsx (88%) delete mode 100644 app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.jsx diff --git a/app/ghostery-browser-hub/Views/OnboardingView/OnboardingViewContainer.jsx b/app/ghostery-browser-hub/Views/OnboardingView/OnboardingViewContainer.jsx index 838f495a0..3e444bcf1 100644 --- a/app/ghostery-browser-hub/Views/OnboardingView/OnboardingViewContainer.jsx +++ b/app/ghostery-browser-hub/Views/OnboardingView/OnboardingViewContainer.jsx @@ -21,7 +21,7 @@ import WelcomeView from '../OnboardingViews/Step0_WelcomeView'; import LoginView from '../OnboardingViews/Step1_LoginView'; import BlockSettingsView from '../OnboardingViews/Step2_BlockSettingsView'; import ChooseDefaultSearchView from '../OnboardingViews/Step3_ChooseDefaultSearchView'; -import ChoosePlanView from '../OnboardingViews/Step4_ChoosePlanView'; +import ChoosePlanView from '../OnboardingViews/ChoosePlanView'; import SuccessView from '../OnboardingViews/Step5_SuccessView'; /** diff --git a/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.jsx b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.jsx index abaddba4d..3e115588d 100644 --- a/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.jsx +++ b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.jsx @@ -1,5 +1,5 @@ /** - * Ghostery Browser Hub Choose Plan View Component + * Plan View Component * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -11,8 +11,367 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -import React from 'react'; +import React, { Fragment } from 'react'; +import ClassNames from 'classnames'; +import PropTypes from 'prop-types'; +import RadioButton from '../../../../shared-components/RadioButton'; +import globals from '../../../../../src/classes/Globals'; -const ChoosePlanView = () =>

Step 4: Choose Plan View

; +const BASIC = 0; +const PLUS = 1; +const PREMIUM = 2; + +const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/en/plus`; +const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/en/premium`; + +const searchPromo = () => ( +
+
+
{ t('ghostery_browser_hub_onboarding_ad_free_with_ghostery_plus_subscription') }
+
{ t('ghostery_browser_hub_onboarding_ad_free_promo') }
+
{ t('ghostery_browser_hub_onboarding_ad_free_promo_description') }
+
+); + +const basicCard = (checked, handleClick) => { + const cardClassNames = ClassNames('ChoosePlanView__card basic', { + checked + }); + return ( +
+
+
+ +
+
+
+
+
+

Ghostery

+
+

{t('hub_upgrade_plan_free')}

+
+

{t('hub_upgrade_basic_protection')}

+
+
+ + {t('ghostery_browser_hub_onboarding_private_search')} +
+
+ + {t('ghostery_browser_hub_onboarding_tracker_protection')} +
+
+ + {t('ghostery_browser_hub_onboarding_speedy_page_loads')} +
+
+ + {t('ghostery_browser_hub_onboarding_intelligence_technology')} +
+
+
+
+ ); +}; + +const plusCard = (checked, handleClick, showCTAButton = false) => { + const cardClassNames = ClassNames('ChoosePlanView__card plus', { + checked + }); + return ( + +
+
+
+ +
+
+
+
+

Ghostery Plus

+
+ +

$4.99

+

{t('per_month')}

+
+
+

{t('hub_upgrade_additional_protection')}

+
+
+ + {t('ghostery_browser_hub_onboarding_private_search')} +
+
+ + {t('ghostery_browser_hub_onboarding_tracker_protection')} +
+
+ + {t('ghostery_browser_hub_onboarding_speedy_page_loads')} +
+
+ + {t('ghostery_browser_hub_onboarding_intelligence_technology')} +
+
+ + {t('ghostery_browser_hub_onboarding_ad_free')} +
+
+ + {t('ghostery_browser_hub_onboarding_supports_ghosterys_mission')} +
+
+
+
+ {showCTAButton && ( + // Route to next screen + + )} + + ); +}; + +const premiumCard = (checked, handleClick, showCTAButton = false) => { + const cardClassNames = ClassNames('ChoosePlanView__card premium', { + checked + }); + return ( + +
+
+
+ +
+
+
+
+
+

Ghostery Premium

+
+ +

$11.99

+

{t('per_month')}

+
+
+

{t('hub_upgrade_maximum_protection')}

+
+
+ + {t('ghostery_browser_hub_onboarding_private_search')} +
+
+ + {t('ghostery_browser_hub_onboarding_tracker_protection')} +
+
+ + {t('ghostery_browser_hub_onboarding_speedy_page_loads')} +
+
+ + {t('ghostery_browser_hub_onboarding_intelligence_technology')} +
+
+ + {t('ghostery_browser_hub_onboarding_ad_free')} +
+
+ + {t('ghostery_browser_hub_onboarding_supports_ghosterys_mission')} +
+
+ + VPN +
+
+ + {t('ghostery_browser_hub_onboarding_unlimited_bandwidth')} +
+
+
+
+ {showCTAButton && ( + {t('ghostery_browser_hub_onboarding_upgrade')} + )} + + ); +}; + +class ChoosePlanView extends React.Component { + constructor(props) { + super(props); + this.state = { + selectedPlan: -1, + expanded: false + }; + // User object doesn't get populated immediately, let's delay the first render + setTimeout(this.setDefaultPlan, 200); + } + + setDefaultPlan = () => { + const { user } = this.props; + const isPlus = (user && user.plusAccess) || false; + const isPremium = (user && user.premiumAccess) || false; + + if (isPremium) { + this.selectPremiumPlan(); + return; + } + if (isPlus) { + this.selectPlusPlan(); + return; + } + this.selectBasicPlan(); + } + + isBasicPlanChecked = () => { + const { selectedPlan } = this.state; + return (selectedPlan === BASIC); + }; + + isPlusPlanChecked = () => { + const { selectedPlan } = this.state; + return (selectedPlan === PLUS); + }; + + isPremiumPlanChecked = () => { + const { selectedPlan } = this.state; + return (selectedPlan === PREMIUM); + }; + + selectBasicPlan = () => this.setState({ selectedPlan: BASIC }); + + selectPlusPlan = () => this.setState({ selectedPlan: PLUS }); + + selectPremiumPlan = () => this.setState({ selectedPlan: PREMIUM }); + + toggleSection = () => { + const { expanded } = this.state; + if (expanded) { + this.setState({ expanded: !expanded }); + } else { + this.setState({ expanded: !expanded }); + } + }; + + renderTitleText = () => { + const { user } = this.props; + const isPlus = (user && user.plusAccess) || false; + const isPremium = (user && user.premiumAccess) || false; + + if (isPremium) return t('ghostery_browser_hub_onboarding_already_premium_subscriber'); + if (isPlus) return t('ghostery_browser_hub_onboarding_already_plus_subscriber'); + return t('ghostery_browser_hub_onboarding_your_privacy_plan'); + }; + + renderSubtitleText = (fromSearchSelectionScreen) => { + const { user } = this.props; + const isPlus = (user && user.plusAccess) || false; + const isPremium = (user && user.premiumAccess) || false; + + if (fromSearchSelectionScreen) return t('ghostery_browser_hub_onboarding_based_on_your_privacy_preferences'); + if (isPremium) return ''; + if (isPlus) return t('ghostery_browser_hub_onboarding_keep_your_current_plan_or_upgrade'); + return t('ghostery_browser_hub_onboarding_choose_an_option'); + }; + + render() { + const { user, didNotSelectGhosterySearch } = this.props; + const { expanded, selectedPlan } = this.state; + + const isBasic = !user; + const isPlus = (user && user.plusAccess && !user.premiumAccess) || false; + const isPremium = (user && user.premiumAccess) || false; + + const arrowClassNames = ClassNames('ChoosePlanView__arrow', { + up: !expanded, + down: expanded + }); + + return ( +
+
{this.renderTitleText()}
+
{this.renderSubtitleText(didNotSelectGhosterySearch)}
+ {didNotSelectGhosterySearch && isBasic && ( + + {searchPromo()} + {/* TODO: For the CTA button below, + 1. If user is signed in, activate the user’s 7-day free trial for the Ghostery Search Plus plan + and move them to Step 5 if signed in + 2. If user is signed out, clicking this should take them to Step 4b (linked) + */} +
{t('ghostery_browser_hub_onboarding_start_trial')}
+
{t('ghostery_browser_hub_onboarding_see_all_plans')}
+
+ + )} + {((isBasic && !didNotSelectGhosterySearch) || expanded || isPlus || isPremium) && ( +
+ {(isPlus) ? ( +
+
+ {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan, isPlus)} +
+
{t('ghostery_browser_hub_onboarding_or')}
+
+ {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan, isPlus)} +
+
+ ) : ( +
+ {isBasic && ( + basicCard(this.isBasicPlanChecked(), this.selectBasicPlan) + )} + {!isPremium && ( + + {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan)} + + )} + {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)} +
+ )} + {(isBasic && ( +
+ {(selectedPlan === BASIC) && ( + // Change to route to next page + + )} + {selectedPlan === PLUS && ( + {t('next')} + )} + {selectedPlan === PREMIUM && ( + {t('next')} + )} +
+ ))} + {isPremium && ( + // Change to route to next page + + )} +
+ )} +
+ ); + } +} + +// PropTypes ensure we pass required props of the correct type +ChoosePlanView.propTypes = { + user: PropTypes.shape({ + plusAccess: PropTypes.bool, + premiumAccess: PropTypes.bool, + }), + didNotSelectGhosterySearch: PropTypes.bool.isRequired, +}; + +// Default props used in the Plus View +ChoosePlanView.defaultProps = { + user: { + plusAccess: false, + premiumAccess: false, + }, +}; export default ChoosePlanView; diff --git a/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.scss b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.scss similarity index 85% rename from app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.scss rename to app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.scss index 0bb628725..bbdb20a40 100644 --- a/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.scss +++ b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.scss @@ -1,32 +1,32 @@ -.Step4_ChoosePlanView { +.ChoosePlanView { padding-bottom: 20px; } -.Step4_ChoosePlanView__yourPrivacyPlan { +.ChoosePlanView__yourPrivacyPlan { margin: auto; font-size: 24px; display: flex; justify-content: center; } -.Step4_ChoosePlanView__subtitle { +.ChoosePlanView__subtitle { margin-top: 12px; display: flex; justify-content: center; font-size: 18px; } -.Step4_ChoosePlanView__searchPromoContainer { +.ChoosePlanView__searchPromoContainer { width: 354px; height: 381px; margin: 48px auto 0 auto; border-radius: 4px; border: solid 4px #00aef0; } -.Step4_ChoosePlanView__searchLogo { +.ChoosePlanView__searchLogo { height: 37px; width: 193px; margin: 65px auto 0 auto; - background-image: url('/app/images/hub/Step4_ChoosePlanView/search.svg'); + background-image: url('/app/images/hub/ChoosePlanView/search.svg'); } -.Step4_ChoosePlanView__adFree { +.ChoosePlanView__adFree { margin: 16px auto 0 auto; color: #b8860b; font-size: 18px; @@ -35,13 +35,13 @@ width: 220px; text-align: center; } -.Step4_ChoosePlanView__adFreePromo { +.ChoosePlanView__adFreePromo { margin: auto; font-size: 18px; line-height: 32px; text-align: center; } -.Step4_ChoosePlanView__adFreePromoDescription { +.ChoosePlanView__adFreePromoDescription { margin: 16px auto 0 auto; height: 88px; width: 250px; @@ -50,7 +50,7 @@ text-align: center; color: #4a4a4a; } -.Step4_ChoosePlanView__searchCTAButton { +.ChoosePlanView__searchCTAButton { display: flex; justify-content: center; margin: 48px auto 0 auto; @@ -83,7 +83,7 @@ color: #FFF; } } -.Step4_ChoosePlanView__premiumCTAButton { +.ChoosePlanView__premiumCTAButton { display: flex; justify-content: center; margin: 48px auto 0 auto; @@ -114,7 +114,7 @@ transition: 0.25s all; } } -.Step4_ChoosePlanView__seeAllPlans { +.ChoosePlanView__seeAllPlans { margin-top: 48px; display: flex; justify-content: center; @@ -123,21 +123,21 @@ text-decoration: underline; cursor: pointer; } -.Step4_ChoosePlanView__plansContainer { +.ChoosePlanView__plansContainer { margin-top: 20px; padding-top: 20px; - .Step4_ChoosePlanView__cardOuter { + .ChoosePlanView__cardOuter { display: flex; flex-direction: column; justify-content: center; margin: 0 15px; } } -.Step4_ChoosePlanView__orCardContainer { +.ChoosePlanView__orCardContainer { display: flex; } -.Step4_ChoosePlanView__or { +.ChoosePlanView__or { display: flex; align-items: center; justify-content: center; @@ -146,14 +146,14 @@ font-size: 24px; color: #4a4a4a; } -.Step4_ChoosePlanView__ctaButtonContainer { +.ChoosePlanView__ctaButtonContainer { display: flex; justify-content: center; } -.Step4_ChoosePlanView__keepOrUpgradeContainer { +.ChoosePlanView__keepOrUpgradeContainer { margin: 40px auto; } -.Step4_ChoosePlanView__arrow { +.ChoosePlanView__arrow { margin: 15px auto 0 auto; height: 12px; width: 12px; @@ -168,7 +168,7 @@ transform: rotate(225deg); } } -.Step4_ChoosePlanView__card { +.ChoosePlanView__card { height: 670px; box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.5); margin-bottom: rem-calc(40); @@ -254,7 +254,7 @@ font-size: 14px; } } -.Step4_ChoosePlanView__price { +.ChoosePlanView__price { min-height: 85px; margin-bottom: rem-calc(20); &-blue { @@ -281,7 +281,7 @@ } } } -.Step4_ChoosePlanView__valuePropList { +.ChoosePlanView__valuePropList { margin: auto; width: 174px; @@ -289,7 +289,7 @@ width: 145px; } } -.Step4_ChoosePlanView__cardSubCopy { +.ChoosePlanView__cardSubCopy { display: flex; justify-content: flex-start; margin-bottom: 5px; @@ -310,7 +310,7 @@ background-image: buildCheckIcon($price-purple); } } -.Step4_ChoosePlanView__radioButtonContainer { +.ChoosePlanView__radioButtonContainer { padding: 11px; margin-bottom: 84px; display: flex; diff --git a/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/index.js b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/index.js deleted file mode 100644 index 72ed11332..000000000 --- a/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/index.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Point of entry index.js file for Ghostery Browser Hub Choose Plan View - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2020 Ghostery, Inc. All rights reserved. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0 - */ - -import ChoosePlanView from './ChoosePlanView'; - -export default ChoosePlanView; diff --git a/app/hub/Views/Step4_ChoosePlanView/index.jsx b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/index.jsx similarity index 88% rename from app/hub/Views/Step4_ChoosePlanView/index.jsx rename to app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/index.jsx index a8cfbe24e..f21eb0832 100644 --- a/app/hub/Views/Step4_ChoosePlanView/index.jsx +++ b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/index.jsx @@ -1,5 +1,5 @@ /** - * Point of entry index.js file for PlanView + * Point of entry index.js file for Ghostery Browser Hub Choose Plan View * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -14,7 +14,7 @@ import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; -import Step4_ChoosePlanView from './Step4_ChoosePlanView'; +import ChoosePlanView from './ChoosePlanView'; /** * Map redux store state properties to the component's own properties. @@ -32,4 +32,4 @@ const mapStateToProps = state => ({ ...state.account }); */ const mapDispatchToProps = dispatch => ({}); -export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Step4_ChoosePlanView)); +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ChoosePlanView)); diff --git a/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.jsx b/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.jsx deleted file mode 100644 index 861555854..000000000 --- a/app/hub/Views/Step4_ChoosePlanView/Step4_ChoosePlanView.jsx +++ /dev/null @@ -1,377 +0,0 @@ -/** - * Plan View Component - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2020 Ghostery, Inc. All rights reserved. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0 - */ - -import React, { Fragment } from 'react'; -import ClassNames from 'classnames'; -import PropTypes from 'prop-types'; -import RadioButton from '../../../shared-components/RadioButton'; -import globals from '../../../../src/classes/Globals'; - -const BASIC = 0; -const PLUS = 1; -const PREMIUM = 2; - -const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/en/plus`; -const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/en/premium`; - -const searchPromo = () => ( -
-
-
{ t('ghostery_browser_hub_onboarding_ad_free_with_ghostery_plus_subscription') }
-
{ t('ghostery_browser_hub_onboarding_ad_free_promo') }
-
{ t('ghostery_browser_hub_onboarding_ad_free_promo_description') }
-
-); - -const basicCard = (checked, handleClick) => { - const cardClassNames = ClassNames('Step4_ChoosePlanView__card basic', { - checked - }); - return ( -
-
-
- -
-
-
-
-
-

Ghostery

-
-

{t('hub_upgrade_plan_free')}

-
-

{t('hub_upgrade_basic_protection')}

-
-
- - {t('ghostery_browser_hub_onboarding_private_search')} -
-
- - {t('ghostery_browser_hub_onboarding_tracker_protection')} -
-
- - {t('ghostery_browser_hub_onboarding_speedy_page_loads')} -
-
- - {t('ghostery_browser_hub_onboarding_intelligence_technology')} -
-
-
-
- ); -}; - -const plusCard = (checked, handleClick, showCTAButton = false) => { - const cardClassNames = ClassNames('Step4_ChoosePlanView__card plus', { - checked - }); - return ( - -
-
-
- -
-
-
-
-

Ghostery Plus

-
- -

$4.99

-

{t('per_month')}

-
-
-

{t('hub_upgrade_additional_protection')}

-
-
- - {t('ghostery_browser_hub_onboarding_private_search')} -
-
- - {t('ghostery_browser_hub_onboarding_tracker_protection')} -
-
- - {t('ghostery_browser_hub_onboarding_speedy_page_loads')} -
-
- - {t('ghostery_browser_hub_onboarding_intelligence_technology')} -
-
- - {t('ghostery_browser_hub_onboarding_ad_free')} -
-
- - {t('ghostery_browser_hub_onboarding_supports_ghosterys_mission')} -
-
-
-
- {showCTAButton && ( - // Route to next screen - - )} - - ); -}; - -const premiumCard = (checked, handleClick, showCTAButton = false) => { - const cardClassNames = ClassNames('Step4_ChoosePlanView__card premium', { - checked - }); - return ( - -
-
-
- -
-
-
-
-
-

Ghostery Premium

-
- -

$11.99

-

{t('per_month')}

-
-
-

{t('hub_upgrade_maximum_protection')}

-
-
- - {t('ghostery_browser_hub_onboarding_private_search')} -
-
- - {t('ghostery_browser_hub_onboarding_tracker_protection')} -
-
- - {t('ghostery_browser_hub_onboarding_speedy_page_loads')} -
-
- - {t('ghostery_browser_hub_onboarding_intelligence_technology')} -
-
- - {t('ghostery_browser_hub_onboarding_ad_free')} -
-
- - {t('ghostery_browser_hub_onboarding_supports_ghosterys_mission')} -
-
- - VPN -
-
- - {t('ghostery_browser_hub_onboarding_unlimited_bandwidth')} -
-
-
-
- {showCTAButton && ( - {t('ghostery_browser_hub_onboarding_upgrade')} - )} - - ); -}; - -class Step4_ChoosePlanView extends React.Component { - constructor(props) { - super(props); - this.state = { - selectedPlan: -1, - expanded: false - }; - // User object doesn't get populated immediately, let's delay the first render - setTimeout(this.setDefaultPlan, 200); - } - - setDefaultPlan = () => { - const { user } = this.props; - const isPlus = (user && user.plusAccess) || false; - const isPremium = (user && user.premiumAccess) || false; - - if (isPremium) { - this.selectPremiumPlan(); - return; - } - if (isPlus) { - this.selectPlusPlan(); - return; - } - this.selectBasicPlan(); - } - - isBasicPlanChecked = () => { - const { selectedPlan } = this.state; - return (selectedPlan === BASIC); - }; - - isPlusPlanChecked = () => { - const { selectedPlan } = this.state; - return (selectedPlan === PLUS); - }; - - isPremiumPlanChecked = () => { - const { selectedPlan } = this.state; - return (selectedPlan === PREMIUM); - }; - - selectBasicPlan = () => this.setState({ selectedPlan: BASIC }); - - selectPlusPlan = () => this.setState({ selectedPlan: PLUS }); - - selectPremiumPlan = () => this.setState({ selectedPlan: PREMIUM }); - - toggleSection = () => { - const { expanded } = this.state; - if (expanded) { - this.setState({ expanded: !expanded }); - } else { - this.setState({ expanded: !expanded }); - } - }; - - renderTitleText = () => { - const { user } = this.props; - const isPlus = (user && user.plusAccess) || false; - const isPremium = (user && user.premiumAccess) || false; - - if (isPremium) return t('ghostery_browser_hub_onboarding_already_premium_subscriber'); - if (isPlus) return t('ghostery_browser_hub_onboarding_already_plus_subscriber'); - return t('ghostery_browser_hub_onboarding_your_privacy_plan'); - }; - - renderSubtitleText = (fromSearchSelectionScreen) => { - const { user } = this.props; - const isPlus = (user && user.plusAccess) || false; - const isPremium = (user && user.premiumAccess) || false; - - if (fromSearchSelectionScreen) return t('ghostery_browser_hub_onboarding_based_on_your_privacy_preferences'); - if (isPremium) return ''; - if (isPlus) return t('ghostery_browser_hub_onboarding_keep_your_current_plan_or_upgrade'); - return t('ghostery_browser_hub_onboarding_choose_an_option'); - }; - - render() { - const { user, didNotSelectGhosterySearch } = this.props; - const { expanded, selectedPlan } = this.state; - - const isBasic = !user; - const isPlus = (user && user.plusAccess && !user.premiumAccess) || false; - const isPremium = (user && user.premiumAccess) || false; - - const arrowClassNames = ClassNames('Step4_ChoosePlanView__arrow', { - up: !expanded, - down: expanded - }); - - return ( -
-
{this.renderTitleText()}
-
{this.renderSubtitleText(didNotSelectGhosterySearch)}
- {didNotSelectGhosterySearch && isBasic && ( - - {searchPromo()} - {/* TODO: For the CTA button below, - 1. If user is signed in, activate the user’s 7-day free trial for the Ghostery Search Plus plan - and move them to Step 5 if signed in - 2. If user is signed out, clicking this should take them to Step 4b (linked) - */} -
{t('ghostery_browser_hub_onboarding_start_trial')}
-
{t('ghostery_browser_hub_onboarding_see_all_plans')}
-
- - )} - {((isBasic && !didNotSelectGhosterySearch) || expanded || isPlus || isPremium) && ( -
- {(isPlus) ? ( -
-
- {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan, isPlus)} -
-
{t('ghostery_browser_hub_onboarding_or')}
-
- {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan, isPlus)} -
-
- ) : ( -
- {isBasic && ( - basicCard(this.isBasicPlanChecked(), this.selectBasicPlan) - )} - {!isPremium && ( - - {plusCard(this.isPlusPlanChecked(), this.selectPlusPlan)} - - )} - {premiumCard(this.isPremiumPlanChecked(), this.selectPremiumPlan)} -
- )} - {(isBasic && ( -
- {(selectedPlan === BASIC) && ( - // Change to route to next page - - )} - {selectedPlan === PLUS && ( - {t('next')} - )} - {selectedPlan === PREMIUM && ( - {t('next')} - )} -
- ))} - {isPremium && ( - // Change to route to next page - - )} -
- )} -
- ); - } -} - -// PropTypes ensure we pass required props of the correct type -Step4_ChoosePlanView.propTypes = { - user: PropTypes.shape({ - plusAccess: PropTypes.bool, - premiumAccess: PropTypes.bool, - }), - didNotSelectGhosterySearch: PropTypes.bool.isRequired, -}; - -// Default props used in the Plus View -Step4_ChoosePlanView.defaultProps = { - user: { - plusAccess: false, - premiumAccess: false, - }, -}; - -export default Step4_ChoosePlanView; diff --git a/app/scss/hub.scss b/app/scss/hub.scss index 6f9079775..d259e061c 100644 --- a/app/scss/hub.scss +++ b/app/scss/hub.scss @@ -87,7 +87,7 @@ html, body, #root { @import '../hub/Views/CreateAccountView/CreateAccountView.scss'; @import '../hub/Views/UpgradePlanView/UpgradePlanView.scss'; @import '../ghostery-browser-hub/Views/OnboardingViews/Step0_WelcomeView/WelcomeView.scss'; -@import '../ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/Step4_ChoosePlanView.scss'; +@import '../ghostery-browser-hub/Views/OnboardingViews/ChoosePlanView/ChoosePlanView.scss'; @import '../ghostery-browser-hub/Views/OnboardingViews/Step5_SuccessView/SuccessView.scss'; // Imports from ../shared-components directory From 2bebdaba24b06a9da0b19695449d73313c9569f4 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 23:11:57 -0500 Subject: [PATCH 27/30] Use BASIC, PLUS, and PREMIUM constants from UpgradePlanViewConstants and fix search.svg path --- .../Views/OnboardingView/OnboardingViewContainer.jsx | 2 +- .../Step4_ChoosePlanView/ChoosePlanView.jsx | 9 +++------ .../{Step4_ChoosePlanView => ChoosePlanView}/search.svg | 0 3 files changed, 4 insertions(+), 7 deletions(-) rename app/images/hub/{Step4_ChoosePlanView => ChoosePlanView}/search.svg (100%) diff --git a/app/ghostery-browser-hub/Views/OnboardingView/OnboardingViewContainer.jsx b/app/ghostery-browser-hub/Views/OnboardingView/OnboardingViewContainer.jsx index 3e444bcf1..838f495a0 100644 --- a/app/ghostery-browser-hub/Views/OnboardingView/OnboardingViewContainer.jsx +++ b/app/ghostery-browser-hub/Views/OnboardingView/OnboardingViewContainer.jsx @@ -21,7 +21,7 @@ import WelcomeView from '../OnboardingViews/Step0_WelcomeView'; import LoginView from '../OnboardingViews/Step1_LoginView'; import BlockSettingsView from '../OnboardingViews/Step2_BlockSettingsView'; import ChooseDefaultSearchView from '../OnboardingViews/Step3_ChooseDefaultSearchView'; -import ChoosePlanView from '../OnboardingViews/ChoosePlanView'; +import ChoosePlanView from '../OnboardingViews/Step4_ChoosePlanView'; import SuccessView from '../OnboardingViews/Step5_SuccessView'; /** diff --git a/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.jsx b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.jsx index 3e115588d..4ce39dc8a 100644 --- a/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.jsx +++ b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.jsx @@ -1,5 +1,5 @@ /** - * Plan View Component + * Ghostery Browser Hub Choose Plan View Component * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -16,10 +16,7 @@ import ClassNames from 'classnames'; import PropTypes from 'prop-types'; import RadioButton from '../../../../shared-components/RadioButton'; import globals from '../../../../../src/classes/Globals'; - -const BASIC = 0; -const PLUS = 1; -const PREMIUM = 2; +import { BASIC, PLUS, PREMIUM } from '../../../../hub/Views/UpgradePlanView/UpgradePlanViewConstants'; const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/en/plus`; const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/en/premium`; @@ -203,7 +200,7 @@ class ChoosePlanView extends React.Component { constructor(props) { super(props); this.state = { - selectedPlan: -1, + selectedPlan: '', expanded: false }; // User object doesn't get populated immediately, let's delay the first render diff --git a/app/images/hub/Step4_ChoosePlanView/search.svg b/app/images/hub/ChoosePlanView/search.svg similarity index 100% rename from app/images/hub/Step4_ChoosePlanView/search.svg rename to app/images/hub/ChoosePlanView/search.svg From e04c6524d2d6a5a3efb3509336beecef4585c99f Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 23:15:51 -0500 Subject: [PATCH 28/30] Update copywrite year --- app/shared-components/RadioButton/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/shared-components/RadioButton/index.js b/app/shared-components/RadioButton/index.js index 04cf4d177..a4160127a 100644 --- a/app/shared-components/RadioButton/index.js +++ b/app/shared-components/RadioButton/index.js @@ -4,7 +4,7 @@ * Ghostery Browser Extension * https://www.ghostery.com/ * - * Copyright 2019 Ghostery, Inc. All rights reserved. + * Copyright 2020 Ghostery, Inc. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this From cd70f46c03d466446844036f631cf82db5eefa64 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 23:20:26 -0500 Subject: [PATCH 29/30] Replace hex color codes with variables --- .../Step4_ChoosePlanView/ChoosePlanView.scss | 22 +++++++++---------- app/scss/partials/_colors.scss | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.scss b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.scss index bbdb20a40..90d077b78 100644 --- a/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.scss +++ b/app/ghostery-browser-hub/Views/OnboardingViews/Step4_ChoosePlanView/ChoosePlanView.scss @@ -18,7 +18,7 @@ height: 381px; margin: 48px auto 0 auto; border-radius: 4px; - border: solid 4px #00aef0; + border: solid 4px $ghosty-blue; } .ChoosePlanView__searchLogo { height: 37px; @@ -48,7 +48,7 @@ font-size: 16px; line-height: 1.38; text-align: center; - color: #4a4a4a; + color: $tundora; } .ChoosePlanView__searchCTAButton { display: flex; @@ -61,13 +61,13 @@ background: linear-gradient( 45deg, #ff7e74 50%, - #00aef0 + $ghosty-blue ); background-size: 200% 100%; background-position: 100% 50%; transition: 0.25s all; border: none; - color: #FFF; + color: $white; font-size: 14.1px; font-weight: 700; border-radius: 3.5px; @@ -80,7 +80,7 @@ transition: 0.25s all; } &:focus { - color: #FFF; + color: $white; } } .ChoosePlanView__premiumCTAButton { @@ -100,7 +100,7 @@ background-position: 100% 50%; transition: 0.25s all; border: none; - color: #FFF; + color: $white; font-size: 14.1px; font-weight: 700; border-radius: 3.5px; @@ -118,7 +118,7 @@ margin-top: 48px; display: flex; justify-content: center; - color: #00aef0; + color: $ghosty-blue; font-size: 16px; text-decoration: underline; cursor: pointer; @@ -144,7 +144,7 @@ padding: 0 66px; height: 180px; font-size: 24px; - color: #4a4a4a; + color: $tundora; } .ChoosePlanView__ctaButtonContainer { display: flex; @@ -157,8 +157,8 @@ margin: 15px auto 0 auto; height: 12px; width: 12px; - border-left: 2px solid #00aef0; - border-top: 2px solid #00aef0; + border-left: 2px solid $ghosty-blue; + border-top: 2px solid $ghosty-blue; cursor: pointer; &.down { @@ -180,7 +180,7 @@ border: 4px solid white; &:hover, &.checked { - border: 4px solid #00aef0; + border: 4px solid $ghosty-blue; .ghostery-free-image-container, .ghostery-plus-image-container, .ghostery-premium-image-background { diff --git a/app/scss/partials/_colors.scss b/app/scss/partials/_colors.scss index cd15e484b..3b99e216c 100644 --- a/app/scss/partials/_colors.scss +++ b/app/scss/partials/_colors.scss @@ -49,8 +49,8 @@ $spring-green: #6aa103; /* MARKETING COLORS */ $red: #E74055; $purple: #720174; -$dark-purple: #5B005C; -$dark-magenta: #920094; +$dark-purple: #5B005C; +$dark-magenta: #920094; $sinopia: #D3451E; $apple: #67A73A; //button_special $caper: #CEECAF; //success-color From c9c5eed6d552628717a6a0fbc84a8b653f0349a5 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 5 Dec 2020 23:24:01 -0500 Subject: [PATCH 30/30] Add border to unchecked radio button --- app/scss/partials/_radio_button.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scss/partials/_radio_button.scss b/app/scss/partials/_radio_button.scss index ead8d17fa..7675d62e6 100644 --- a/app/scss/partials/_radio_button.scss +++ b/app/scss/partials/_radio_button.scss @@ -44,9 +44,10 @@ &.altDesign { height: 24px; width: 24px; - border: none; + border: 1px solid black; &.checked { background-color: #00aef0; + border: none; } } &.checked:not(.altDesign) {