diff --git a/app/hub/Views/SetupViews/SetupAntiSuiteView/SetupAntiSuiteViewContainer.jsx b/app/hub/Views/SetupViews/SetupAntiSuiteView/SetupAntiSuiteViewContainer.jsx
index f0ed52027..42d541b67 100644
--- a/app/hub/Views/SetupViews/SetupAntiSuiteView/SetupAntiSuiteViewContainer.jsx
+++ b/app/hub/Views/SetupViews/SetupAntiSuiteView/SetupAntiSuiteViewContainer.jsx
@@ -36,7 +36,7 @@ class SetupAntiSuiteViewContainer extends Component {
activeIndex: index,
hrefPrev: `/setup/${index - 1}`,
hrefNext: `/setup/${index + 1}`,
- hrefDone: '/',
+ hrefDone: '/home',
textPrev: t('previous'),
textNext: t('next'),
textDone: t('hub_setup_exit_flow'),
diff --git a/app/hub/Views/SetupViews/SetupBlockingView/SetupBlockingViewContainer.jsx b/app/hub/Views/SetupViews/SetupBlockingView/SetupBlockingViewContainer.jsx
index b50fa624f..193445ade 100644
--- a/app/hub/Views/SetupViews/SetupBlockingView/SetupBlockingViewContainer.jsx
+++ b/app/hub/Views/SetupViews/SetupBlockingView/SetupBlockingViewContainer.jsx
@@ -38,7 +38,7 @@ class SetupBlockingViewContainer extends Component {
activeIndex: index,
hrefPrev: false,
hrefNext: `/setup/${index + 1}`,
- hrefDone: '/',
+ hrefDone: '/home',
textPrev: false,
textNext: t('next'),
textDone: t('hub_setup_exit_flow'),
diff --git a/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx b/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx
index 3ee04fcb9..5b649ea5d 100644
--- a/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx
+++ b/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx
@@ -31,8 +31,8 @@ class SetupDoneViewContainer extends Component {
props.actions.setSetupNavigation({
activeIndex: index,
hrefPrev: `/setup/${index - 1}`,
- hrefNext: '/',
- hrefDone: '/',
+ hrefNext: '/home',
+ hrefDone: '/home',
textPrev: t('previous'),
textNext: t('done'),
textDone: t('hub_setup_exit_flow'),
diff --git a/app/hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebViewContainer.jsx b/app/hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebViewContainer.jsx
index 9657fc595..96acc7156 100644
--- a/app/hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebViewContainer.jsx
+++ b/app/hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebViewContainer.jsx
@@ -32,7 +32,7 @@ class SetupHumanWebViewContainer extends Component {
activeIndex: index,
hrefPrev: `/setup/${index - 1}`,
hrefNext: `/setup/${index + 1}`,
- hrefDone: '/',
+ hrefDone: '/home',
textPrev: t('previous'),
textNext: t('next'),
textDone: t('hub_setup_exit_flow'),
diff --git a/app/hub/Views/SideNavigationView/SideNavigationView.scss b/app/hub/Views/SideNavigationView/SideNavigationView.scss
index 8e00c3116..7a2a31b29 100644
--- a/app/hub/Views/SideNavigationView/SideNavigationView.scss
+++ b/app/hub/Views/SideNavigationView/SideNavigationView.scss
@@ -126,6 +126,10 @@ a .SideNavigation__menuIcon.home,
a.disabled.active .SideNavigation__menuIcon.home {
background-image: buildIconHome(#ffffff);
}
+a .SideNavigation__menuIcon.shield,
+a.disabled.active .SideNavigation__menuIcon.shield {
+ background-image: buildIconShield(#ffffff);
+}
a .SideNavigation__menuIcon.setup,
a.disabled.active .SideNavigation__menuIcon.setup {
background-image: buildIconSetup(#ffffff);
@@ -153,6 +157,9 @@ a.disabled.active .SideNavigation__menuIcon.profile {
a.disabled .SideNavigation__menuIcon.home {
background-image: buildIconHome(#a9b9be);
}
+a.disabled .SideNavigation__menuIcon.shield {
+ background-image: buildIconShield(#a9b9be);
+}
a.disabled .SideNavigation__menuIcon.setup {
background-image: buildIconSetup(#a9b9be);
}
diff --git a/app/hub/Views/SideNavigationView/SideNavigationViewContainer.jsx b/app/hub/Views/SideNavigationView/SideNavigationViewContainer.jsx
index 77492fdcf..0fa5028e5 100644
--- a/app/hub/Views/SideNavigationView/SideNavigationViewContainer.jsx
+++ b/app/hub/Views/SideNavigationView/SideNavigationViewContainer.jsx
@@ -50,7 +50,8 @@ class SideNavigationViewContainer extends Component {
const disableRegEx = /^(\/setup(?!\/4$))|(\/tutorial(?!\/6$))/;
const menuItems = [
- { href: '/', icon: 'home', text: t('hub_side_navigation_home') },
+ { href: '/home', icon: 'home', text: t('hub_side_navigation_home') },
+ { href: '/', icon: 'shield', text: t('hub_side_navigation_upgrade_plan') },
{ href: '/setup', icon: 'setup', text: t('customize_setup') },
{ href: '/tutorial', icon: 'tutorial', text: t('hub_side_navigation_tutorial') },
{ href: '/plus', icon: 'plus', text: t('get_ghostery_plus') },
diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx
index fccaca98e..5313f9b07 100644
--- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx
@@ -31,8 +31,8 @@ class TutorialAntiSuiteViewContainer extends Component {
props.actions.setTutorialNavigation({
activeIndex: index,
hrefPrev: `/tutorial/${index - 1}`,
- hrefNext: '/',
- hrefDone: '/',
+ hrefNext: '/home',
+ hrefDone: '/home',
textPrev: t('previous'),
textNext: t('done'),
textDone: t('hub_tutorial_exit_flow'),
diff --git a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx
index 246ac22d1..5210ca461 100644
--- a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx
@@ -32,7 +32,7 @@ class TutorialBlockingViewContainer extends Component {
activeIndex: index,
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: `/tutorial/${index + 1}`,
- hrefDone: '/',
+ hrefDone: '/home',
textPrev: t('previous'),
textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
diff --git a/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx
index 407bf8fa9..59c5f0208 100644
--- a/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx
@@ -32,7 +32,7 @@ class TutorialLayoutViewContainer extends Component {
activeIndex: index,
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: `/tutorial/${index + 1}`,
- hrefDone: '/',
+ hrefDone: '/home',
textPrev: t('previous'),
textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
diff --git a/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx
index b59c40b1d..9aeab240b 100644
--- a/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx
@@ -32,7 +32,7 @@ class TutorialTrackerListViewContainer extends Component {
activeIndex: index,
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: `/tutorial/${index + 1}`,
- hrefDone: '/',
+ hrefDone: '/home',
textPrev: t('previous'),
textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
diff --git a/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx
index f48598ad0..42d8e341e 100644
--- a/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx
@@ -32,7 +32,7 @@ class TutorialTrustViewContainer extends Component {
activeIndex: index,
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: `/tutorial/${index + 1}`,
- hrefDone: '/',
+ hrefDone: '/home',
textPrev: t('previous'),
textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
diff --git a/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx
index a6af3c5ce..23659b366 100644
--- a/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx
@@ -32,7 +32,7 @@ class TutorialVideoViewContainer extends Component {
activeIndex: index,
hrefPrev: false,
hrefNext: `/tutorial/${index + 1}`,
- hrefDone: '/',
+ hrefDone: '/home',
textPrev: false,
textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
diff --git a/app/hub/Views/UpgradePlanView/UpgradePlanView.jsx b/app/hub/Views/UpgradePlanView/UpgradePlanView.jsx
new file mode 100644
index 000000000..15967b4e1
--- /dev/null
+++ b/app/hub/Views/UpgradePlanView/UpgradePlanView.jsx
@@ -0,0 +1,524 @@
+/**
+ * Upgrade 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, { useRef, Fragment } from 'react';
+import ClassNames from 'classnames';
+import PropTypes from 'prop-types';
+import { NavLink } from 'react-router-dom';
+import { BASIC, PLUS, PREMIUM } from './UpgradePlanViewConstants';
+import globals from '../../../../src/classes/Globals';
+
+const featureMatrixRow = (label, isBasic, isPlus, isSparkle) => (
+
+
+ {label}
+ {isSparkle &&
+
+ }
+
+
+ {isBasic &&
+
+ }
+
+
+ {isPlus &&
+
+ }
+
+
+
+
+
+);
+
+const mobileFeatureMatrixRow = (label, isBasic, isPlus, isSparkle) => (
+
+
+
+ {label}
+ {isSparkle &&
+
+ }
+
+
+
+ {isBasic ? (
+
+
+
+ ) : (
+
+
+
+ )}
+ {isPlus ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+);
+
+const basicCard = () => (
+
+
+
+
+
Ghostery
+
+
{t('hub_upgrade_plan_free')}
+
+
+ {t('hub_upgrade_already_protected')}
+
+
{t('hub_upgrade_basic_protection')}
+
+
+ {t('hub_upgrade_basic_browser_protection')}
+
+
+
+);
+
+/**
+ * A React class component for rendering the Upgrade Plan View
+ * @return {JSX} JSX for rendering the Upgrade Plan View of the Hub app
+ * @memberof HubComponents
+ */
+const UpgradePlanView = (props) => {
+ const {
+ protection_level,
+ show_yearly_prices,
+ user,
+ actions,
+ } = props;
+
+ const {
+ toggleMonthlyYearlyPrices,
+ setBasicProtection,
+ setPlusProtection,
+ setPremiumProtection
+ } = actions;
+
+ const isPlus = (user && user.plusAccess) || false;
+ const isPremium = (user && user.premiumAccess) || false;
+
+ const sliderClassNames = ClassNames('switch-check', {
+ checked: show_yearly_prices
+ });
+ const tabsTitleBlueClassNames = ClassNames('tabs-title tabs-title-blue', {
+ 'is-active': protection_level === BASIC
+ });
+ const tabsTitleGoldClassNames = ClassNames('tabs-title tabs-title-gold', {
+ 'is-active': protection_level === PLUS
+ });
+ const tabsTitlePurpleClassNames = ClassNames('tabs-title tabs-title-purple', {
+ 'is-active': protection_level === PREMIUM
+ });
+ const monthlyToggleLabel = ClassNames('toggle-label', {
+ active: !show_yearly_prices
+ });
+ const yearlyToggleLabel = ClassNames('toggle-label', {
+ active: show_yearly_prices
+ });
+
+ // Clicking arrow scrolls to table
+ const comparisonTableRef = useRef(null);
+ const scrollToComparisonTable = () => {
+ comparisonTableRef.current.scrollIntoView({ behavior: 'smooth' });
+ };
+ // Clicking arrow scrolls to table for mobile view
+ const mobileComparisonTableRef = useRef(null);
+ const scrollToMobileComparisonTable = () => {
+ mobileComparisonTableRef.current.scrollIntoView({ behavior: 'smooth' });
+ };
+
+ // UTM params
+ const signedIn = +!!user;
+ const subscriptionType = () => {
+ if (isPremium) return 'PREMIUM';
+ if (isPlus) return 'SUPPORTER';
+ return '-1';
+ };
+ // Interval is the query Param to show monthly/yearly pricing in checkout web, also used as a ping parameter
+ const interval = show_yearly_prices ? 'year' : 'month';
+ const utmParams = `utm_source=gbe&utm_campaign=intro_hub_c_1&signedIn=${signedIn}&st=${subscriptionType()}&subscription_interval=${interval}`;
+
+ const plusCheckoutLink = `${globals.CHECKOUT_BASE_URL}/plus?interval=${interval}&${utmParams}`;
+ const premiumCheckoutLink = `${globals.CHECKOUT_BASE_URL}/premium?interval=${interval}&${utmParams}`;
+
+ const plusCTAButton = () => (
+ isPlus ? (
+
+ {t('hub_upgrade_already_protected')}
+
+ ) : (
+
+ {`${t('hub_upgrade_to')} Plus`}
+
+ )
+ );
+
+ const premiumCTAButton = () => (
+ isPremium ? (
+
+ {t('hub_upgrade_already_protected')}
+
+ ) : (
+
+ {`${t('hub_upgrade_to')} Premium`}
+
+ )
+ );
+
+ const toggleSwitch = (mobileView, secondToggle) => {
+ const toggleSwitchClassNames = ClassNames('small-12 text-center columns', {
+ 'toggle-switch-row': mobileView,
+ 'second-toggle': secondToggle,
+ });
+ return (
+
+
+ {t('hub_upgrade_monthly')}
+
+
+
+
+ {t('hub_upgrade_yearly')}
+
+
+ );
+ };
+
+ const plusCard = mobileView => (
+
+
+
+
Ghostery Plus
+
+ {show_yearly_prices ? (
+
+ $3.99
+ {t('per_month')}
+
+
{`( $47.88 ${t('per_year')})`}
+
+
+ ) : (
+
+ $4.99
+ {t('per_month')}
+
+ )}
+
+ {mobileView && toggleSwitch(true)}
+ {plusCTAButton()}
+
{t('hub_upgrade_additional_protection')}
+
+
+ {t('hub_upgrade_basic_browser_protection')}
+
+
+
+ {t('hub_upgrade_advanced_device_protection')}
+
+
+
+ );
+
+ const premiumCard = mobileView => (
+
+
+
+
+
Ghostery Premium
+
+ {show_yearly_prices ? (
+
+ $8.99
+ {t('per_month')}
+
+
{`( $107.88 ${t('per_year')})`}
+
+
+ ) : (
+
+ $11.99
+ {t('per_month')}
+
+ )}
+
+ {mobileView && toggleSwitch(true)}
+ {premiumCTAButton()}
+
+ {t('hub_upgrade_maximum_browser_protection')}
+
+
+
+ {t('hub_upgrade_basic_browser_protection')}
+
+
+
+ {t('hub_upgrade_advanced_device_protection')}
+
+
+
+ VPN
+
+
+
+ );
+
+ return (
+
+
+
+
+
{`${t('hub_upgrade_your')} Ghostery ${t('hub_upgrade_protection_plan')}`}
+ {toggleSwitch()}
+
+
+
+
+
+
+ {basicCard()}
+ {plusCard()}
+ {premiumCard()}
+
+
+
+
+
+
+
{`${t('hub_upgrade_your')} Ghostery ${t('hub_upgrade_protection_plan')}`}
+
+
+
+
+
+ {t('hub_upgrade_plan_free')}
+ Plus
+ Premium
+
+
+
+
+ {protection_level === BASIC && basicCard()}
+ {protection_level === PLUS && plusCard(true)}
+ {protection_level === PREMIUM && premiumCard(true)}
+
+
+
+
+
{t('hub_upgrade_scroll_down')}
+
+
+
+
+
+
{t('hub_upgrade_scroll_down')}
+
+
+
+
+
+
+
+
+
+ Ghostery
+
+
+ Ghostery Plus
+
+
+ Ghostery Premium
+
+
+
+
+ {`- ${t('hub_upgrade_midnight_note')}`}
+
+
+
+
+
+ Ghostery
+ Ghostery Plus
+ Ghostery Premium
+
+
+
+ {featureMatrixRow(t('hub_upgrade_browser_tracker_blocking'), true, true)}
+ {featureMatrixRow(t('hub_upgrade_browser_ad_blocking'), true, true)}
+ {featureMatrixRow(t('hub_upgrade_custom_blocking_preferences'), true, true)}
+ {featureMatrixRow(t('hub_upgrade_extension_themes'), false, true)}
+ {featureMatrixRow(t('hub_upgrade_historical_extension_stats'), false, true)}
+ {featureMatrixRow(t('hub_upgrade_application_tracker_blocking'), false, true, true)}
+ {featureMatrixRow(t('hub_upgrade_application_ad_blocking'), false, true, true)}
+ {featureMatrixRow('VPN', false, false, true)}
+ {featureMatrixRow(t('hub_upgrade_no_vpn_logs'), false, false, true)}
+ {featureMatrixRow(`P2P ${t('support')}`, false, false, true)}
+ {featureMatrixRow(`IPv6 ${t('hub_upgrade_leak_protection')}`, false, false, true)}
+ {featureMatrixRow(t('hub_upgrade_physical_servers'), false, false, true)}
+ {featureMatrixRow(t('hub_upgrade_unlimited_bandwidth'), false, false, true)}
+
+
+
+
+ {t('hub_upgrade_already_protected')}
+
+
+
+ {plusCTAButton()}
+
+
+ {premiumCTAButton()}
+
+
+
+
+
+
+
+
+
+
+
+ {`- ${t('hub_upgrade_midnight_note')}`}
+
+
+
+ {toggleSwitch(true, true)}
+
+
+
+
{t('ghostery_basic')}
+
+
+
+
+
+
+
{t('hub_upgrade_plan_free')}
+
+
+ {show_yearly_prices ? (
+
$3.99
+ ) : (
+
$4.99
+ )}
+
+
+ {show_yearly_prices ? (
+
$8.99
+ ) : (
+
$11.99
+ )}
+
+
+
+
+
+
+
+
+ {mobileFeatureMatrixRow(t('hub_upgrade_browser_tracker_blocking'), true, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_browser_ad_blocking'), true, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_custom_blocking_preferences'), true, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_extension_themes'), false, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_historical_extension_stats'), false, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_application_tracker_blocking'), false, true, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_application_ad_blocking'), false, true, true)}
+ {mobileFeatureMatrixRow('VPN', false, false, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_no_vpn_logs'), false, false, true)}
+ {mobileFeatureMatrixRow(`P2P ${t('support')}`, false, false, true)}
+ {mobileFeatureMatrixRow(`IPv6 ${t('hub_upgrade_leak_protection')}`, false, false, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_physical_servers'), false, false, true)}
+ {mobileFeatureMatrixRow(t('hub_upgrade_unlimited_bandwidth'), false, false, true)}
+
+
+
+
+
+
+
+
+ {t('hub_upgrade_already_protected')}
+
+
+
+
+
+ {plusCTAButton()}
+
+
+
+
+ {premiumCTAButton()}
+
+
+
+
+
+
+ );
+};
+
+// PropTypes ensure we pass required props of the correct type
+UpgradePlanView.propTypes = {
+ protection_level: PropTypes.string.isRequired,
+ show_yearly_prices: PropTypes.bool.isRequired,
+ user: PropTypes.shape({
+ email: PropTypes.string,
+ plusAccess: PropTypes.bool,
+ premiumAccess: PropTypes.bool,
+ }),
+ actions: PropTypes.shape({
+ toggleMonthlyYearlyPrices: PropTypes.func.isRequired,
+ setBasicProtection: PropTypes.func.isRequired,
+ setPlusProtection: PropTypes.func.isRequired,
+ setPremiumProtection: PropTypes.func.isRequired,
+ }).isRequired,
+};
+
+// Default props used on the Home View
+UpgradePlanView.defaultProps = {
+ user: {
+ email: '',
+ plusAccess: false,
+ premiumAccess: false,
+ },
+};
+
+export default UpgradePlanView;
diff --git a/app/hub/Views/UpgradePlanView/UpgradePlanView.scss b/app/hub/Views/UpgradePlanView/UpgradePlanView.scss
new file mode 100644
index 000000000..2e9b3d460
--- /dev/null
+++ b/app/hub/Views/UpgradePlanView/UpgradePlanView.scss
@@ -0,0 +1,783 @@
+$price-blue: #00AEF0;
+$price-blue-hover: #0078CA;
+$blue-alt: #4caeea;
+$price-purple: #611b87;
+$price-purple-alt: #720174;
+$price-purple-hover: #710d72;
+$price-gold: #b8860b;
+$price-gold-hover: #906908;
+$medium-large-breakpoint: 1118px; // Break when 3 cards on the screen overflow to next line
+
+.font-size-36 {
+ font-size: rem-calc(36);
+}
+.font-size-12 {
+ font-size: rem-calc(12);
+}
+
+.page-template-page-content-modules,
+section.home-template .section.section-pricing {
+ .show-for-extra-large {
+ @include breakpoint($medium-large-breakpoint down) {
+ display: none;
+ }
+ }
+ .hide-for-extra-large {
+ display: none;
+ @include breakpoint($medium-large-breakpoint down) {
+ display: block;
+ }
+ }
+ main {
+ padding-bottom: 0;
+ }
+ h1 {
+ margin: rem-calc(40) 0 54px 0;
+ color: $tundora;
+ font-size: rem-calc(24);
+ font-family: Roboto;
+ font-stretch: condensed;
+ @include breakpoint($medium-large-breakpoint down) {
+ margin: 40px auto 22px auto;
+ }
+ }
+ .toggle-switch {
+ span {
+ vertical-align: middle;
+ font-size: 18px;
+ color: #cad3d5;
+ @include breakpoint($medium-large-breakpoint down) {
+ font-size: rem-calc(12);
+ }
+ &.toggle-label.active {
+ color: #4a4a4a;
+ }
+ }
+ }
+ .tabs {
+ border-radius: 4px;
+ border: 2px solid #6a6a6a;
+ }
+
+ .tabs-content {
+ border: none;
+ background-color: $white;
+ @include breakpoint($medium-large-breakpoint down) {
+ margin-top: 32px;
+ }
+ }
+
+ .tabs-title {
+ &:not(.is-active) {
+ cursor: pointer;
+ }
+ &-blue {
+ border-right: 2px solid #6a6a6a;
+ &.is-active {
+ background-color: $price-blue;
+ color: #FFF;
+ }
+ &:hover {
+ background-color: $price-blue;
+ color: $white;
+ }
+ }
+ &-gold {
+ border-right: 2px solid #6a6a6a;
+ &.is-active {
+ background-color: $price-gold;
+ color: #FFF;
+ }
+ &:hover {
+ background-color: $price-gold;
+ color: $white;
+ }
+ }
+ &-purple {
+ &.is-active {
+ background-image: linear-gradient(112deg, #5c218b, #00aef0);
+ color: #FFF;
+ }
+ &:hover {
+ background-image: linear-gradient(112deg, #5c218b, #00aef0);
+ color: $white;
+ }
+ }
+ }
+ .tabs-title>a:focus {
+ background-color: transparent;
+ color: $white;
+ }
+ .tabs-title>a:hover {
+ background-color: $price-blue;
+ color: $white;
+ }
+ #price-tabs-lower {
+ a {
+ padding: 0.7rem 1rem;
+ }
+ }
+
+ .tiers-group {
+ margin-top: rem-calc(20);
+ margin-bottom: rem-calc(50);
+ list-style-type: none;
+ display: flex;
+ @include breakpoint($medium-large-breakpoint down) {
+ margin-bottom: rem-calc(10);
+ margin-top: rem-calc(40);
+ margin: auto;
+ }
+ li {
+ width: 120px;
+ height: 30px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ @include breakpoint(small down) {
+ width: 75px;
+ }
+ a {
+ color: #6a6a6a;
+ font-size: rem-calc(12);
+ font-family: 'Roboto';
+ }
+ &.is-active {
+ a {
+ color: $white;
+ }
+ }
+ }
+ }
+ .switch {
+ position: relative;
+ display: inline-block;
+ width: 60px;
+ height: 34px;
+ margin-left: rem-calc(30);
+ margin-right: rem-calc(30);
+ }
+
+ /* Hide default HTML checkbox */
+ .switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+
+ }
+
+ /* The slider */
+ .slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: $mystic;
+ -webkit-transition: .4s;
+ transition: .4s;
+ border: 2px solid #6a6a6a;
+ }
+
+ .slider:before {
+ position: absolute;
+ content: "";
+ height: 26px;
+ width: 26px;
+ left: 2px;
+ bottom: 2px;
+ background-color: #6a6a6a;
+ -webkit-transition: .4s;
+ transition: .4s;
+ }
+
+ input.checked + .slider {
+ background-color: $mystic;
+ }
+
+ input:focus + .slider {
+ box-shadow: 0 0 1px $mystic;
+ }
+
+ input.checked + .slider:before {
+ -webkit-transform: translateX(26px);
+ -ms-transform: translateX(26px);
+ transform: translateX(26px);
+ }
+
+ /* Rounded sliders */
+ .slider.round {
+ border-radius: 34px;
+ }
+
+ .slider.round:before {
+ border-radius: 50%;
+ }
+
+ .card-wrapper {
+ margin-top: rem-calc(80);
+ @include breakpoint($medium-large-breakpoint down) {
+ margin-top: 0;
+ }
+ }
+ .card-outer {
+ 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);
+ }
+ }
+ }
+ .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%;
+ }
+ }
+ }
+ .card {
+ height: 482px;
+ 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(40);
+ 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;
+ width: 177px;
+ height: 38px;
+ line-height: 22px;
+ &.already-protected {
+ @include breakpoint($medium-large-breakpoint down) {
+ margin-top: 45px;
+ }
+ }
+ }
+ .card-sub-header {
+ font-size: 14px;
+ }
+ }
+
+ .premium-sparkle {
+ margin-left: 5px;
+ display: inline-block;
+ vertical-align: middle;
+ height: 14px;
+ width: 12px;
+ background-repeat: no-repeat;
+ background-image: url('/app/images/premium-sparkle.svg');
+ }
+ .check {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ background-repeat: no-repeat;
+ margin-top: 5px;
+ &.blue {
+ background-image: buildCheckIcon($price-blue);
+ }
+ &.yellow {
+ background-image: buildCheckIcon($price-gold);
+ }
+ &.purple {
+ background-image: buildCheckIcon($price-purple);
+ }
+ }
+ .x-icon {
+ display: inline-block;
+ height: 14px;
+ width: 14px;
+ background-image: url('/app/images/hub/upgrade/x-icon.svg')
+ }
+ .hide-for-extra-large {
+ .protection-description {
+ font-weight: bold;
+ margin: 20px 0 15px 0;
+ &.blue {
+ color: $price-blue;
+ }
+ &.yellow {
+ color: $price-gold;
+ }
+ &.purple {
+ color: $price-purple;
+ }
+ }
+ .footer-buttons {
+ .button {
+ width: 410px;
+ margin-top: rem-calc(25);
+ text-transform: none;
+ }
+ }
+ .protection-header {
+ margin-bottom: rem-calc(15);
+ font-size: 18px;
+ }
+ .protection-header-plus-yearly {
+ display: none;
+ &.is-active {
+ display: block;
+ }
+ }
+ }
+ .hide-for-extra-large {
+ @media only screen and (max-width: 740px) {
+ .card {
+ box-shadow: none;
+ margin-bottom: 0;
+ padding-bottom: rem-calc(15);
+ }
+ }
+ .price {
+ min-height: auto;
+ font-size: rem-calc(12);
+ }
+ .toggle-switch {
+ margin-bottom: 20px;
+ .toggle-switch-row {
+ margin-top: 22px;
+ }
+ .second-toggle {
+ margin-top: 0;
+ }
+ }
+ .table-header {
+ margin-top: rem-calc(20);
+ font-size: rem-calc(18);
+ }
+
+ .checkmark {
+ display: none;
+ &.is-active {
+ display: inline-block;
+ }
+ &-gray {
+ display: none;
+ &.is-active {
+ display: inline-block;
+ }
+ }
+ }
+ tbody > tr:nth-child(2n) {
+ border-bottom: 1px solid #b6b6b6;
+ }
+ .table-container {
+ flex: 0 0 auto;
+ @include breakpoint($medium-large-breakpoint down) {
+ max-width: 100%;
+ }
+ }
+ }
+
+
+ .tick { font-size:18px; color:$price-blue; }
+
+ .module-editor .learn-more {
+ color: $purple;
+ text-decoration: underline;
+ margin: rem-calc(15) auto 25px auto;
+ width: 120px;
+ cursor: pointer;
+ @include breakpoint($medium-large-breakpoint down) {
+ margin-top: rem-calc(5);
+ }
+ }
+ .module-editor .arrow {
+ background-image: url('/app/images/hub/upgrade/arrow-down.svg');
+ width: 30px;
+ height: 16px;
+ margin-top: rem-calc(25);
+ margin: auto;
+ cursor: pointer
+ }
+
+ .key-container {
+ height: 70px;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ &.mobile {
+ @include breakpoint($medium-large-breakpoint up) {
+ display: none
+ }
+ }
+ @include breakpoint($medium-large-breakpoint down) {
+ justify-content: center;
+ }
+ .midnight-note {
+ margin-left: 15px;
+ color: $price-purple-alt;
+ }
+ }
+
+ .button {
+ text-transform: none;
+ white-space: nowrap;
+ font-family: 'Open Sans';
+ background-color: $price-blue;
+ font-weight: 600;
+ &:hover {
+ background-color: $price-blue-hover;
+ }
+ }
+
+ .button-gold {
+ background-color: $price-gold;
+ border: none;
+ &:hover {
+ background-color: $price-gold-hover;
+ }
+ }
+ .button-premium {
+ height: 38px;
+ width: 177px;
+ 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;
+ &:hover {
+ background-position: 0% 50%;
+ transition: 0.25s all;
+ }
+ }
+
+ .comparison-table {
+ background-color: $alabaster;
+ padding-bottom: rem-calc(100);
+ margin-top: rem-calc(40);
+ @include breakpoint($medium-large-breakpoint down) {
+ margin-top: 0;
+ padding-top: 0;
+ background-color: $white;
+ }
+ ul {
+ display:flex;
+ top:0px;
+ z-index:10;
+ padding-bottom:14px;
+ margin: 0;
+ @include breakpoint($medium-large-breakpoint down) {
+ padding-bottom: 0;
+ margin-bottom: rem-calc(40);
+ }
+ }
+ li {
+ list-style:none;
+ flex:1;
+ &:hover {
+ cursor: pointer;
+ }
+ }
+ li:last-child {
+ border-right:1px solid #b6b6b6;
+ @include breakpoint($medium-large-breakpoint down) {
+ border-right: none;
+ }
+ }
+ button {
+ width:100%;
+ padding: 10px;
+ font-size:14px;
+ height:60px;
+ color: $white;
+ text-transform: none;
+ &:hover {
+ cursor: pointer;
+ }
+ }
+ li.active button {
+ color: $white;
+ font-weight:bold;
+ }
+ @media only screen and (min-width: 832px) {
+ .table {
+ border-collapse:collapse;
+ width:100%;
+ max-width: 750px;
+ }
+ }
+ .mobile-table-header {
+ position: sticky;
+ top: 0;
+ background-color: #FFF;
+ }
+ table {
+ border-collapse:collapse;
+ width:100%;
+ max-width: 750px;
+ @include breakpoint($medium-large-breakpoint down) {
+ table-layout: fixed;
+ }
+ }
+ tbody {
+ @include breakpoint($medium-large-breakpoint down) {
+ border: 1px solid #b6b6b6;
+ }
+ }
+ th {
+ background:$alabaster; display:none; color: $white;
+ font-family: 'Open Sans';
+ font-size: rem-calc(14);
+ font-weight: normal;
+ }
+ td {
+ font-size: rem-calc(12);
+ }
+ td, th {
+ height:53px;
+ max-width: 120px;
+ }
+ td,th {
+ border: 1px solid #b6b6b6;
+ padding: 10px;
+ empty-cells:show;
+ @include breakpoint($medium-large-breakpoint down) {
+ border: none;
+ }
+ }
+ td,th {
+ text-align:left;
+ @include breakpoint($medium-large-breakpoint down) {
+ text-align: center;
+ }
+ }
+ td+td, th+th {
+ text-align:center;
+ }
+ td.default {
+ display:table-cell;
+ }
+ tbody {
+ @include breakpoint($medium-large-breakpoint up) {
+ tr:nth-child(2n) {
+ background-color: #F7F7F7;
+ }
+ tr:nth-child(2n+1) {
+ background-color: #FFF;
+ }
+ }
+ @include breakpoint ($medium-large-breakpoint down) {
+ tr:nth-child(4n), tr:nth-child(4n+3) {
+ background-color: #FFF;
+ }
+ tr:nth-child(4n+2), tr:nth-child(4n+1) {
+ background-color: #F7F7F7;
+ }
+ }
+ }
+ tr:last-child > td {
+ border: none;
+ }
+ tr:last-child > td > a {
+ width: 104%;
+ height: 38px;
+ padding: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .feature-title {
+ margin-right: 6px;
+ }
+ .bg-blue {
+ background-color: $price-blue;
+ }
+ .bg-gold {
+ background-color: $price-gold;
+ }
+ .bg-purple-blue {
+ background-image: linear-gradient(120deg, #720174 0%, #5a258e 18%, #2a6ec2 57%, #0c9ce3 86%, #00aef0 100%);
+ }
+ .sep {
+ background:$alabaster;
+ font-weight:bold;
+ }
+ .txt-l { font-size:28px; font-weight:bold; }
+ .txt-top { position:relative; top:-9px; left:-2px; }
+
+ .hide {
+ border:0;
+ background:none;
+ }
+ .button {
+ margin-bottom: 0;
+ @include breakpoint($medium-large-breakpoint up) {
+ height: 38px;
+ display: flex;
+ align-items: center;
+ }
+ @include breakpoint($medium-large-breakpoint down) {
+ padding-left: rem-calc(20);
+ padding-right: rem-calc(20);
+ }
+ }
+ @include breakpoint(medium up) {
+ ul {
+ display:none;
+ }
+ td,th {
+ display:table-cell !important;
+ }
+ tr > td:first-child {
+ width: 200px;
+ max-width: 200px;
+ }
+ }
+
+ @include breakpoint(large up) {
+ td,th {
+ width: 200px;
+ max-width: 200px;
+
+ }
+ td+td, th+th {
+ width: 166px;
+ max-width: 166px;
+ }
+ }
+ }
+}
diff --git a/app/hub/Views/UpgradePlanView/UpgradePlanViewActions.js b/app/hub/Views/UpgradePlanView/UpgradePlanViewActions.js
new file mode 100644
index 000000000..0db4ad954
--- /dev/null
+++ b/app/hub/Views/UpgradePlanView/UpgradePlanViewActions.js
@@ -0,0 +1,59 @@
+/**
+ * UpgradePlanView Action creators
+ *
+ * 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 {
+ TOGGLE_MONTHLY_YEARLY_PRICES,
+ SET_BASIC_PROTECTION,
+ SET_PLUS_PROTECTION,
+ SET_PREMIUM_PROTECTION
+} from './UpgradePlanViewConstants';
+
+/**
+ * Toggle Monthly/Yearly Prices
+ * @return {Object}
+ */
+export function toggleMonthlyYearlyPrices() {
+ return {
+ type: TOGGLE_MONTHLY_YEARLY_PRICES,
+ };
+}
+
+/**
+ * Set Basic protection on medium or smaller screen sizes
+ * @return {Object}
+ */
+export function setBasicProtection() {
+ return {
+ type: SET_BASIC_PROTECTION,
+ };
+}
+
+/**
+ * Set Plus protection on medium or smaller screen sizes
+ * @return {Object}
+ */
+export function setPlusProtection() {
+ return {
+ type: SET_PLUS_PROTECTION,
+ };
+}
+
+/**
+ * Set Premium protection on medium or smaller screen sizes
+ * @return {Object}
+ */
+export function setPremiumProtection() {
+ return {
+ type: SET_PREMIUM_PROTECTION,
+ };
+}
diff --git a/app/hub/Views/UpgradePlanView/UpgradePlanViewConstants.js b/app/hub/Views/UpgradePlanView/UpgradePlanViewConstants.js
new file mode 100644
index 000000000..8635837c2
--- /dev/null
+++ b/app/hub/Views/UpgradePlanView/UpgradePlanViewConstants.js
@@ -0,0 +1,25 @@
+/**
+ * Upgrade Plan View Constants
+ *
+ * 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
+ */
+
+// Monthly/Yearly toggle
+export const TOGGLE_MONTHLY_YEARLY_PRICES = 'TOGGLE_MONTHLY_YEARLY_PRICES';
+
+// Free/Plus/Premium on medium or smaller screen sizes
+export const SET_BASIC_PROTECTION = 'SET_BASIC_PROTECTION';
+export const SET_PLUS_PROTECTION = 'SET_PLUS_PROTECTION';
+export const SET_PREMIUM_PROTECTION = 'SET_PREMIUM_PROTECTION';
+
+// Basic/Plus/Premium card to show on mobile view
+export const BASIC = 'BASIC';
+export const PLUS = 'PLUS';
+export const PREMIUM = 'PREMIUM';
diff --git a/app/hub/Views/UpgradePlanView/UpgradePlanViewReducer.js b/app/hub/Views/UpgradePlanView/UpgradePlanViewReducer.js
new file mode 100644
index 000000000..69637ff8c
--- /dev/null
+++ b/app/hub/Views/UpgradePlanView/UpgradePlanViewReducer.js
@@ -0,0 +1,59 @@
+/**
+ * Reducer used throughout the UpgradePlanView's flow
+ *
+ * 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 {
+ TOGGLE_MONTHLY_YEARLY_PRICES,
+ SET_BASIC_PROTECTION,
+ SET_PLUS_PROTECTION,
+ SET_PREMIUM_PROTECTION,
+ BASIC,
+ PLUS,
+ PREMIUM
+} from './UpgradePlanViewConstants';
+
+const initialState = {
+ show_yearly_prices: true,
+ protection_level: BASIC
+};
+
+function UpgradePlanViewReducer(state = initialState, action) {
+ switch (action.type) {
+ case TOGGLE_MONTHLY_YEARLY_PRICES: {
+ return {
+ ...state,
+ show_yearly_prices: !state.show_yearly_prices
+ };
+ }
+ case SET_BASIC_PROTECTION: {
+ return {
+ ...state,
+ protection_level: BASIC
+ };
+ }
+ case SET_PLUS_PROTECTION: {
+ return {
+ ...state,
+ protection_level: PLUS
+ };
+ }
+ case SET_PREMIUM_PROTECTION: {
+ return {
+ ...state,
+ protection_level: PREMIUM
+ };
+ }
+ default: return state;
+ }
+}
+
+export default UpgradePlanViewReducer;
diff --git a/app/hub/Views/UpgradePlanView/index.js b/app/hub/Views/UpgradePlanView/index.js
new file mode 100644
index 000000000..3ebc11681
--- /dev/null
+++ b/app/hub/Views/UpgradePlanView/index.js
@@ -0,0 +1,42 @@
+/**
+ * Point of entry index.js file for UpgradePlanView
+ *
+ * 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 { bindActionCreators } from 'redux';
+import { withRouter } from 'react-router-dom';
+
+import UpgradePlanView from './UpgradePlanView';
+import UpgradePlanViewReducer from './UpgradePlanViewReducer';
+import * as UpgradePlanViewActions from './UpgradePlanViewActions';
+
+/**
+ * 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 => ({
+ actions: bindActionCreators({ ...UpgradePlanViewActions }, dispatch),
+});
+
+export const reducer = UpgradePlanViewReducer;
+
+export default withRouter(connect(mapStateToProps, mapDispatchToProps)(UpgradePlanView));
diff --git a/app/hub/createStore.js b/app/hub/createStore.js
index bfa1bb2dc..8718724ef 100644
--- a/app/hub/createStore.js
+++ b/app/hub/createStore.js
@@ -25,6 +25,7 @@ import { reducer as app } from './Views/AppView';
import { reducer as home } from './Views/HomeView';
import { reducer as setup } from './Views/SetupView';
import { reducer as tutorial } from './Views/TutorialView';
+import { reducer as upgrade } from './Views/UpgradePlanView';
import account from '../Account/AccountReducer';
import settings from '../panel/reducers/settings';
@@ -35,6 +36,7 @@ const reducer = combineReducers({
tutorial,
account,
settings,
+ upgrade
});
/**
diff --git a/app/hub/index.jsx b/app/hub/index.jsx
index 020cde46e..6e8f215ab 100644
--- a/app/hub/index.jsx
+++ b/app/hub/index.jsx
@@ -30,6 +30,7 @@ import ProductsView from './Views/ProductsView';
import CreateAccountView from './Views/CreateAccountView';
import ForgotPasswordView from '../shared-components/ForgotPassword/ForgotPasswordContainer';
import LogInView from './Views/LogInView';
+import UpgradePlanView from './Views/UpgradePlanView';
const store = createStore();
@@ -39,7 +40,8 @@ const store = createStore();
*/
const Hub = () => (
-
+
+
diff --git a/app/images/hub/upgrade/arrow-down.svg b/app/images/hub/upgrade/arrow-down.svg
new file mode 100644
index 000000000..2fb5d83b4
--- /dev/null
+++ b/app/images/hub/upgrade/arrow-down.svg
@@ -0,0 +1 @@
+
diff --git a/app/images/hub/upgrade/check.svg b/app/images/hub/upgrade/check.svg
new file mode 100644
index 000000000..b1b7defab
--- /dev/null
+++ b/app/images/hub/upgrade/check.svg
@@ -0,0 +1 @@
+
diff --git a/app/images/hub/upgrade/ghostery-basic-card.svg b/app/images/hub/upgrade/ghostery-basic-card.svg
new file mode 100644
index 000000000..13f10f619
--- /dev/null
+++ b/app/images/hub/upgrade/ghostery-basic-card.svg
@@ -0,0 +1 @@
+
diff --git a/app/images/hub/upgrade/ghostery-plus-card.svg b/app/images/hub/upgrade/ghostery-plus-card.svg
new file mode 100644
index 000000000..575180465
--- /dev/null
+++ b/app/images/hub/upgrade/ghostery-plus-card.svg
@@ -0,0 +1 @@
+
diff --git a/app/images/hub/upgrade/ghostery-premium-card.svg b/app/images/hub/upgrade/ghostery-premium-card.svg
new file mode 100644
index 000000000..03fb33f37
--- /dev/null
+++ b/app/images/hub/upgrade/ghostery-premium-card.svg
@@ -0,0 +1 @@
+
diff --git a/app/images/hub/upgrade/x-icon.svg b/app/images/hub/upgrade/x-icon.svg
new file mode 100644
index 000000000..cde0bd209
--- /dev/null
+++ b/app/images/hub/upgrade/x-icon.svg
@@ -0,0 +1 @@
+
diff --git a/app/images/premium-sparkle.svg b/app/images/premium-sparkle.svg
new file mode 100644
index 000000000..5a9551c96
--- /dev/null
+++ b/app/images/premium-sparkle.svg
@@ -0,0 +1 @@
+
diff --git a/app/panel/components/HeaderMenu.jsx b/app/panel/components/HeaderMenu.jsx
index 620c810a3..57ddbcbc8 100644
--- a/app/panel/components/HeaderMenu.jsx
+++ b/app/panel/components/HeaderMenu.jsx
@@ -268,7 +268,7 @@ class HeaderMenu extends React.Component {
)}
- {hasPremiumAccess ? t('panel_detail_premium_title') : t('ghostery_plus')}
+ {hasPremiumAccess ? 'Ghostery Premium' : 'Ghostery Plus'}
diff --git a/app/panel/components/Help.jsx b/app/panel/components/Help.jsx
index 777f7d1e5..ef5f442b9 100644
--- a/app/panel/components/Help.jsx
+++ b/app/panel/components/Help.jsx
@@ -12,37 +12,33 @@
*/
import React from 'react';
-import { openSupportPage } from '../utils/msg';
+import { openSupportPage, openHubPage } from '../utils/msg';
import PanelToTabLink from './BuildingBlocks/PanelToTabLink';
/**
* Render Help view that user can open from the header drop-down menu
*/
-const Help = () => {
- const hubUrl = chrome.runtime.getURL('./app/templates/hub.html');
-
- return (
-