diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index c3659b390..72acad9af 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -22,16 +22,9 @@
}
}
},
- "all": {
- "description": "Default setting in the 'filter by type' dropdown for the tag browser. Doesn't filter anything out. Should read as 'Show all'.",
- "message": "all"
- },
"banner_check_your_email_title": {
"message": "Please check your email shortly for a link to reset your password."
},
- "banner_no_such_account_message": {
- "message": "Looks like we can't find this email and password combo. Give it another shot."
- },
"banner_email_not_in_system_message": {
"message": "Sorry, that email isn't in our system."
},
@@ -41,10 +34,6 @@
"blacklist_error_whitelist_url": {
"message": "This site has been removed from your Trusted Sites list and added to your Restricted Sites list"
},
- "blocked": {
- "description": "Select this to show only blocked (checked) tags in the tag browser. Should read as 'Show blocked'.",
- "message": "blocked"
- },
"blocked_redirect_action_always_title": {
"description": "Title for the 'Allow always and reload' button on the blocked redirect page.",
"message": "Always allow and reload."
@@ -375,31 +364,6 @@
}
}
},
- "copyright": {
- "description": "Copyright message, shown in page footers.",
- "message": "$C$ $YEAR$ $GHOSTERY$, a part of $COMPANY_ADDRESS$",
- "placeholders": {
- "c": {
- "content": "©"
- },
- "company_address": {
- "content": "$1",
- "example": "GHOSTERY, Inc., Such-and-such Street, Such-and-such Floor, New York, NY, Zip Code"
- },
- "ghostery": {
- "content": "Ghostery"
- },
- "year": {
- "content": "2015"
- }
- }
- },
- "email_confirm_field_label": {
- "message": "Confirm Email:"
- },
- "email_field_label": {
- "message": "Email:"
- },
"error_email_forgot": {
"message": "Hmm, I can’t find that email. Maybe try another?"
},
@@ -409,12 +373,6 @@
"forgot_password_message": {
"message": "Forgot your password? Hey, it happens to everyone. We'll email you instructions to reset your password."
},
- "invalid_email_confirmation": {
- "message": "Your emails do not match."
- },
- "invalid_email_create": {
- "message": "Please enter a valid email."
- },
"invalid_email_forgot": {
"message": "Sorry, you have to enter a real email address."
},
@@ -532,9 +490,6 @@
"description": "as in '5 (trackers) WHITELISTED'",
"message": "Whitelisted"
},
- "panel_create_account": {
- "message": "Create Account"
- },
"panel_email_verification_sent": {
"message": "$BOLD_HTML_STARTS$ Success! $BOLD_HTML_END$ An account verification email has been sent to $EMAIL$",
"placeholders": {
@@ -568,12 +523,30 @@
"panel_help_questions_header": {
"message": "Questions and Comments"
},
- "panel_help_support": {
- "message": "Support"
- },
"panel_help_setup": {
"message": "Set Up Ghostery"
},
+ "panel_insights_audit_tags": {
+ "message": "Audit marketing tags on a page"
+ },
+ "panel_insights_promotion_explore_trends": {
+ "message": "Explore global digital trends"
+ },
+ "panel_insights_promotion_call_to_action": {
+ "message": "Try for free"
+ },
+ "panel_insights_promotion_header": {
+ "message": "Try Ghostery Insights"
+ },
+ "panel_insights_promotion_description": {
+ "message": "Speed up and clean up digital user experience with our professional tag analytics tool."
+ },
+ "panel_insights_promotion_trace_poor_performance": {
+ "message": "Trace sources of poor performance"
+ },
+ "panel_insights_promotion_watch_pings": {
+ "message": "Watch pings fire in real-time"
+ },
"panel_about_panel_header": {
"message": "About Ghostery Browser Extension"
},
@@ -623,15 +596,6 @@
"panel_menu_about": {
"message": "About"
},
- "panel_menu_ghostery_subscriber": {
- "message": "Ghostery Plus"
- },
- "panel_menu_signin": {
- "message": "Sign in"
- },
- "panel_menu_signout": {
- "message": "Sign out"
- },
"global_settings_saved": {
"message": "Global Settings Saved"
},
@@ -691,9 +655,6 @@
"panel_signin_success_title": {
"message": "Congrats! Your Ghostery account is ready to go."
},
- "panel_title_create_account": {
- "message": "Create Account"
- },
"panel_tracker_found_sources_title": {
"message": "Detected tracker URLs:"
},
@@ -739,15 +700,9 @@
"panel_detail_menu_rewards_title": {
"message": "Rewards"
},
- "panel_detail_menu_stats_title": {
- "message": "Historical stats"
- },
"panel_detail_menu_premium_title": {
"message": "Premium"
},
- "panel_detail_learn_more": {
- "message": "Learn More"
- },
"panel_detail_history_title": {
"message": "History"
},
@@ -802,27 +757,15 @@
"notification_library_update_link": {
"message": "Check out what's new"
},
- "panel_header_sign_in": {
- "message": "Sign In"
- },
"panel_header_verify_account": {
"message": "Verify Account"
},
- "panel_header_simple_view": {
- "message": "Simple View"
- },
- "panel_header_detailed_view": {
- "message": "Detailed View"
- },
"password_characters_requirements": {
"message": "Only these special characters are allowed: !@#$%^&*=+()<>{}[];:,./?"
},
"password_field_label": {
"message": "Password"
},
- "create_password_field_label": {
- "message": "Password:"
- },
"password_requirements": {
"message": "Use between 8 and 50 characters."
},
@@ -958,6 +901,9 @@
"settings_new_features": {
"message": "Releases new features"
},
+ "settings_new_promotions": {
+ "message": "Has product promotions"
+ },
"settings_new_trackers": {
"message": "Adds new trackers to its tracker library"
},
@@ -1126,57 +1072,6 @@
"blocking_category_tracker_found": {
"message": "Found"
},
- "drawer_title_enable_anti_tracking": {
- "message": "Enhanced Anti-Tracking"
- },
- "drawer_tooltip_enable_anti_tracking": {
- "message": "Anonymize unblocked and unknown trackers for greater browsing protection"
- },
- "drawer_label_enable_anti_tracking": {
- "message": "Trackers Anonymized"
- },
- "drawer_desc_enable_anti_tracking": {
- "message": "Private data points have been removed."
- },
- "drawer_status_enable_anti_tracking": {
- "message": "Anti-Tracking is"
- },
- "drawer_title_enable_ad_block": {
- "message": "Enhanced Ad Blocking"
- },
- "drawer_tooltip_enable_ad_block": {
- "message": "Block advertisements on websites you visit"
- },
- "drawer_label_enable_ad_block": {
- "message": "Ads Blocked"
- },
- "drawer_desc_enable_ad_block": {
- "message": "Ad spots have been blocked."
- },
- "drawer_status_enable_ad_block": {
- "message": "Ad Blocking is"
- },
- "drawer_title_enable_smart_block": {
- "message": "Smart Blocking"
- },
- "drawer_tooltip_enable_smart_block": {
- "message": "Automatically block and unblock trackers to optimize page performance"
- },
- "drawer_label_enable_smart_block": {
- "message": "Trackers Adjusted"
- },
- "drawer_desc_enable_smart_block": {
- "message": "Trackers have been temporarily blocked or unblocked."
- },
- "drawer_status_enable_smart_block": {
- "message": "Smart Blocking is"
- },
- "drawer_on": {
- "message": "On"
- },
- "drawer_off": {
- "message": "Off"
- },
"blocking_unblock_all": {
"message": "Unblock All"
},
@@ -1246,34 +1141,16 @@
"alert_site_restricted_off": {
"message": "Site no longer blacklisted."
},
- "tooltip_anti_track": {
- "message": "Enhanced Anti-Tracking"
- },
- "tooltip_anti_track_body": {
- "message": "Anonymize personal data for greater protection."
- },
- "tooltip_anti_track_body_on": {
+ "tooltip_anti_track_on": {
"message": "Personal data points anonymized."
},
"tooltip_body_in_cliqz": {
"message": "Feature already active in Cliqz by default."
},
- "tooltip_ad_block": {
- "message": "Enhanced Ad Blocking"
- },
- "tooltip_ad_block_body": {
- "message": "Block advertisements."
- },
- "tooltip_ad_block_body_on": {
+ "tooltip_ad_block_on": {
"message": "Advertisements have been blocked."
},
- "tooltip_smart_block": {
- "message": "Smart Blocking"
- },
- "tooltip_smart_block_body": {
- "message": "Automatically block and unblock trackers to optimize page performance."
- },
- "tooltip_smart_block_body_on": {
+ "tooltip_smart_block_on": {
"message": "Tracker blocking adjusted to optimize page performance."
},
"tooltip_trust": {
@@ -1294,12 +1171,6 @@
"tooltip_resume": {
"message": "Resume Ghostery"
},
- "tooltip_expert": {
- "message": "Detailed View"
- },
- "tooltip_simple": {
- "message": "Simple View"
- },
"license_module": {
"message": "Module"
},
@@ -1350,30 +1221,15 @@
"hub_side_navigation_home": {
"message": "Home"
},
- "hub_side_navigation_setup": {
- "message": "Customize Setup"
- },
"hub_side_navigation_tutorial": {
"message": "Take a Tutorial"
},
- "hub_side_navigation_supporter": {
- "message": "Get Ghostery Plus"
- },
"hub_side_navigation_rewards": {
"message": "Try Ghostery Rewards"
},
"hub_side_navigation_products": {
"message": "See More Ghostery Products"
},
- "hub_side_navigation_create_account": {
- "message": "Create Account"
- },
- "hub_side_navigation_log_in": {
- "message": "Sign In"
- },
- "hub_side_navigation_log_out": {
- "message": "Sign Out"
- },
"hub_home_page_title": {
"message": "Ghostery Hub - Home"
},
@@ -1404,24 +1260,15 @@
"hub_home_subheader_optimize": {
"message": "Optimize your Ghostery experience"
},
- "hub_home_subheader_create_account": {
- "message": "Create Account"
- },
"hub_home_feature_tutorial_title": {
"message": "Take a Tutorial"
},
"hub_home_feature_tutorial_text": {
"message": "Walk through Ghostery's main features."
},
- "hub_home_feature_tutorial_button": {
- "message": "Start"
- },
"hub_home_feature_tutorial_button_alt": {
"message": "Tutorial Complete"
},
- "hub_home_feature_setup_title": {
- "message": "Customize Setup"
- },
"hub_home_feature_setup_text": {
"message": "Edit your settings and blocking preferences."
},
@@ -1434,12 +1281,6 @@
"hub_home_feature_supporter_text": {
"message": "Upgrade to Ghostery Plus and unlock special features."
},
- "hub_home_feature_supporter_button": {
- "message": "Get Ghostery Plus"
- },
- "hub_home_feature_supporter_button_alt": {
- "message": "Already Subscribed"
- },
"hub_setup_page_title": {
"message": "Ghostery Hub - Setup"
},
@@ -1475,15 +1316,6 @@
"hub_setup_exit_flow": {
"message": "Exit Custom Setup"
},
- "hub_setup_nav_previous": {
- "message": "Previous"
- },
- "hub_setup_nav_next": {
- "message": "Next"
- },
- "hub_setup_nav_done": {
- "message": "Done"
- },
"hub_setup_enter_modal_text": {
"message": "Entering custom setup will override your previous Ghostery settings. Do you want to continue?"
},
@@ -1520,24 +1352,9 @@
"hub_setup_blocking_description_custom": {
"message": "Choose which trackers to block"
},
- "hub_setup_antisuite_name_antitracking": {
- "message": "Enhanced Anti-Tracking"
- },
"hub_setup_antisuite_description_antitracking": {
"message": "Anonymize unblocked and unknown trackers for greater browsing protection."
},
- "hub_setup_adblock_name_adblocking": {
- "message": "Enhanced Ad Blocking"
- },
- "hub_setup_adblock_description_adblocking": {
- "message": "Block advertisements on websites you visit."
- },
- "hub_setup_smartblocking_name_smartblocking": {
- "message": "Smart Blocking"
- },
- "hub_setup_smartblocking_description_smartblocking": {
- "message": "Automatically block and unblock trackers to optimize page performance."
- },
"hub_setup_feature_already_active": {
"message": "This feature is already active in Cliqz by default. $LINK_LM_START$Learn More$LINK_LM_END$",
"placeholders": {
@@ -1581,18 +1398,9 @@
"hub_setup_feature_tutorial_description": {
"message": "Walk through Ghostery's main features."
},
- "hub_setup_feature_tutorial_button": {
- "message": "Start"
- },
- "hub_setup_feature_supporter_title": {
- "message": "Get Ghostery Plus"
- },
"hub_setup_feature_supporter_description": {
"message": "Support Ghostery and unlock special perks."
},
- "hub_setup_feature_supporter_button": {
- "message": "Support"
- },
"hub_setup_feature_products_title": {
"message": "See more Ghostery Products"
},
@@ -1626,21 +1434,6 @@
"hub_tutorial_exit_flow": {
"message": "Exit Tutorial"
},
- "hub_tutorial_nav_previous": {
- "message": "Previous"
- },
- "hub_tutorial_nav_next": {
- "message": "Next"
- },
- "hub_tutorial_nav_done": {
- "message": "Done"
- },
- "hub_tutorial_simple_view": {
- "message": "Simple View"
- },
- "hub_tutorial_detailed_view": {
- "message": "Detailed View"
- },
"hub_tutorial_detailed_expanded_view": {
"message": "Detailed Expanded View"
},
@@ -1692,24 +1485,9 @@
"hub_tutorial_antisuite_title": {
"message": "Get extra protection and automated control with our enhanced privacy features:"
},
- "hub_tutorial_antisuite_antitracking_title": {
- "message": "Enhanced Anti-Tracking"
- },
"hub_tutorial_antisuite_antitracking_description": {
"message": "Remove data points that websites can use to identify you."
},
- "hub_tutorial_antisuite_adblocking_title": {
- "message": "Enhanced Ad Blocking"
- },
- "hub_tutorial_antisuite_adblocking_description": {
- "message": "Block advertisements on the pages you visit."
- },
- "hub_tutorial_antisuite_smartblocking_title": {
- "message": "Smart Blocking"
- },
- "hub_tutorial_antisuite_smartblocking_description": {
- "message": "Automatically block and unblock trackers to optimize page performance."
- },
"hub_products_page_title" : {
"message": "Ghostery Hub - Try Other Ghostery Products"
},
@@ -1746,9 +1524,6 @@
"hub_rewards_header_description": {
"message": "Our new Rewards feature offers a powerful, completely private new way to receive real discounts online. Turn it on and check it out!"
},
- "hub_rewards_header_learn_more": {
- "message": "Learn More"
- },
"hub_rewards_experience_title": {
"message": "A Smarter Shopping Experience"
},
@@ -1779,12 +1554,6 @@
"hub_supporter_header_description": {
"message": "Show your support and unlock special perks!"
},
- "hub_supporter_button_text": {
- "message": "Get Ghostery Plus"
- },
- "hub_supporter_button_text_alt": {
- "message": "Already Subscribed"
- },
"hub_supporter_price": {
"message": "$SUP_START$$$SUP_END$$SPAN_START$2$SPAN_END$ per month",
"placeholders": {
@@ -1802,15 +1571,9 @@
}
}
},
- "hub_supporter_perk_themes_title": {
- "message": "New Themes"
- },
"hub_supporter_perk_themes_description": {
"message": "Customize the Ghostery colors - try our Midnight theme!"
},
- "hub_supporter_perk_stats_title": {
- "message": "Historical Blocking Stats"
- },
"hub_supporter_perk_stats_description": {
"message": "View your blocking statistics and see how Ghostery is working for you"
},
@@ -1823,21 +1586,12 @@
"hub_supporter_manifesto": {
"message": "We strive to deliver the best privacy protection services to our users free of cost. While we do not charge for our privacy suite, you may choose to support us through a small monthly subscription. Join us in our mission by upgrading to Ghostery Plus - and unlock cool perks along the way!"
},
- "hub_supporter_feature_theme_title": {
- "message": "New Themes"
- },
"hub_supporter_feature_theme_description": {
"message": "Customize the Ghostery colors for a new visual experience! Introduced through popular request. Check out our special Midnight theme, and more to come."
},
- "hub_supporter_feature_stats_title": {
- "message": "Historical Blocking Stats"
- },
"hub_supporter_feature_stats_description": {
"message": "View historical blocking results with graphs and statistics to reveal trends and learn how Ghostery has affected your browsing."
},
- "hub_supporter_feature_support_title": {
- "message": "Priority Support"
- },
"hub_supporter_feature_support_description": {
"message": "Need assistance? Find a broken page? Have your questions answered and issues resolved fast with our Priority help desk service, accessible only when signed in with a Plus account."
},
@@ -1859,15 +1613,6 @@
"hub_login_header_title": {
"message": "Sign in to your account."
},
- "hub_login_label_email": {
- "message": "Email:"
- },
- "hub_login_label_password": {
- "message": "Password:"
- },
- "hub_login_label_email_invalid": {
- "message": "Please enter a valid email."
- },
"hub_login_label_password_invalid": {
"message": "Use between 8 and 50 characters."
},
@@ -1877,39 +1622,18 @@
"hub_login_link_create_account": {
"message": "Sign up."
},
- "hub_login_button_submit": {
- "message": "Sign In"
- },
"hub_login_toast_success": {
"message": "Sign in successful! Your account settings have been imported."
},
- "hub_login_toast_error": {
- "message": "Looks like we can't find this email and password combo. Give it another shot."
- },
"hub_create_account_header_title": {
"message": "Would you like to create a Ghostery account to sync settings across browsers and devices?"
},
- "hub_create_account_label_email": {
- "message": "Email:"
- },
- "hub_create_account_label_email_confirm": {
- "message": "Confirm Email:"
- },
"hub_create_account_label_first_name": {
"message": "First Name (Optional):"
},
"hub_create_account_label_email_last_name": {
"message": "Last Name (Optional):"
},
- "hub_create_account_label_password": {
- "message": "Password:"
- },
- "hub_create_account_label_email_invalid": {
- "message": "Please enter a valid email."
- },
- "hub_create_account_label_email_confirm_invalid": {
- "message": "Your emails do not match."
- },
"hub_create_account_label_password_invalid": {
"message": "Only these special characters are allowed: !@#$%^&*=+()<>{}[];:,./?"
},
@@ -1925,9 +1649,6 @@
"hub_create_account_link_login": {
"message": "Sign in here."
},
- "hub_create_account_button_submit": {
- "message": "Create Account"
- },
"hub_create_account_toast_success": {
"message": "Account Successfully Created"
},
@@ -2059,9 +1780,6 @@
"rewards_code_copied_toast_notification": {
"message": "Rewards code copied!"
},
- "rewards_learn_more": {
- "message": "Learn More"
- },
"offers_hub_copy_btn": {
"message": "Copy code"
},
@@ -2080,21 +1798,9 @@
"subscription_themes": {
"message": "Ghostery Themes"
},
- "subscription_info_title": {
- "message": "Ghostery Plus"
- },
"subscription_themes_title": {
"message": "Themes"
},
- "subscription_priority_support_title": {
- "message": "Priority Support"
- },
- "subscription_priority_support": {
- "message": "Priority Support"
- },
- "subscription_history_stats": {
- "message": "Historical Stats"
- },
"subscribe_pitch": {
"message": "While Ghostery is free, you can choose to support us through a small subscription of $2 per month in exchange for cool perks, such as color themes, priority help service, and more. Join our mission and subscribe!"
},
@@ -2104,9 +1810,15 @@
"subscribe_pitch_button_label": {
"message": "Get Ghostery Plus!"
},
+ "subscribe_pitch_no_thanks": {
+ "message": "No thanks, maybe later"
+ },
"subscribe_pitch_sign_here": {
"message": "Already a subscriber? Sign in here"
},
+ "subscribe_pitch_sign_in": {
+ "message": "Already subscribed? Sign in"
+ },
"subscription_midnight_theme": {
"message": "Midnight Theme"
},
@@ -2125,9 +1837,6 @@
"subscription_themes_tooltip": {
"message": "Change the color scheme of Ghostery!"
},
- "subscription_tracker_stats": {
- "message": "Historical Stats"
- },
"subscription_charge_date" : {
"message": "Next Payment Date"
},
@@ -2172,9 +1881,6 @@
"panel_stats_menu_daily": {
"message": "Daily"
},
- "panel_stats_header_title": {
- "message": "Historical Tracker Stats"
- },
"panel_stats_header_title_monthly": {
"message": "Historical Tracker Stats (Monthly Avg.)"
},
@@ -2237,9 +1943,6 @@
"panel_stats_pitch_modal_sign_in": {
"message": "Sign in here"
},
- "panel_stats_pitch_modal_subscribe": {
- "message": "Get Ghostery Plus!"
- },
"panel_stats_pitch_modal_tooltip": {
"message": "Erase all statistics history up until this point in time."
},
@@ -2261,12 +1964,6 @@
"ads": {
"message": "ads"
},
- "cliqz_feature_status_on": {
- "message": "On"
- },
- "cliqz_feature_status_off": {
- "message": "Off"
- },
"create_account_form_legal_consent_checkbox_label": {
"message": "I accept the $LINK_TERMS_START$Terms and Conditions$LINK_END$, the $LINK_LICENSE_START$Public License Agreement$LINK_END$, and consent to data practices found in the $LINK_PRIVACY_START$Privacy Policy$LINK_END$.",
"placeholders": {
@@ -2295,5 +1992,176 @@
},
"unknown_description": {
"message": "Unknown trackers scrubbed by Anti-Tracking"
+ },
+ "thanks_for_downloading_ghostery": {
+ "message": "Thanks for downloading Ghostery!"
+ },
+ "choose_your_privacy_plan": {
+ "message": "Choose your privacy plan"
+ },
+ "choose_your_ghostery_privacy_plan": {
+ "message": "Choose your Ghostery privacy plan"
+ },
+ "ghostery_basic": {
+ "message": "Ghostery Basic"
+ },
+ "ghostery_plus": {
+ "message": "Ghostery Plus"
+ },
+ "locale_appropriate_currency_icon": {
+ "message": "$$",
+ "description": "Use '$$' to mean '$'. '$' has a special meaning in the code and the first '$' tells the browser to ignore the special meaning of the second '$' and print it literally."
+ },
+ "plus_monthly_subscription_price_number": {
+ "message": "2"
+ },
+ "per_month": {
+ "message": "per month"
+ },
+ "protection_for_this_browser": {
+ "message": "Protection for this browser"
+ },
+ "blocks_ads": {
+ "message": "Blocks Ads"
+ },
+ "blocks_trackers": {
+ "message": "Blocks Trackers"
+ },
+ "fast_browsing": {
+ "message": "Fast Browsing"
+ },
+ "select_basic": {
+ "message": "Select Basic"
+ },
+ "select_plus": {
+ "message": "Select Plus"
+ },
+ "recommended": {
+ "message": "Recommended"
+ },
+ "get_ghostery_plus": {
+ "message": "Get Ghostery Plus"
+ },
+ "get_ghostery_plus_bang": {
+ "message": "Get Ghostery Plus!"
+ },
+ "already_subscribed": {
+ "message": "Already Subscribed"
+ },
+ "new_themes": {
+ "message": "New Themes"
+ },
+ "historical_blocking_stats": {
+ "message": "Historical Blocking Stats"
+ },
+ "sign_in": {
+ "message": "Sign In"
+ },
+ "sign_out": {
+ "message": "Sign Out"
+ },
+ "create_account": {
+ "message": "Create Account"
+ },
+ "email_colon": {
+ "message": "Email:"
+ },
+ "confirm_email_colon": {
+ "message": "Confirm Email:"
+ },
+ "next": {
+ "message": "Next"
+ },
+ "previous": {
+ "message": "Previous"
+ },
+ "done": {
+ "message": "Done"
+ },
+ "simple_view": {
+ "message": "Simple View"
+ },
+ "detailed_view": {
+ "message": "Detailed View"
+ },
+ "support": {
+ "message": "Support"
+ },
+ "start": {
+ "message": "Start"
+ },
+ "password_colon": {
+ "message": "Password:"
+ },
+ "please_enter_a_valid_email": {
+ "message": "Please enter a valid email."
+ },
+ "your_email_do_not_match": {
+ "message": "Your emails do not match."
+ },
+ "customize_setup": {
+ "message": "Customize Setup"
+ },
+ "learn_more": {
+ "message": "Learn More"
+ },
+ "historical_stats": {
+ "message": "Historical Stats"
+ },
+ "priority_support": {
+ "message": "Priority Support"
+ },
+ "on": {
+ "message": "On"
+ },
+ "off": {
+ "message": "Off"
+ },
+ "enhanced_ad_blocking": {
+ "message": "Enhanced Ad Blocking"
+ },
+ "smart_blocking": {
+ "message": "Smart Blocking"
+ },
+ "smart_blocking_DESC": {
+ "message": "Automatically block and unblock trackers to optimize page performance."
+ },
+ "ad_blocking_DESC": {
+ "message": "Block advertisements on the pages you visit."
+ },
+ "anti_tracking_DESC": {
+ "message": "Anonymize personal data for greater protection."
+ },
+ "no_such_email_password_combo": {
+ "message": "Looks like we can't find this email and password combo. Give it another shot."
+ },
+ "all_basic_features_plus_COLON": {
+ "message": "All basic features, plus:"
+ },
+ "historical_tracker_stats": {
+ "message": "Historical Tracker Stats"
+ },
+ "new_color_themes": {
+ "message": "New Color Themes"
+ },
+ "upgrade_cta_TEXT": {
+ "message": "Unlock historical tracker insights, priority support access, and new color themes by upgrading to Ghostery Plus for only $2 per month.",
+ "description": "Body text in a non-responsive modal. Character limit: 135."
+ },
+ "upgrade_your_ghostery_experience": {
+ "message": "Upgrade your Ghostery experience",
+ "description": "Header text for a non-responsive modal. Character limit: 40."
+ },
+ "upgrade_to_plus": {
+ "message": "Upgrade to Plus",
+ "description": "Button text in a non-responsive modal. Character limit: 35."
+ },
+ "no_thanks_turn_promos_off": {
+ "message": "No thanks, turn promos off",
+ "description": "Text link in a non-responsive modal. Character limit: 28."
+ },
+ "already_subscribed_sign_in": {
+ "message": "Already subscribed? Sign In",
+ "description": "Character limit: 28."
}
}
diff --git a/app/content-scripts/rewards/OfferCard.jsx b/app/content-scripts/rewards/OfferCard.jsx
index 9e26138b5..c97e906e9 100644
--- a/app/content-scripts/rewards/OfferCard.jsx
+++ b/app/content-scripts/rewards/OfferCard.jsx
@@ -74,7 +74,7 @@ class OfferCard extends Component {
message: t('rewards_first_prompt_extended'),
textLink: {
href: 'https://www.ghostery.com/faqs/what-is-ghostery-rewards/',
- text: t('rewards_learn_more'),
+ text: t('learn_more'),
callback: () => {
this.props.actions.sendSignal('offer_first_learn');
sendMessage('ping', 'rewards_first_learn_more');
diff --git a/app/fonts/roboto-all-charsets.woff b/app/fonts/roboto-all-charsets.woff
deleted file mode 100644
index 96c1986f0..000000000
Binary files a/app/fonts/roboto-all-charsets.woff and /dev/null differ
diff --git a/app/fonts/roboto-condensed-latin-bold-700.woff2 b/app/fonts/roboto-condensed-latin-bold-700.woff2
new file mode 100644
index 000000000..1a32150b5
Binary files /dev/null and b/app/fonts/roboto-condensed-latin-bold-700.woff2 differ
diff --git a/app/fonts/roboto-latin-bold-300.woff2 b/app/fonts/roboto-latin-bold-300.woff2
new file mode 100644
index 000000000..ef8c8836b
Binary files /dev/null and b/app/fonts/roboto-latin-bold-300.woff2 differ
diff --git a/app/fonts/roboto-latin-bold-500.woff2 b/app/fonts/roboto-latin-bold-500.woff2
new file mode 100644
index 000000000..6362d7f64
Binary files /dev/null and b/app/fonts/roboto-latin-bold-500.woff2 differ
diff --git a/app/fonts/roboto-latin-bold-700.woff2 b/app/fonts/roboto-latin-bold-700.woff2
new file mode 100644
index 000000000..32b25eee7
Binary files /dev/null and b/app/fonts/roboto-latin-bold-700.woff2 differ
diff --git a/app/fonts/roboto-latin-bold-900.woff2 b/app/fonts/roboto-latin-bold-900.woff2
new file mode 100644
index 000000000..802499d3f
Binary files /dev/null and b/app/fonts/roboto-latin-bold-900.woff2 differ
diff --git a/app/hub/Views/CreateAccountView/CreateAccountView.jsx b/app/hub/Views/CreateAccountView/CreateAccountView.jsx
index 432463ee7..9bd342680 100644
--- a/app/hub/Views/CreateAccountView/CreateAccountView.jsx
+++ b/app/hub/Views/CreateAccountView/CreateAccountView.jsx
@@ -73,7 +73,7 @@ const CreateAccountView = (props) => {
{
/>
{emailError && (
- {t('hub_create_account_label_email_invalid')}
+ {t('please_enter_a_valid_email')}
)}
{
/>
{confirmEmailError && (
- {t('hub_create_account_label_email_confirm_invalid')}
+ {t('your_emails_do_not_match')}
)}
@@ -147,7 +147,7 @@ const CreateAccountView = (props) => {
@@ -288,7 +288,7 @@ exports[`app/hub/Views/CreateAccount component Snapshot tests with react-test-re
className="CreateAccountView__inputLabel"
htmlFor="create-account-email"
>
- hub_create_account_label_email
+ email_colon
- hub_create_account_label_email_invalid
+ please_enter_a_valid_email
- hub_create_account_label_email_confirm
+ confirm_email_colon
- hub_create_account_label_email_confirm_invalid
+ your_emails_do_not_match
@@ -386,7 +386,7 @@ exports[`app/hub/Views/CreateAccount component Snapshot tests with react-test-re
className="CreateAccountView__inputLabel"
htmlFor="create-account-password"
>
- hub_create_account_label_password
+ password_colon
- hub_create_account_button_submit
+ create_account
diff --git a/app/hub/Views/HomeView/HomeView.jsx b/app/hub/Views/HomeView/HomeView.jsx
index b22261ce3..e19d54d45 100644
--- a/app/hub/Views/HomeView/HomeView.jsx
+++ b/app/hub/Views/HomeView/HomeView.jsx
@@ -106,7 +106,7 @@ const HomeView = (props) => {
) : (
- {t('hub_home_subheader_create_account')}
+ {t('create_account')}
)}
@@ -120,7 +120,7 @@ const HomeView = (props) => {
{t('hub_home_feature_tutorial_text')}
- {tutorial_complete ? t('hub_home_feature_tutorial_button_alt') : t('hub_home_feature_tutorial_button')}
+ {tutorial_complete ? t('hub_home_feature_tutorial_button_alt') : t('start')}
@@ -128,7 +128,7 @@ const HomeView = (props) => {
- {t('hub_home_feature_setup_title')}
+ {t('customize_setup')}
{t('hub_home_feature_setup_text')}
@@ -146,7 +146,7 @@ const HomeView = (props) => {
- {isPlus ? t('hub_home_feature_supporter_button_alt') : t('hub_home_feature_supporter_button')}
+ {isPlus ? t('Aready_Subscribed') : t('get_ghostery_plus')}
diff --git a/app/hub/Views/HomeView/HomeView.scss b/app/hub/Views/HomeView/HomeView.scss
index 00fbf9b47..7a228b9cc 100644
--- a/app/hub/Views/HomeView/HomeView.scss
+++ b/app/hub/Views/HomeView/HomeView.scss
@@ -154,16 +154,16 @@
// Firefox Font Size Override and Image Size Override
@-moz-document url-prefix() {
- .HomeView--firefoxFontSize {
- font-size: 75%;
- }
+.HomeView--firefoxFontSize {
+ font-size: 75%;
+}
+.HomeView--firefoxImageSize {
+ height: 113.875px;
+}
+@media only screen and (max-width: 740px) {
.HomeView--firefoxImageSize {
- height: 113.875px;
- }
- @media only screen and (max-width: 740px) {
- .HomeView--firefoxImageSize {
- min-width: 126px !important;
- max-width: 146px !important;
- }
+ min-width: 126px !important;
+ max-width: 146px !important;
}
}
+}
diff --git a/app/hub/Views/HomeView/HomeViewActions.js b/app/hub/Views/HomeView/HomeViewActions.js
index 20f3c5057..3de1b1976 100644
--- a/app/hub/Views/HomeView/HomeViewActions.js
+++ b/app/hub/Views/HomeView/HomeViewActions.js
@@ -12,7 +12,7 @@
*/
import { log, sendMessageInPromise } from '../../utils';
-import { GET_HOME_PROPS, SET_METRICS } from './HomeViewConstants';
+import { GET_HOME_PROPS, MARK_PLUS_PROMO_MODAL_SHOWN, SET_METRICS } from './HomeViewConstants';
export function getHomeProps() {
return function(dispatch) {
@@ -39,3 +39,9 @@ export function setMetrics(actionData) {
});
};
}
+
+export function markPlusPromoModalShown() {
+ return {
+ type: MARK_PLUS_PROMO_MODAL_SHOWN,
+ };
+}
diff --git a/app/hub/Views/HomeView/HomeViewConstants.js b/app/hub/Views/HomeView/HomeViewConstants.js
index 02218a87b..2defff14b 100644
--- a/app/hub/Views/HomeView/HomeViewConstants.js
+++ b/app/hub/Views/HomeView/HomeViewConstants.js
@@ -13,4 +13,5 @@
// Home View
export const GET_HOME_PROPS = 'GET_HOME_PROPS';
+export const MARK_PLUS_PROMO_MODAL_SHOWN = 'MARK_PLUS_PROMO_MODAL_SHOWN';
export const SET_METRICS = 'SET_METRICS';
diff --git a/app/hub/Views/HomeView/HomeViewContainer.jsx b/app/hub/Views/HomeView/HomeViewContainer.jsx
index b3660cf85..5603b74da 100644
--- a/app/hub/Views/HomeView/HomeViewContainer.jsx
+++ b/app/hub/Views/HomeView/HomeViewContainer.jsx
@@ -15,6 +15,8 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import QueryString from 'query-string';
import HomeView from './HomeView';
+import { PlusPromoModal } from '../../../shared-components';
+import { sendMessage } from '../../utils';
/**
* @class Implement the Home View for the Ghostery Hub
@@ -27,6 +29,7 @@ class HomeViewContainer extends Component {
const { justInstalled } = QueryString.parse(window.location.search);
this.state = {
+ getUserResolved: false,
justInstalled: justInstalled === 'true',
};
@@ -34,25 +37,58 @@ class HomeViewContainer extends Component {
window.document.title = title;
props.actions.getHomeProps();
- props.actions.getUser();
+
+ // Prevent flickering in of user's email if getUser() returns after initial render,
+ // as well as flickering of plus promo modal if user is already a subscriber
+ props.actions.getUser()
+ .then(() => {
+ this.setState({
+ getUserResolved: true,
+ });
+ });
}
/**
- * Function to handle toggling Metrics Opt-In
- */
+ * @private
+ * Function to handle toggling Metrics Opt-In
+ */
_handleToggleMetrics = () => {
const enable_metrics = !this.props.home.enable_metrics;
this.props.actions.setMetrics({ enable_metrics });
}
/**
- * React's required render function. Returns JSX
- * @return {JSX} JSX for rendering the Home View of the Hub app
+ * @private
+ * Function to handle clicks on Select Basic in the Plus Promo Modal
*/
- render() {
+ // TODO send appropriate metrics ping
+ _handlePromoSelectBasicClick = () => {
+ // GH-1777
+ // we want to show the Plus Promo modal once per Hub visit - not every time the user returns to the Home view
+ this.props.actions.markPlusPromoModalShown();
+
+ sendMessage('SET_PLUS_PROMO_MODAL_SEEN', {});
+ }
+
+ /**
+ * @private
+ * Function to handle clicks on Select Plus in the Plus Promo Modal
+ */
+ // TODO send appropriate metrics ping
+ _handlePromoSelectPlusClick = () => {
+ // GH-1777
+ // we want to show the Plus Promo modal once per Hub visit - not every time the user returns to the Home view
+ this.props.actions.markPlusPromoModalShown();
+
+ sendMessage('SET_PLUS_PROMO_MODAL_SEEN', {});
+ }
+
+ _render() {
const { justInstalled } = this.state;
const { home, user } = this.props;
+ const isPlus = user && user.subscriptionsPlus || false;
const {
+ plus_promo_modal_shown,
setup_complete,
tutorial_complete,
enable_metrics,
@@ -64,10 +100,30 @@ class HomeViewContainer extends Component {
enable_metrics,
changeMetrics: this._handleToggleMetrics,
email: user ? user.email : '',
- isPlus: user && user.subscriptionsPlus || false,
+ isPlus,
};
- return
;
+ return (
+
+ );
+ }
+
+ /**
+ * React's required render function. Returns JSX
+ * @return {JSX} JSX for rendering the Home View of the Hub app
+ */
+ render() {
+ const { getUserResolved } = this.state;
+
+ return (getUserResolved ? this._render() : null);
}
}
@@ -75,9 +131,10 @@ class HomeViewContainer extends Component {
// Note: isRequired is not needed when a prop has a default value
HomeViewContainer.propTypes = {
home: PropTypes.shape({
+ enable_metrics: PropTypes.bool,
+ plus_promo_modal_shown: PropTypes.bool,
setup_complete: PropTypes.bool,
tutorial_complete: PropTypes.bool,
- enable_metrics: PropTypes.bool,
}),
user: PropTypes.shape({
email: PropTypes.string,
@@ -85,17 +142,19 @@ HomeViewContainer.propTypes = {
}),
actions: PropTypes.shape({
getHomeProps: PropTypes.func.isRequired,
- setMetrics: PropTypes.func.isRequired,
getUser: PropTypes.func.isRequired,
+ markPlusPromoModalShown: PropTypes.func.isRequired,
+ setMetrics: PropTypes.func.isRequired,
}).isRequired,
};
// Default props used on the Home View
HomeViewContainer.defaultProps = {
home: {
+ enable_metrics: false,
+ plus_promo_modal_shown: false,
setup_complete: false,
tutorial_complete: false,
- enable_metrics: false,
},
user: {
email: '',
diff --git a/app/hub/Views/HomeView/HomeViewReducer.js b/app/hub/Views/HomeView/HomeViewReducer.js
index e14aaa559..f60c13123 100644
--- a/app/hub/Views/HomeView/HomeViewReducer.js
+++ b/app/hub/Views/HomeView/HomeViewReducer.js
@@ -11,7 +11,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0
*/
-import { GET_HOME_PROPS, SET_METRICS } from './HomeViewConstants';
+import { GET_HOME_PROPS, MARK_PLUS_PROMO_MODAL_SHOWN, SET_METRICS } from './HomeViewConstants';
const initialState = {};
@@ -31,6 +31,13 @@ function HomeViewReducer(state = initialState, action) {
}),
});
}
+ case MARK_PLUS_PROMO_MODAL_SHOWN: {
+ return Object.assign({}, state, {
+ home: Object.assign({}, state.home, {
+ plus_promo_modal_shown: true,
+ })
+ });
+ }
case SET_METRICS: {
const { enable_metrics } = action.data;
return Object.assign({}, state, {
diff --git a/app/hub/Views/HomeView/__tests__/__snapshots__/HomeView.test.jsx.snap b/app/hub/Views/HomeView/__tests__/__snapshots__/HomeView.test.jsx.snap
index 1b14914b8..808de5ec5 100644
--- a/app/hub/Views/HomeView/__tests__/__snapshots__/HomeView.test.jsx.snap
+++ b/app/hub/Views/HomeView/__tests__/__snapshots__/HomeView.test.jsx.snap
@@ -75,7 +75,7 @@ exports[`app/hub/Views/HomeView component Snapshot tests with react-test-rendere
href="/create-account"
onClick={[Function]}
>
- hub_home_subheader_create_account
+ create_account
- hub_home_feature_tutorial_button
+ start
- hub_home_feature_setup_title
+ customize_setup
- hub_home_feature_supporter_button
+ get_ghostery_plus
@@ -295,7 +295,7 @@ exports[`app/hub/Views/HomeView component Snapshot tests with react-test-rendere
- hub_home_feature_setup_title
+ customize_setup
- hub_home_feature_supporter_button_alt
+ Aready_Subscribed
diff --git a/app/hub/Views/LogInView/LogInView.jsx b/app/hub/Views/LogInView/LogInView.jsx
index 2147985b6..6e76b3462 100644
--- a/app/hub/Views/LogInView/LogInView.jsx
+++ b/app/hub/Views/LogInView/LogInView.jsx
@@ -56,7 +56,7 @@ const LogInView = (props) => {
diff --git a/app/hub/Views/LogInView/LogInViewContainer.jsx b/app/hub/Views/LogInView/LogInViewContainer.jsx
index b5d9c616a..fb9cd1289 100644
--- a/app/hub/Views/LogInView/LogInViewContainer.jsx
+++ b/app/hub/Views/LogInView/LogInViewContainer.jsx
@@ -109,7 +109,7 @@ class LogInViewContainer extends Component {
this.props.history.push('/');
} else {
this.props.actions.setToast({
- toastMessage: t('hub_login_toast_error'),
+ toastMessage: t('no_such_email_password_combo'),
toastClass: 'alert'
});
}
diff --git a/app/hub/Views/LogInView/__tests__/__snapshots__/LogInView.test.jsx.snap b/app/hub/Views/LogInView/__tests__/__snapshots__/LogInView.test.jsx.snap
index 82823ec9d..d6b6f0e0f 100644
--- a/app/hub/Views/LogInView/__tests__/__snapshots__/LogInView.test.jsx.snap
+++ b/app/hub/Views/LogInView/__tests__/__snapshots__/LogInView.test.jsx.snap
@@ -40,7 +40,7 @@ exports[`app/hub/Views/LogIn component Snapshot tests with react-test-renderer l
className="LogInView__inputLabel"
htmlFor="login-email"
>
- hub_login_label_email
+ email_colon
- hub_login_label_password
+ password_colon
- hub_login_button_submit
+ sign_in
@@ -140,7 +140,7 @@ exports[`app/hub/Views/LogIn component Snapshot tests with react-test-renderer l
className="LogInView__inputLabel"
htmlFor="login-email"
>
- hub_login_label_email
+ email_colon
- hub_login_label_email_invalid
+ please_enter_a_valid_email
- hub_login_button_submit
+ sign_in
diff --git a/app/hub/Views/PlusView/PlusView.jsx b/app/hub/Views/PlusView/PlusView.jsx
index 9f6d0d89c..6457f84fe 100644
--- a/app/hub/Views/PlusView/PlusView.jsx
+++ b/app/hub/Views/PlusView/PlusView.jsx
@@ -36,11 +36,11 @@ class PlusView extends Component {
return isPlus ? (
- {t('hub_supporter_button_text_alt')}
+ {t('already_subscribed')}
) : (
- {t('hub_supporter_button_text')}
+ {t('get_ghostery_plus')}
);
}
@@ -74,7 +74,7 @@ class PlusView extends Component {
- {t('hub_supporter_perk_themes_title')}
+ {t('new_themes')}
{t('hub_supporter_perk_themes_description')}
@@ -83,7 +83,7 @@ class PlusView extends Component {
- {t('hub_supporter_perk_stats_title')}
+ {t('historical_blocking_stats')}
{t('hub_supporter_perk_stats_description')}
@@ -110,7 +110,7 @@ class PlusView extends Component {
- {t('hub_supporter_feature_theme_title')}
+ {t('new_themes')}
{t('hub_supporter_feature_theme_description')}
@@ -121,7 +121,7 @@ class PlusView extends Component {
@@ -139,12 +139,12 @@ class PlusView extends Component {
- {t('hub_supporter_feature_stats_title')}
+ {t('historical_blocking_stats')}
{t('hub_supporter_feature_stats_description')}
@@ -155,7 +155,7 @@ class PlusView extends Component {
@@ -171,7 +171,7 @@ class PlusView extends Component {
- {t('hub_supporter_feature_support_title')}
+ {t('priority_support')}
{t('hub_supporter_feature_support_description')}
@@ -182,7 +182,7 @@ class PlusView extends Component {
diff --git a/app/hub/Views/PlusView/__tests__/__snapshots__/PlusView.test.jsx.snap b/app/hub/Views/PlusView/__tests__/__snapshots__/PlusView.test.jsx.snap
index dff7f3f49..c673637ca 100644
--- a/app/hub/Views/PlusView/__tests__/__snapshots__/PlusView.test.jsx.snap
+++ b/app/hub/Views/PlusView/__tests__/__snapshots__/PlusView.test.jsx.snap
@@ -29,7 +29,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
- hub_supporter_button_text_alt
+ already_subscribed
- hub_supporter_perk_themes_title
+ new_themes
- hub_supporter_perk_stats_title
+ historical_blocking_stats
- hub_supporter_feature_theme_title
+ new_themes
- hub_supporter_button_text_alt
+ already_subscribed

@@ -157,7 +157,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
- hub_supporter_button_text_alt
+ already_subscribed

@@ -186,7 +186,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
- hub_supporter_feature_stats_title
+ historical_blocking_stats
- hub_supporter_button_text_alt
+ already_subscribed

@@ -221,7 +221,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
- hub_supporter_button_text_alt
+ already_subscribed
- hub_supporter_feature_support_title
+ priority_support
- hub_supporter_button_text_alt
+ already_subscribed

@@ -276,7 +276,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
- hub_supporter_button_text_alt
+ already_subscribed
- hub_supporter_button_text_alt
+ already_subscribed
- hub_supporter_button_text
+ get_ghostery_plus
- hub_supporter_perk_themes_title
+ new_themes
- hub_supporter_perk_stats_title
+ historical_blocking_stats
- hub_supporter_feature_theme_title
+ new_themes
- hub_supporter_button_text
+ get_ghostery_plus

@@ -502,7 +502,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
rel="noopener noreferrer"
target="_blank"
>
- hub_supporter_button_text
+ get_ghostery_plus

@@ -531,7 +531,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
- hub_supporter_feature_stats_title
+ historical_blocking_stats
- hub_supporter_button_text
+ get_ghostery_plus

@@ -574,7 +574,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
rel="noopener noreferrer"
target="_blank"
>
- hub_supporter_button_text
+ get_ghostery_plus
- hub_supporter_feature_support_title
+ priority_support
- hub_supporter_button_text
+ get_ghostery_plus

@@ -637,7 +637,7 @@ exports[`app/hub/Views/PlusView component Snapshot tests with react-test-rendere
rel="noopener noreferrer"
target="_blank"
>
- hub_supporter_button_text
+ get_ghostery_plus
- hub_supporter_button_text
+ get_ghostery_plus
diff --git a/app/hub/Views/RewardsView/__tests__/__snapshots__/RewardsView.test.jsx.snap b/app/hub/Views/RewardsView/__tests__/__snapshots__/RewardsView.test.jsx.snap
index fa349dd34..f5d3ad6fe 100644
--- a/app/hub/Views/RewardsView/__tests__/__snapshots__/RewardsView.test.jsx.snap
+++ b/app/hub/Views/RewardsView/__tests__/__snapshots__/RewardsView.test.jsx.snap
@@ -37,7 +37,7 @@ exports[`app/hub/Views/RewardsView component Snapshot tests with react-test-rend
rel="noopener noreferrer"
target="_blank"
>
- hub_rewards_header_learn_more
+ learn_more
diff --git a/app/hub/Views/SetupViews/SetupAntiSuiteView/SetupAntiSuiteViewContainer.jsx b/app/hub/Views/SetupViews/SetupAntiSuiteView/SetupAntiSuiteViewContainer.jsx
index 08302f49b..42c9f03fe 100644
--- a/app/hub/Views/SetupViews/SetupAntiSuiteView/SetupAntiSuiteViewContainer.jsx
+++ b/app/hub/Views/SetupViews/SetupAntiSuiteView/SetupAntiSuiteViewContainer.jsx
@@ -36,8 +36,8 @@ class SetupAntiSuiteViewContainer extends Component {
hrefPrev: `/setup/${index - 1}`,
hrefNext: `/setup/${index + 1}`,
hrefDone: '/',
- textPrev: t('hub_setup_nav_previous'),
- textNext: t('hub_setup_nav_next'),
+ textPrev: t('previous'),
+ textNext: t('next'),
textDone: t('hub_setup_exit_flow'),
});
@@ -103,7 +103,7 @@ class SetupAntiSuiteViewContainer extends Component {
const features = [
{
id: 'anti-tracking',
- name: t('hub_setup_antisuite_name_antitracking'),
+ name: t('enhanced_anti_tracking'),
enabled: anti_tracking_enabled,
locked: IS_CLIQZ,
toggle: IS_CLIQZ ?
@@ -113,20 +113,20 @@ class SetupAntiSuiteViewContainer extends Component {
},
{
id: 'ad-block',
- name: t('hub_setup_adblock_name_adblocking'),
+ name: t('enhanced_ad_blocking'),
enabled: ad_block_enabled,
locked: IS_CLIQZ,
toggle: IS_CLIQZ ?
() => {} :
() => this._handleToggle('ad-block'),
- description: IS_CLIQZ ? t('hub_setup_feature_already_active') : t('hub_setup_adblock_description_adblocking'),
+ description: IS_CLIQZ ? t('hub_setup_feature_already_active') : t('ad_blocking_DESC'),
},
{
id: 'smart-blocking',
- name: t('hub_setup_smartblocking_name_smartblocking'),
+ name: t('smart_blocking'),
enabled: enable_smart_block,
toggle: () => this._handleToggle('smart-blocking'),
- description: t('hub_setup_smartblocking_description_smartblocking'),
+ description: t('smart_blocking_DESC'),
}
];
diff --git a/app/hub/Views/SetupViews/SetupBlockingDropdown/SetupBlockingDropdown.jsx b/app/hub/Views/SetupViews/SetupBlockingDropdown/SetupBlockingDropdown.jsx
index f876ad30b..1944171e1 100644
--- a/app/hub/Views/SetupViews/SetupBlockingDropdown/SetupBlockingDropdown.jsx
+++ b/app/hub/Views/SetupViews/SetupBlockingDropdown/SetupBlockingDropdown.jsx
@@ -80,7 +80,7 @@ class SetupBlockingDropdown extends Component {
- {t('hub_setup_nav_done')}
+ {t('done')}
diff --git a/app/hub/Views/SetupViews/SetupBlockingDropdown/__tests__/__snapshots__/SetupBlockingDropdown.test.jsx.snap b/app/hub/Views/SetupViews/SetupBlockingDropdown/__tests__/__snapshots__/SetupBlockingDropdown.test.jsx.snap
index 0fe67c4a8..1bbb9a35c 100644
--- a/app/hub/Views/SetupViews/SetupBlockingDropdown/__tests__/__snapshots__/SetupBlockingDropdown.test.jsx.snap
+++ b/app/hub/Views/SetupViews/SetupBlockingDropdown/__tests__/__snapshots__/SetupBlockingDropdown.test.jsx.snap
@@ -14,7 +14,7 @@ exports[`app/hub/Views/SetupViews/SetupBlockingDropdown component Snapshot tests
className="button success"
onClick={[Function]}
>
- hub_setup_nav_done
+ done
diff --git a/app/hub/Views/SetupViews/SetupBlockingView/SetupBlockingViewContainer.jsx b/app/hub/Views/SetupViews/SetupBlockingView/SetupBlockingViewContainer.jsx
index fdc2e5124..e1b7ac71c 100644
--- a/app/hub/Views/SetupViews/SetupBlockingView/SetupBlockingViewContainer.jsx
+++ b/app/hub/Views/SetupViews/SetupBlockingView/SetupBlockingViewContainer.jsx
@@ -40,7 +40,7 @@ class SetupBlockingViewContainer extends Component {
hrefNext: `/setup/${index + 1}`,
hrefDone: '/',
textPrev: false,
- textNext: t('hub_setup_nav_next'),
+ 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 1416b0388..3ee04fcb9 100644
--- a/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx
+++ b/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx
@@ -33,8 +33,8 @@ class SetupDoneViewContainer extends Component {
hrefPrev: `/setup/${index - 1}`,
hrefNext: '/',
hrefDone: '/',
- textPrev: t('hub_setup_nav_previous'),
- textNext: t('hub_setup_nav_done'),
+ textPrev: t('previous'),
+ textNext: t('done'),
textDone: t('hub_setup_exit_flow'),
});
@@ -56,14 +56,14 @@ class SetupDoneViewContainer extends Component {
id: 'tutorial',
title: t('hub_setup_feature_tutorial_title'),
description: t('hub_setup_feature_tutorial_description'),
- buttonText: t('hub_setup_feature_tutorial_button'),
+ buttonText: t('start'),
buttonHref: '/tutorial/1',
},
{
id: 'plus',
- title: t('hub_setup_feature_supporter_title'),
+ title: t('get_ghostery_plus'),
description: t('hub_setup_feature_supporter_description'),
- buttonText: t('hub_setup_feature_supporter_button'),
+ buttonText: t('support'),
buttonHref: '/plus',
},
{
diff --git a/app/hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebViewContainer.jsx b/app/hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebViewContainer.jsx
index c7dc7ee8f..3e6415082 100644
--- a/app/hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebViewContainer.jsx
+++ b/app/hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebViewContainer.jsx
@@ -33,8 +33,8 @@ class SetupHumanWebViewContainer extends Component {
hrefPrev: `/setup/${index - 1}`,
hrefNext: `/setup/${index + 1}`,
hrefDone: '/',
- textPrev: t('hub_setup_nav_previous'),
- textNext: t('hub_setup_nav_next'),
+ textPrev: t('previous'),
+ textNext: t('next'),
textDone: t('hub_setup_exit_flow'),
});
diff --git a/app/hub/Views/SideNavigationView/SideNavigationViewContainer.jsx b/app/hub/Views/SideNavigationView/SideNavigationViewContainer.jsx
index f3526640f..7bd78abcf 100644
--- a/app/hub/Views/SideNavigationView/SideNavigationViewContainer.jsx
+++ b/app/hub/Views/SideNavigationView/SideNavigationViewContainer.jsx
@@ -49,21 +49,21 @@ class SideNavigationViewContainer extends Component {
const menuItems = [
{ href: '/', icon: 'home', text: t('hub_side_navigation_home') },
- { href: '/setup', icon: 'setup', text: t('hub_side_navigation_setup') },
+ { href: '/setup', icon: 'setup', text: t('customize_setup') },
{ href: '/tutorial', icon: 'tutorial', text: t('hub_side_navigation_tutorial') },
- { href: '/plus', icon: 'plus', text: t('hub_side_navigation_supporter') },
+ { href: '/plus', icon: 'plus', text: t('get_ghostery_plus') },
...(IS_CLIQZ ? [] : [{ href: '/rewards', icon: 'rewards', text: t('hub_side_navigation_rewards') }]),
{ href: '/products', icon: 'products', text: t('hub_side_navigation_products') }
];
const bottomItems = user ? [
{ id: 'email', href: `https://account.${globals.GHOSTERY_DOMAIN}.com/`, text: user.email },
- { id: 'logout', text: t('hub_side_navigation_log_out'), clickHandler: this._handleLogoutClick },
+ { id: 'logout', text: t('sign_out'), clickHandler: this._handleLogoutClick },
] : [
- { id: 'create-account', href: '/create-account', text: t('hub_side_navigation_create_account') },
+ { id: 'create-account', href: '/create-account', text: t('create_account') },
{
id: 'log-id',
href: '/log-in',
- text: t('hub_side_navigation_log_in'),
+ text: t('sign_in'),
icon: 'profile',
},
];
diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteView.jsx b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteView.jsx
index ed5776b48..5b4ec4e55 100644
--- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteView.jsx
+++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteView.jsx
@@ -22,20 +22,20 @@ const TutorialAntiSuiteView = () => (
- {t('hub_tutorial_simple_view')}
+ {t('simple_view')}
- {t('hub_tutorial_detailed_view')}
+ {t('detailed_view')}
@@ -48,7 +48,7 @@ const TutorialAntiSuiteView = () => (
- {t('hub_tutorial_antisuite_antitracking_title')}
+ {t('enhanced_anti_tracking')}
{t('hub_tutorial_antisuite_antitracking_description')}
@@ -59,10 +59,10 @@ const TutorialAntiSuiteView = () => (
- {t('hub_tutorial_antisuite_adblocking_title')}
+ {t('enhanced_ad_blocking')}
- {t('hub_tutorial_antisuite_adblocking_description')}
+ {t('ad_blocking_DESC')}
@@ -70,10 +70,10 @@ const TutorialAntiSuiteView = () => (
- {t('hub_tutorial_antisuite_smartblocking_title')}
+ {t('smart_blocking')}
- {t('hub_tutorial_antisuite_smartblocking_description')}
+ {t('smart_blocking_DESC')}
diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx
index bd8a4af68..a08f8708c 100644
--- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx
@@ -33,8 +33,8 @@ class TutorialAntiSuiteViewContainer extends Component {
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: '/',
hrefDone: '/',
- textPrev: t('hub_tutorial_nav_previous'),
- textNext: t('hub_tutorial_nav_done'),
+ textPrev: t('previous'),
+ textNext: t('done'),
textDone: t('hub_tutorial_exit_flow'),
});
diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/__test__/__snapshots__/TutorialAntiSuiteView.test.jsx.snap b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/__test__/__snapshots__/TutorialAntiSuiteView.test.jsx.snap
index a99bef9d4..83a6fdc3e 100644
--- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/__test__/__snapshots__/TutorialAntiSuiteView.test.jsx.snap
+++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/__test__/__snapshots__/TutorialAntiSuiteView.test.jsx.snap
@@ -10,20 +10,20 @@ exports[`app/hub/Views/TutorialViews/TutorialAntiSuiteView component Snapshot te
- hub_tutorial_simple_view
+ simple_view
- hub_tutorial_detailed_view
+ detailed_view

@@ -49,7 +49,7 @@ exports[`app/hub/Views/TutorialViews/TutorialAntiSuiteView component Snapshot te
- hub_tutorial_antisuite_antitracking_title
+ enhanced_anti_tracking
- hub_tutorial_antisuite_adblocking_title
+ enhanced_ad_blocking
- hub_tutorial_antisuite_adblocking_description
+ ad_blocking_DESC
@@ -87,12 +87,12 @@ exports[`app/hub/Views/TutorialViews/TutorialAntiSuiteView component Snapshot te
- hub_tutorial_antisuite_smartblocking_title
+ smart_blocking
- hub_tutorial_antisuite_smartblocking_description
+ smart_blocking_DESC
diff --git a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingView.jsx b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingView.jsx
index eb3d9e4a7..ca0199702 100644
--- a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingView.jsx
+++ b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingView.jsx
@@ -22,12 +22,12 @@ const TutorialBlockingView = () => (
- {t('hub_tutorial_detailed_view')}
+ {t('detailed_view')}
{t('hub_tutorial_detailed_expanded_view')}
diff --git a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx
index d85fc5dfd..246ac22d1 100644
--- a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx
@@ -33,8 +33,8 @@ class TutorialBlockingViewContainer extends Component {
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: `/tutorial/${index + 1}`,
hrefDone: '/',
- textPrev: t('hub_tutorial_nav_previous'),
- textNext: t('hub_tutorial_nav_next'),
+ textPrev: t('previous'),
+ textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
});
}
diff --git a/app/hub/Views/TutorialViews/TutorialBlockingView/__tests__/__snapshots__/TutorialBlockingView.test.jsx.snap b/app/hub/Views/TutorialViews/TutorialBlockingView/__tests__/__snapshots__/TutorialBlockingView.test.jsx.snap
index a86a12011..f314105f1 100644
--- a/app/hub/Views/TutorialViews/TutorialBlockingView/__tests__/__snapshots__/TutorialBlockingView.test.jsx.snap
+++ b/app/hub/Views/TutorialViews/TutorialBlockingView/__tests__/__snapshots__/TutorialBlockingView.test.jsx.snap
@@ -10,10 +10,10 @@ exports[`app/hub/Views/TutorialViews/TutorialBlockingView component Snapshot tes
- hub_tutorial_detailed_view
+ detailed_view

diff --git a/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutView.jsx b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutView.jsx
index f869c252e..56a7bac57 100644
--- a/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutView.jsx
+++ b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutView.jsx
@@ -24,12 +24,12 @@ const TutorialLayoutView = () => (
diff --git a/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx
index e8e276dea..407bf8fa9 100644
--- a/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx
@@ -33,8 +33,8 @@ class TutorialLayoutViewContainer extends Component {
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: `/tutorial/${index + 1}`,
hrefDone: '/',
- textPrev: t('hub_tutorial_nav_previous'),
- textNext: t('hub_tutorial_nav_next'),
+ textPrev: t('previous'),
+ textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
});
}
diff --git a/app/hub/Views/TutorialViews/TutorialLayoutView/__tests__/__snapshots__/TutorialLayoutView.test.jsx.snap b/app/hub/Views/TutorialViews/TutorialLayoutView/__tests__/__snapshots__/TutorialLayoutView.test.jsx.snap
index 4bfd63c38..1b7dcb048 100644
--- a/app/hub/Views/TutorialViews/TutorialLayoutView/__tests__/__snapshots__/TutorialLayoutView.test.jsx.snap
+++ b/app/hub/Views/TutorialViews/TutorialLayoutView/__tests__/__snapshots__/TutorialLayoutView.test.jsx.snap
@@ -8,12 +8,12 @@ exports[`app/hub/Views/TutorialViews/TutorialLayoutView component Snapshot tests
className="columns small-10 medium-8 large-6 small-offset-1"
>

diff --git a/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx
index f09f35815..b59c40b1d 100644
--- a/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx
@@ -33,8 +33,8 @@ class TutorialTrackerListViewContainer extends Component {
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: `/tutorial/${index + 1}`,
hrefDone: '/',
- textPrev: t('hub_tutorial_nav_previous'),
- textNext: t('hub_tutorial_nav_next'),
+ textPrev: t('previous'),
+ textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
});
}
diff --git a/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustView.jsx b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustView.jsx
index 31c66ff5a..605aaa9cb 100644
--- a/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustView.jsx
+++ b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustView.jsx
@@ -22,20 +22,20 @@ const TutorialTrustView = () => (
- {t('hub_tutorial_simple_view')}
+ {t('simple_view')}
- {t('hub_tutorial_detailed_view')}
+ {t('detailed_view')}
diff --git a/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx
index 373233096..f48598ad0 100644
--- a/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx
@@ -33,8 +33,8 @@ class TutorialTrustViewContainer extends Component {
hrefPrev: `/tutorial/${index - 1}`,
hrefNext: `/tutorial/${index + 1}`,
hrefDone: '/',
- textPrev: t('hub_tutorial_nav_previous'),
- textNext: t('hub_tutorial_nav_next'),
+ textPrev: t('previous'),
+ textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
});
}
diff --git a/app/hub/Views/TutorialViews/TutorialTrustView/__tests__/__snapshots__/TutorialTrustView.test.jsx.snap b/app/hub/Views/TutorialViews/TutorialTrustView/__tests__/__snapshots__/TutorialTrustView.test.jsx.snap
index a472a37fe..27e9a3973 100644
--- a/app/hub/Views/TutorialViews/TutorialTrustView/__tests__/__snapshots__/TutorialTrustView.test.jsx.snap
+++ b/app/hub/Views/TutorialViews/TutorialTrustView/__tests__/__snapshots__/TutorialTrustView.test.jsx.snap
@@ -10,20 +10,20 @@ exports[`app/hub/Views/TutorialViews/TutorialTrustView component Snapshot tests
- hub_tutorial_simple_view
+ simple_view
- hub_tutorial_detailed_view
+ detailed_view

diff --git a/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx
index 65b4a5ee2..a6af3c5ce 100644
--- a/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx
+++ b/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx
@@ -34,7 +34,7 @@ class TutorialVideoViewContainer extends Component {
hrefNext: `/tutorial/${index + 1}`,
hrefDone: '/',
textPrev: false,
- textNext: t('hub_tutorial_nav_next'),
+ textNext: t('next'),
textDone: t('hub_tutorial_exit_flow'),
});
}
diff --git a/app/hub/utils/index.js b/app/hub/utils/index.js
index 0766b4f07..156704369 100644
--- a/app/hub/utils/index.js
+++ b/app/hub/utils/index.js
@@ -14,10 +14,14 @@
// Imports utilities from elsewhere in the codebase to reduce duplicate code
import { log } from '../../../src/utils/common';
-import { sendMessageInPromise as importedSMIP } from '../../panel/utils/msg';
+import { sendMessage as importedSM, sendMessageInPromise as importedSMIP } from '../../panel/utils/msg';
const sendMessageInPromise = function(name, message) {
return importedSMIP(name, message, 'ghostery-hub');
};
-export { log, sendMessageInPromise };
+const sendMessage = function(name, message) {
+ return importedSM(name, message, 'ghostery-hub');
+};
+
+export { log, sendMessage, sendMessageInPromise };
diff --git a/app/images/hub/home/check-icon.svg b/app/images/hub/home/check-icon.svg
new file mode 100644
index 000000000..7e2e16aad
--- /dev/null
+++ b/app/images/hub/home/check-icon.svg
@@ -0,0 +1,12 @@
+
diff --git a/app/images/hub/home/gold-ghostie-badge.svg b/app/images/hub/home/gold-ghostie-badge.svg
new file mode 100644
index 000000000..a6cba7a4d
--- /dev/null
+++ b/app/images/hub/home/gold-ghostie-badge.svg
@@ -0,0 +1,25 @@
+
diff --git a/app/images/hub/home/recommended-banner.svg b/app/images/hub/home/recommended-banner.svg
new file mode 100644
index 000000000..4777a7728
--- /dev/null
+++ b/app/images/hub/home/recommended-banner.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/app/images/panel/checked-circle-icon.svg b/app/images/panel/checked-circle-icon.svg
new file mode 100644
index 000000000..493ad4055
--- /dev/null
+++ b/app/images/panel/checked-circle-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/images/panel/insights-ribbon.svg b/app/images/panel/insights-ribbon.svg
new file mode 100644
index 000000000..568714725
--- /dev/null
+++ b/app/images/panel/insights-ribbon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/panel/actions/PanelActions.js b/app/panel/actions/PanelActions.js
index 601f169e9..9079120f0 100644
--- a/app/panel/actions/PanelActions.js
+++ b/app/panel/actions/PanelActions.js
@@ -17,7 +17,8 @@ import {
CLOSE_NOTIFICATION,
TOGGLE_EXPERT,
SET_THEME,
- CLEAR_THEME
+ CLEAR_THEME,
+ TOGGLE_PROMO_MODAL
} from '../constants/constants';
import { sendMessageInPromise } from '../utils/msg';
@@ -98,3 +99,13 @@ export const getTheme = name => dispatch => (
}
})
);
+
+/**
+ * Triggered when the user signs in through the Insights modal into an account that does not have an insights subscription, prompting to re-display the modal, requiring a re-render
+ * @return {Object}
+ */
+export function togglePromoModal() {
+ return {
+ type: TOGGLE_PROMO_MODAL,
+ };
+}
diff --git a/app/panel/components/BuildingBlocks/CliqzFeature.jsx b/app/panel/components/BuildingBlocks/CliqzFeature.jsx
index 72cfe1372..b699e387a 100644
--- a/app/panel/components/BuildingBlocks/CliqzFeature.jsx
+++ b/app/panel/components/BuildingBlocks/CliqzFeature.jsx
@@ -51,19 +51,50 @@ class CliqzFeature extends React.Component {
}
_getStatus(active) {
- return active ? t('cliqz_feature_status_on') : t('cliqz_feature_status_off');
+ return active ? t('on') : t('off');
}
_getTooltipBodyText(active, isTooltipBody, type) {
if (!isTooltipBody) return false;
- return active ?
- t(`tooltip_${type}_body_on`) :
- t(`tooltip_${type}_body`);
+ if (active) {
+ switch (type) {
+ case 'ad_block':
+ return t('tooltip_ad_block_on');
+ case 'anti_track':
+ return t('tooltip_anti_track_on');
+ case 'smart_block':
+ return t('tooltip_smart_block_on');
+ default:
+ return false;
+ }
+ } else {
+ switch (type) {
+ case 'ad_block':
+ return t('ad_blocking_DESC');
+ case 'anti_track':
+ return t('anti_tracking_DESC');
+ case 'smart_block':
+ return t('smart_blocking_DESC');
+ default:
+ return false;
+ }
+ }
}
_getTooltipHeaderText(isTooltipHeader, type) {
- return isTooltipHeader ? t(`tooltip_${type}`) : false;
+ if (!isTooltipHeader) return false;
+
+ switch (type) {
+ case 'ad_block':
+ return t('enhanced_ad_blocking');
+ case 'anti_track':
+ return t('enhanced_anti_tracking');
+ case 'smart_block':
+ return t('smart_blocking');
+ default:
+ return false;
+ }
}
_getAlertText(active, type) {
@@ -103,7 +134,14 @@ class CliqzFeature extends React.Component {
const iconClassNames = ClassNames('CliqzFeature__icon', cssTypeName, 'g-tooltip');
const featureType = type === 'anti_track' ? 'anti_tracking' : type;
- const featureName = t(`drawer_title_enable_${featureType}`);
+ let featureName;
+ if (featureType === 'anti_tracking') {
+ featureName = t('enhanced_anti_tracking');
+ } else if (featureType === 'ad_block') {
+ featureName = t('enhanced_ad_blocking');
+ } else if (featureType === 'smart_block') {
+ featureName = t('smart_blocking');
+ }
return (
diff --git a/app/panel/components/BuildingBlocks/ModalExitButton.jsx b/app/panel/components/BuildingBlocks/ModalExitButton.jsx
new file mode 100644
index 000000000..92dad90e3
--- /dev/null
+++ b/app/panel/components/BuildingBlocks/ModalExitButton.jsx
@@ -0,0 +1,40 @@
+
+/**
+ * Modal Exit Button Component
+ *
+ * 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 React from 'react';
+import PropTypes from 'prop-types';
+
+/**
+ * A Functional React component for a Exit Button
+ * @return {JSX} JSX for rendering a Exit Button
+ * @memberof SharedComponents
+ */
+const ModalExitButton = (props) => {
+ const {
+ toggleModal
+ } = props;
+
+ return (
+
+ );
+};
+
+// PropTypes ensure we pass required props of the correct type
+ModalExitButton.propTypes = {
+ toggleModal: PropTypes.func.isRequired
+};
+
+export default ModalExitButton;
diff --git a/app/panel/components/BuildingBlocks/PanelToTabLink.jsx b/app/panel/components/BuildingBlocks/PanelToTabLink.jsx
index 32748e1b1..286827c53 100644
--- a/app/panel/components/BuildingBlocks/PanelToTabLink.jsx
+++ b/app/panel/components/BuildingBlocks/PanelToTabLink.jsx
@@ -19,10 +19,12 @@ import { handleClickOnNewTabLink } from '../../utils/msg';
* @memberof PanelBuildingBlocks
*/
const PanelToTabLink = (props) => {
- const { href, children } = props;
+ const { className, href, children } = props;
+
+ const classes = className || '';
return (
-
{children}
+
{children}
);
};
diff --git a/app/panel/components/BuildingBlocks/index.js b/app/panel/components/BuildingBlocks/index.js
index e689a77de..3cb86a8ca 100644
--- a/app/panel/components/BuildingBlocks/index.js
+++ b/app/panel/components/BuildingBlocks/index.js
@@ -23,6 +23,7 @@ import PauseButton from './PauseButton';
import ToggleSlider from './ToggleSlider';
import RewardDetail from './RewardDetail';
import RewardListItem from './RewardListItem';
+import ModalExitButton from './ModalExitButton';
export {
ClickOutside,
@@ -33,5 +34,6 @@ export {
PauseButton,
ToggleSlider,
RewardDetail,
- RewardListItem
+ RewardListItem,
+ ModalExitButton
};
diff --git a/app/panel/components/CreateAccount.jsx b/app/panel/components/CreateAccount.jsx
index db5fe2f4a..8c615c5f5 100644
--- a/app/panel/components/CreateAccount.jsx
+++ b/app/panel/components/CreateAccount.jsx
@@ -152,21 +152,21 @@ class CreateAccount extends React.Component {
-
{ t('invalid_email_confirmation') }
+
{ t('your_emails_do_not_match') }
@@ -194,7 +194,7 @@ class CreateAccount extends React.Component {
@@ -240,7 +240,7 @@ class CreateAccount extends React.Component {
diff --git a/app/panel/components/DetailMenu.jsx b/app/panel/components/DetailMenu.jsx
index ecec07c98..9443029d5 100644
--- a/app/panel/components/DetailMenu.jsx
+++ b/app/panel/components/DetailMenu.jsx
@@ -74,7 +74,7 @@ class DetailMenu extends React.Component {
-
{ t('panel_detail_menu_stats_title') }
+
{ t('historical_stats') }
diff --git a/app/panel/components/ForgotPassword.jsx b/app/panel/components/ForgotPassword.jsx
index f187ff21d..b1d0f7bbe 100644
--- a/app/panel/components/ForgotPassword.jsx
+++ b/app/panel/components/ForgotPassword.jsx
@@ -83,7 +83,7 @@ class ForgotPassword extends React.Component {
diff --git a/app/panel/components/Header.jsx b/app/panel/components/Header.jsx
index 8768b72c2..a8be9d5ff 100644
--- a/app/panel/components/Header.jsx
+++ b/app/panel/components/Header.jsx
@@ -101,7 +101,7 @@ class Header extends React.Component {
let text = '';
let handleOnClick = null;
if (!loggedIn) {
- text = t('panel_header_sign_in');
+ text = t('sign_in');
handleOnClick = this.handleSignin;
} else if (loggedIn && user && !user.emailValidated) {
text = t('panel_header_verify_account');
@@ -186,7 +186,7 @@ class Header extends React.Component {
const simpleTab = (
- {t('panel_header_simple_view')}
+ {t('simple_view')}
);
@@ -194,7 +194,7 @@ class Header extends React.Component {
const detailedTab = (
- {t('panel_header_detailed_view')}
+ {t('detailed_view')}
);
diff --git a/app/panel/components/HeaderMenu.jsx b/app/panel/components/HeaderMenu.jsx
index 5b0dcc2d7..bc03910c0 100644
--- a/app/panel/components/HeaderMenu.jsx
+++ b/app/panel/components/HeaderMenu.jsx
@@ -236,7 +236,7 @@ class HeaderMenu extends React.Component {
-
{ t('panel_menu_ghostery_subscriber') }
+
{ t('ghostery_plus') }
@@ -251,10 +251,10 @@ class HeaderMenu extends React.Component {
{ email }
- { t('panel_menu_signin') }
+ { t('sign_in') }
- { t('panel_menu_signout') }
+ { t('sign_out') }
diff --git a/app/panel/components/Help.jsx b/app/panel/components/Help.jsx
index 057a47736..c436a5b06 100644
--- a/app/panel/components/Help.jsx
+++ b/app/panel/components/Help.jsx
@@ -33,7 +33,7 @@ const Help = () => {
{ t('panel_help_questions_header') }
{t('panel_help_faq')}
{t('panel_help_feedback')}
-
{ t('panel_help_support') }
+
{ t('support') }
{ t('panel_help_contact_header') }
diff --git a/app/panel/components/InsightsPromoModal.jsx b/app/panel/components/InsightsPromoModal.jsx
new file mode 100644
index 000000000..98a6b9dcf
--- /dev/null
+++ b/app/panel/components/InsightsPromoModal.jsx
@@ -0,0 +1,93 @@
+/**
+ * Insights Promo Modal Component
+ *
+ * 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 React from 'react';
+import globals from '../../../src/classes/Globals';
+import Modal from '../../shared-components/Modal';
+import ModalExitButton from './BuildingBlocks/ModalExitButton';
+import PanelToTabLink from './BuildingBlocks/PanelToTabLink';
+
+const INSIGHTS = 'insights';
+const CTA_LINK = globals.DEBUG ? 'https://checkout.ghosterystage.com/insights' : 'http://ghostery.com/insights/';
+
+/**
+ * @class Implements the Insights Promo Modal
+ * @memberof PanelClasses
+ */
+class InsightsPromoModal extends React.Component {
+ handleNoThanksClick = () => { this.props.handleNoThanksClick(INSIGHTS); };
+
+ handleSignInClick = () => { this.props.handleSignInClick(INSIGHTS); };
+
+ handleXClick = () => { this.props.handleXClick(INSIGHTS); };
+
+ render() {
+ return (
+
+
+
+
+
+ {t('panel_insights_promotion_header')}
+
+
+ {t('panel_insights_promotion_description')}
+
+
+
+
+
+
+ { t('panel_insights_audit_tags') }
+
+
+
+
+
+ { t('panel_insights_promotion_trace_poor_performance') }
+
+
+
+
+
+
+
+ { t('panel_insights_promotion_watch_pings') }
+
+
+
+
+
+ { t('panel_insights_promotion_explore_trends') }
+
+
+
+
+
+
+
+ {t('panel_insights_promotion_call_to_action')}
+
+
+
+ {t('subscribe_pitch_sign_in')}
+ {t('no_thanks_turn_promos_off')}
+
+
+
+
+ );
+ }
+}
+
+export default InsightsPromoModal;
diff --git a/app/panel/components/Login.jsx b/app/panel/components/Login.jsx
index 4ea3c807d..6d793515c 100644
--- a/app/panel/components/Login.jsx
+++ b/app/panel/components/Login.jsx
@@ -17,6 +17,7 @@ import ClassNames from 'classnames';
import RSVP from 'rsvp';
import { validateEmail } from '../utils/utils';
import { log } from '../../../src/utils/common';
+import history from '../utils/history';
/**
* @class Implement Sign In view which opens from 'Sign In' CTA on the Header.
@@ -72,7 +73,10 @@ class Login extends React.Component {
})
.finally(() => {
this.setState({ loading: false }, () => {
- this.props.history.push(this.props.is_expert ? '/detail/blocking' : '/');
+ this.props.actions.togglePromoModal();
+ history.push({
+ pathname: this.props.is_expert ? '/detail/blocking' : '/'
+ });
});
});
} else {
@@ -99,7 +103,7 @@ class Login extends React.Component {
- { t('panel_create_account') }
+ { t('create_account') }
diff --git a/app/panel/components/Panel.jsx b/app/panel/components/Panel.jsx
index 684d21b4d..6c322b7a9 100644
--- a/app/panel/components/Panel.jsx
+++ b/app/panel/components/Panel.jsx
@@ -13,9 +13,13 @@
import React from 'react';
import Header from '../containers/HeaderContainer';
+import { PlusPromoModal, Modal } from '../../shared-components';
+import InsightsPromoModal from './InsightsPromoModal';
+import PlusUpgradePromoModal from './PlusUpgradePromoModal';
import { DynamicUIPortContext } from '../contexts/DynamicUIPortContext';
import { sendMessage } from '../utils/msg';
import { setTheme } from '../utils/utils';
+import history from '../utils/history';
/**
* @class Implement base view with functionality common to all views.
* @memberof PanelClasses
@@ -35,7 +39,6 @@ class Panel extends React.Component {
*/
componentDidMount() {
sendMessage('ping', 'engaged');
-
this._dynamicUIDataInitialized = false;
this._dynamicUIPort = chrome.runtime.connect({ name: 'dynamicUIPanelPort' });
this._dynamicUIPort.onMessage.addListener((msg) => {
@@ -58,6 +61,16 @@ class Panel extends React.Component {
this._dynamicUIPort.disconnect();
}
+ /**
+ * Reload the current tab
+ * @param {Object} event
+ * @todo Why do we need explicit argument here?
+ */
+ clickReloadBanner() {
+ sendMessage('reloadTab', { tab_id: +this.props.tab_id });
+ window.close();
+ }
+
/**
* Close banner notification
* @param {Object} event
@@ -80,16 +93,6 @@ class Panel extends React.Component {
});
}
- /**
- * Reload the current tab
- * @param {Object} event
- * @todo Why do we need explicit argument here?
- */
- clickReloadBanner() {
- sendMessage('reloadTab', { tab_id: +this.props.tab_id });
- window.close();
- }
-
/**
* Filter trackers when clicking on compatibility/slow
* tracker notifications and trigger appropriate action.
@@ -111,12 +114,12 @@ class Panel extends React.Component {
this.closeNotification();
}
-
/**
* Dynamic UI data port first payload handling
* Called once, when we get the first message from the background through the port
* @param {Object} payload the body of the message
*/
+
_initializeData(payload) {
this._dynamicUIDataInitialized = true;
@@ -148,6 +151,7 @@ class Panel extends React.Component {
}
}
+
/**
* Helper render function for the notification callout
* @return {JSX} JSX for the notification callout
@@ -193,6 +197,113 @@ class Panel extends React.Component {
return false;
}
+ _handlePromoNoThanksClick = (modal) => {
+ // TODO metrics ping
+ this.props.actions.togglePromoModal();
+ sendMessage('promoModals.turnOffPromos', {});
+ };
+
+ _handlePromoSignInClick = (modal) => {
+ // TODO metrics ping
+ this.props.actions.togglePromoModal();
+ history.push({
+ pathname: '/login',
+ });
+ };
+
+ _handlePromoSelectBasicClick = () => {
+ // TODO send metrics ping
+ this.props.actions.togglePromoModal();
+ };
+
+ _handlePromoSelectPlusClick = () => {
+ // TODO send metrics ping
+ this.props.actions.togglePromoModal();
+ };
+
+ _handlePromoSubscribeClick = (modal) => {
+ // TODO send metrics ping
+ this.props.actions.togglePromoModal();
+ };
+
+ _handlePromoXClick = (modal) => {
+ // TODO send metrics ping
+ this.props.actions.togglePromoModal();
+ };
+
+ _plusSubscriber = () => {
+ const { loggedIn, user } = this.props;
+
+ return loggedIn && (user && user.subscriptionsPlus);
+ }
+
+ _insightsSubscriber = () => {
+ const { loggedIn, user } = this.props;
+
+ return loggedIn && (user && user.scopes && user.scopes.includes('subscriptions:insights'));
+ }
+
+ _renderPlusPromoModal = () => {
+ if (this._plusSubscriber() || this._insightsSubscriber()) return null;
+
+ sendMessage('promoModals.sawPlusPromo', {});
+
+ if (this.props.promoModal === 'plus_upgrade') {
+ return (
+
+ );
+ }
+
+ // promoModal === 'plus_initial'
+ return (
+
+ );
+ }
+
+ _renderInsightsPromoModal = () => {
+ if (this._insightsSubscriber()) return null;
+
+ sendMessage('promoModals.sawInsightsPromo', '', 'metrics');
+
+ return (
+
+ );
+ }
+
+ _renderPromoModal = () => {
+ const {
+ promoModal,
+ isPromoModalHidden,
+ } = this.props;
+
+ if (isPromoModalHidden) return null;
+
+ if (promoModal === 'insights') {
+ return this._renderInsightsPromoModal();
+ }
+
+ if (promoModal === 'plus_initial' || promoModal === 'plus_upgrade') {
+ return this._renderPlusPromoModal();
+ }
+
+ return null;
+ }
+
/**
* React's required render function. Returns JSX
* @return {JSX} JSX for rendering the Panel
@@ -207,6 +318,7 @@ class Panel extends React.Component {
return (
+ {this._renderPromoModal()}
);
diff --git a/app/panel/components/Settings/Notifications.jsx b/app/panel/components/Settings/Notifications.jsx
index 9569486d7..6b658001b 100644
--- a/app/panel/components/Settings/Notifications.jsx
+++ b/app/panel/components/Settings/Notifications.jsx
@@ -41,6 +41,12 @@ const Notifications = (props) => {
+
+
+
+
+
+
diff --git a/app/panel/components/Stats.jsx b/app/panel/components/Stats.jsx
index 117230c8f..b4028171b 100644
--- a/app/panel/components/Stats.jsx
+++ b/app/panel/components/Stats.jsx
@@ -106,13 +106,13 @@ class Stats extends React.Component {
getSummaryTitle = (type) => {
switch (type) {
case 'cumulative':
- return t('panel_stats_header_title');
+ return t('historical_tracker_stats');
case 'monthly':
return t('panel_stats_header_title_monthly');
case 'daily':
return t('panel_stats_header_title_daily');
default:
- return t('panel_stats_header_title');
+ return t('historical_tracker_stats');
}
}
diff --git a/app/panel/components/StatsView.jsx b/app/panel/components/StatsView.jsx
index 312d8fa20..e850cac14 100644
--- a/app/panel/components/StatsView.jsx
+++ b/app/panel/components/StatsView.jsx
@@ -196,7 +196,7 @@ const StatsView = (props) => {
-
{t('panel_stats_pitch_modal_subscribe')}
+
{t('Get_Ghostery_Plus_bang')}
{ !loggedIn && (
diff --git a/app/panel/components/Subscribe.jsx b/app/panel/components/Subscribe.jsx
index dab8ecd5f..1bc92505d 100644
--- a/app/panel/components/Subscribe.jsx
+++ b/app/panel/components/Subscribe.jsx
@@ -40,11 +40,11 @@ const Subscribe = (props) => {
{t('subscribe_pitch_learn_more')}
- {t('subscribe_pitch_button_label')}
+ {t('Get_Ghostery_Plus_bang')}
{(loggedIn === 'false') && (
- {t('subscribe_pitch_sign_here')}
+ {t('already_subscribed_sign_in')}
)}
diff --git a/app/panel/components/Subscription/PrioritySupport.jsx b/app/panel/components/Subscription/PrioritySupport.jsx
index 57b63ec52..94ddd15aa 100644
--- a/app/panel/components/Subscription/PrioritySupport.jsx
+++ b/app/panel/components/Subscription/PrioritySupport.jsx
@@ -24,7 +24,7 @@ const PrioritySupport = () => (
-
{ t('subscription_priority_support_title') }
+
{ t('priority_support') }
{ t('subscription_support') }
diff --git a/app/panel/components/Subscription/SubscriptionInfo.jsx b/app/panel/components/Subscription/SubscriptionInfo.jsx
index 3090992c8..93c1161a4 100644
--- a/app/panel/components/Subscription/SubscriptionInfo.jsx
+++ b/app/panel/components/Subscription/SubscriptionInfo.jsx
@@ -45,7 +45,7 @@ const SubscriptionInfo = (props) => {
-
{ t('subscription_info_title') }
+
{ t('ghostery_plus') }
{loading ? (
) : (
@@ -75,8 +75,8 @@ const SubscriptionInfo = (props) => {
- {t('subscription_midnight_theme')}
- - {t('subscription_tracker_stats')}
- - {t('subscription_priority_support')}
+ - {t('historical_stats')}
+ - {t('priority_support')}
diff --git a/app/panel/components/Subscription/SubscriptionMenu.jsx b/app/panel/components/Subscription/SubscriptionMenu.jsx
index b718e67be..279ac3322 100644
--- a/app/panel/components/Subscription/SubscriptionMenu.jsx
+++ b/app/panel/components/Subscription/SubscriptionMenu.jsx
@@ -33,13 +33,13 @@ const SubscriptionMenu = () => (
- { t('subscription_priority_support') }
+ { t('priority_support') }
- { t('subscription_history_stats') }
+ { t('historical_stats') }
diff --git a/app/panel/components/Summary.jsx b/app/panel/components/Summary.jsx
index 766e84b0c..81fec0993 100644
--- a/app/panel/components/Summary.jsx
+++ b/app/panel/components/Summary.jsx
@@ -246,6 +246,7 @@ class Summary extends React.Component {
}
}
+
/**
* Calculates total tracker latency and sets it to state
* @param {Object} props Summary's props, either this.props or nextProps.
@@ -707,7 +708,7 @@ class Summary extends React.Component {
return (
-
+
);
}
diff --git a/app/panel/constants/constants.js b/app/panel/constants/constants.js
index 7d5a98342..8f7f8ede5 100644
--- a/app/panel/constants/constants.js
+++ b/app/panel/constants/constants.js
@@ -18,6 +18,7 @@ export const SHOW_NOTIFICATION = 'SHOW_NOTIFICATION';
export const TOGGLE_CLIQZ_FEATURE = 'TOGGLE_CLIQZ_FEATURE';
export const CLOSE_NOTIFICATION = 'CLOSE_NOTIFICATION';
export const TOGGLE_EXPERT = 'TOGGLE_EXPERT';
+export const TOGGLE_PROMO_MODAL = 'TOGGLE_PROMO_MODAL';
// summary
export const UPDATE_SUMMARY_DATA = 'UPDATE_SUMMARY_DATA';
diff --git a/app/panel/containers/PanelContainer.js b/app/panel/containers/PanelContainer.js
index ce4a744bb..2a4b9e007 100644
--- a/app/panel/containers/PanelContainer.js
+++ b/app/panel/containers/PanelContainer.js
@@ -27,7 +27,7 @@ import { updateBlockingData } from '../actions/BlockingActions';
* @todo We are not using ownProps, so we better not specify it explicitly,
* in this case it won't be passed by React (see https://github.com/reactjs/react-redux/blob/master/docs/api.md).
*/
-const mapStateToProps = state => Object.assign({}, state.panel, state.drawer, {
+const mapStateToProps = state => Object.assign({}, state.panel, state.drawer, state.account, {
paused_blocking: state.summary.paused_blocking,
sitePolicy: state.summary.sitePolicy,
trackerCounts: state.summary.trackerCounts,
diff --git a/app/panel/reducers/panel.js b/app/panel/reducers/panel.js
index 194f16c73..43b52ff11 100644
--- a/app/panel/reducers/panel.js
+++ b/app/panel/reducers/panel.js
@@ -26,7 +26,8 @@ import {
SET_OFFER_READ,
TOGGLE_EXPANDED,
SET_THEME,
- CLEAR_THEME
+ CLEAR_THEME,
+ TOGGLE_PROMO_MODAL
} from '../constants/constants';
import {
LOGIN_SUCCESS,
@@ -60,6 +61,7 @@ const initialState = {
email: '',
emailValidated: false,
current_theme: 'default',
+ isPromoModalHidden: false,
};
/**
* Default export for panel view reducer. Handles actions
@@ -108,7 +110,7 @@ export default (state = initialState, action) => {
switch (err.code) {
case '10050':
case '10110':
- errorText = t('banner_no_such_account_message');
+ errorText = t('no_such_email_password_combo');
break;
default:
errorText = t('server_error_message');
@@ -139,7 +141,7 @@ export default (state = initialState, action) => {
errorText = t('email_address_in_use');
break;
case '10080':
- errorText = t('invalid_email_confirmation');
+ errorText = t('your_emails_do_not_match');
break;
default:
errorText = t('server_error_message');
@@ -260,6 +262,12 @@ export default (state = initialState, action) => {
}
return state;
}
+ case TOGGLE_PROMO_MODAL: {
+ return {
+ ...state,
+ isPromoModalHidden: !state.isPromoModalHidden
+ };
+ }
default: return state;
}
};
diff --git a/app/scss/hub.scss b/app/scss/hub.scss
index 1faa03903..a59365f96 100644
--- a/app/scss/hub.scss
+++ b/app/scss/hub.scss
@@ -53,6 +53,7 @@ html, body, #root {
@import './partials/_hub_mixins';
@import './partials/_hub_svgs';
@import './partials/_shared_components_svgs';
+@import './partials/_fonts';
// Imports from ../hub directory
@import '../hub/Views/SideNavigationView/SideNavigationView.scss';
@@ -75,6 +76,7 @@ html, body, #root {
// Imports from ../shared-components directory
@import '../shared-components/ExitButton/ExitButton.scss';
@import '../shared-components/Modal/Modal.scss';
+@import '../shared-components/PlusPromoModal/PlusPromoModal.scss';
@import '../shared-components/SteppedNavigation/SteppedNavigation.scss';
@import '../shared-components/ToastMessage/ToastMessage.scss';
@import '../shared-components/ToggleCheckbox/ToggleCheckbox.scss';
diff --git a/app/scss/panel.scss b/app/scss/panel.scss
index c37affeec..3f6596ed4 100644
--- a/app/scss/panel.scss
+++ b/app/scss/panel.scss
@@ -51,6 +51,7 @@ html body {
// Partial View SASS files
@import './partials/_svgs';
+@import './partials/_shared_components_svgs';
@import './partials/_header';
@import './partials/_callout';
@import './partials/_summary';
@@ -73,3 +74,9 @@ html body {
@import './partials/_subscribe';
@import './partials/_stats';
@import './partials/_stats_graph';
+@import './partials/_modal_exit_button';
+@import './partials/insights_promo_modal.scss';
+
+// Imports from ../shared-components directory
+@import '../shared-components/Modal/Modal.scss';
+@import '../shared-components/PlusPromoModal/PlusPromoModal.scss';
diff --git a/app/scss/partials/_colors.scss b/app/scss/partials/_colors.scss
index 213fa9cab..d52e7f0ca 100644
--- a/app/scss/partials/_colors.scss
+++ b/app/scss/partials/_colors.scss
@@ -37,6 +37,7 @@ $ghosty-blue: #00AEF0;
$active-blue: #48ACD3; //top_nav_active_tab
$link-blue: #2092BF; //primary-color
$button-primary: #3AA2CF;
+$dark-cyan-blue: #325e97; //insights modal border
/* MARKETING COLORS */
$red: #E74055;
diff --git a/app/scss/partials/_fonts.scss b/app/scss/partials/_fonts.scss
index 0317018f2..c048be1ee 100644
--- a/app/scss/partials/_fonts.scss
+++ b/app/scss/partials/_fonts.scss
@@ -8,7 +8,7 @@
* 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
@@ -182,3 +182,45 @@
src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(../fonts/opensans-semibold-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
+/* roboto-300 - latin */
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 300;
+ src: local('Roboto Light'), local('Roboto-Light'), url('../fonts/roboto-latin-bold-300.woff2') format('woff2'),
+}
+/* roboto-regular - latin */
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Roboto'), local('Roboto-Regular'), url('../fonts/roboto-all-charsets.woff2') format('woff2'),
+}
+/* roboto-500 - latin */
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 500;
+ src: local('Roboto Medium'), local('Roboto-Medium'), url('../fonts/roboto-latin-bold-500.woff2') format('woff2'),
+}
+/* roboto-700 - latin */
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 700;
+ src: local('Roboto Bold'), local('Roboto-Bold'), url('../fonts/roboto-latin-bold-700.woff2') format('woff2'),
+}
+/* roboto-900 - latin */
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 900;
+ src: local('Roboto Black'), local('Roboto-Black'), url('../fonts/roboto-latin-bold-900.woff2') format('woff2'),
+}
+/* roboto-condensed-700 - latin */
+@font-face {
+ font-family: 'Roboto Condensed';
+ font-style: normal;
+ font-weight: 700;
+ src: local('Roboto Condensed Bold'), local('RobotoCondensed-Bold'), url('../fonts/roboto-condensed-latin-bold-700.woff2') format('woff2'), /* Super Modern Browsers */
+}
diff --git a/app/scss/partials/_insights_promo_modal.scss b/app/scss/partials/_insights_promo_modal.scss
new file mode 100644
index 000000000..299ac8f5c
--- /dev/null
+++ b/app/scss/partials/_insights_promo_modal.scss
@@ -0,0 +1,106 @@
+.InsightsModal__content {
+ background-color: $alabaster;
+ position: relative;
+ width: 518px;
+ min-height: 437px;
+ padding-top: 21px;
+ color: $tundora;
+ border: 2px solid $dark-cyan-blue;
+ z-index: 10;
+}
+
+.InsightsModal__image {
+ height: 94px;
+ width: 177px;
+ margin-bottom: 16px;
+ background-image: url('/app/images/panel/insights-ribbon.svg');
+}
+
+.InsightsModal__header {
+ font-family: 'Roboto';
+ height: 27.1px;
+ font-size: 20px;
+ font-weight: 900;
+ line-height: 1.35;
+ color: $tundora;
+ margin-bottom: 8.9px;
+}
+
+.InsightsModal__description {
+ width: 372px;
+ height: 54.2px;
+ font-size: 18px;
+ font-weight: 500;
+ text-align: center;
+ margin-bottom: 12.8px;
+ font-family: 'Roboto';
+}
+
+.InsightsModal__features {
+ &:nth-child(odd) {
+ margin-left: 28px;
+ width: 260px;
+ }
+ &:nth-child(even) {
+ width: 229.8px;
+ }
+}
+
+.InsightsModal__feature-text {
+ font-family: 'Roboto';
+ font-size: 14px;
+ line-height: 39px;
+ color: $medium-gray;
+}
+
+.InsightsModal__checked-circle-icon {
+ height: 18px;
+ width: 18px;
+ margin-right: 8px;
+ background-image: url('/app/images/panel/checked-circle-icon.svg');
+}
+
+.InsightsModal__call-to-action-container {
+ height: 107px;
+ width: 506px;
+ margin-top: 10px;
+ background-color: $mystic;
+}
+
+.InsightsModal__call-to-action {
+ display: flex;
+ justify-content: center;
+ width: 176px;
+ height: 36px;
+ margin-top: 18px;
+ border-radius: 2px;
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.24), 0 0 2px 0 rgba(0, 0, 0, 0.12);
+ background-image: linear-gradient(101deg, #070e18, #1678a0);
+ font-size: 14px;
+ font-family: 'Roboto Condensed';
+ letter-spacing: .5px;
+ color: $white;
+ line-height: 36px;
+ &:hover {
+ background-image: linear-gradient(101deg, #000004, #02648C);
+ color: $white;
+ }
+}
+
+.InsightsModal__link {
+ font-family: 'Roboto';
+ font-size: 15px;
+ color: $tundora;
+ &:hover {
+ cursor: pointer;
+ color: #090909;
+ }
+}
+
+.InsightsModal__other-options-container {
+ margin-top: 23px;
+ padding: 0 10.5px;
+ text-decoration: underline;
+ font-size: 15px;
+ color: $tundora;
+}
diff --git a/app/scss/partials/_modal_exit_button.scss b/app/scss/partials/_modal_exit_button.scss
new file mode 100644
index 000000000..955fdfaa1
--- /dev/null
+++ b/app/scss/partials/_modal_exit_button.scss
@@ -0,0 +1,37 @@
+/**
+ * Exit Button Sass
+ *
+ * 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
+ */
+
+// Exit Button
+.ModalExitButton__exit {
+ position: absolute;
+ top: -10px;
+ right: -10px;
+ width: 26px;
+ height: 26px;
+ border-radius: 15px;
+ border: solid 0.8px #325e97;
+ background-color: #f7f7f7;
+ @include transition(background-color 0.2s);
+}
+.ModalExitButton__exit:hover {
+ background-color: #efefef;
+ cursor: pointer;
+}
+.ModalExitButton__exitIcon {
+ height: 11px;
+ width: 11px;
+ margin: 0 auto;
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-image: buildIconX(#4a4a4a);
+}
diff --git a/app/shared-components/PlusPromoModal/PlusPromoModal.jsx b/app/shared-components/PlusPromoModal/PlusPromoModal.jsx
new file mode 100644
index 000000000..acb61ca8e
--- /dev/null
+++ b/app/shared-components/PlusPromoModal/PlusPromoModal.jsx
@@ -0,0 +1,146 @@
+/**
+ * Plus Promo Modal Component
+ * renders Plus Promo inside of the shared Modal component
+ *
+ * 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 React from 'react';
+import PropTypes from 'prop-types';
+import ClassNames from 'classnames';
+import globals from '../../../src/classes/Globals';
+import Modal from '../Modal/Modal';
+
+const DOMAIN = globals.DEBUG ? 'ghosterystage' : 'ghostery';
+
+function _renderInitialVersion(props) {
+ const { show, location, clickHandler } = props;
+
+ const isInHub = location === 'hub';
+
+ const locationClassName = {
+ 'in-hub': isInHub,
+ 'in-panel': location === 'panel'
+ };
+ const contentClassNames = ClassNames(
+ 'PlusPromoModal__content',
+ 'flex-container',
+ 'flex-dir-column',
+ 'align-middle',
+ 'initial',
+ locationClassName
+ );
+ const optionsContainerClassNames = ClassNames(
+ 'PlusPromoModal__options-container',
+ 'full-width',
+ locationClassName
+ );
+ const chooseYourPlanClassNames = ClassNames(
+ 'PlusPromoModal__choose-your-plan',
+ locationClassName
+ );
+ const recommendedBannerClassNames = ClassNames(
+ 'PlusPromoModal__recommended-banner',
+ locationClassName
+ );
+ const optionDescriptionBoxClassNames = ClassNames(
+ 'PlusPromoModal__option-description-box',
+ locationClassName
+ );
+
+ // TODO refactor for clarity & concision alongside implementing _renderUpgradeVersion for GH-1813
+ return (
+
+
+
+ {isInHub && (
+
+ {t('thanks_for_downloading_ghostery')}
+
+ )}
+
+ {isInHub ? t('choose_your_privacy_plan') : t('choose_your_ghostery_privacy_plan')}
+
+
+
+
+
{t('ghostery_basic')}
+
+ {t('locale_appropriate_currency_icon')}
+ 0
+
+ {t('per_month')}
+
+
+
{t('protection_for_this_browser')}
+
{t('blocks_ads')}
+
{t('blocks_trackers')}
+
{t('fast_browsing')}
+
+
+
+ {t('select_basic')}
+
+
+
+
+
+

+
{t('recommended')}
+
+
{t('ghostery_plus')}
+
+ {t('locale_appropriate_currency_icon')}
+ {t('plus_monthly_subscription_price_number')}
+
+ {t('per month')}
+
+
+
{t('all_basic_features_plus_COLON')}
+
+

+
{t('historical_tracker_stats')}
+
+
+

+
{t('priority_support')}
+
+
+

+
{t('new_color_themes')}
+
+
+
+
+ {t('select_plus')}
+
+
+
+
+
+ );
+}
+
+/**
+ * A Functional React component for a Plus Promo Modal
+ * @return {JSX} JSX for rendering a Plus Promo Modal
+ * @memberof SharedComponents
+ */
+const PlusPromoModal = props => _renderInitialVersion(props);
+
+// PropTypes ensure we pass required props of the correct type
+PlusPromoModal.propTypes = {
+ show: PropTypes.bool.isRequired,
+ location: PropTypes.string.isRequired,
+ handleSelectBasicClick: PropTypes.func.isRequired,
+ handleSelectPlusClick: PropTypes.func.isRequired,
+};
+
+export default PlusPromoModal;
diff --git a/app/shared-components/PlusPromoModal/PlusPromoModal.scss b/app/shared-components/PlusPromoModal/PlusPromoModal.scss
new file mode 100644
index 000000000..100160bdb
--- /dev/null
+++ b/app/shared-components/PlusPromoModal/PlusPromoModal.scss
@@ -0,0 +1,294 @@
+/**
+ * Plus Promo Modal Sass
+ *
+ * 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
+ */
+
+// Plus Promo Modal
+$standard-font-family: Roboto, "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+
+.PlusPromoModal__gold-ghostie-badge {
+ margin-top: 21px;
+ margin-bottom: 16px;
+}
+
+.PlusPromoModal__header {
+ margin-bottom: 10px;
+ font-size: 20px;
+ font-weight: bold;
+ font-family: $standard-font-family;
+}
+
+.PlusPromoModal__description {
+ margin-bottom: 5px;
+ width: 350px;
+ text-align: center;
+ font-size: 18px;
+ font-weight: 500;
+ font-family: $standard-font-family
+}
+
+.PlusPromoModal__content {
+ position: relative;
+ background-color: #f7f7f7;
+ border: 1.9px solid #930194;
+ z-index: 10;
+
+ &.initial {
+ &.in-hub {
+ width: 646px;
+ height: 553px;
+ }
+
+ &.in-panel {
+ width: 556px;
+ height: 471px;
+ }
+ }
+
+ &.upgrade {
+ width: 434px;
+ height: 410px;
+ }
+}
+
+.PlusPromoModal__buttons-background {
+ background-color: #e7ecee;
+ position: absolute;
+ bottom: 3px;
+ width: 99%;
+ height: 72px;
+ z-index: -1;
+
+ &.initial { height: 72px; }
+ &.upgrade { height: 107px; }
+}
+
+.PlusPromoModal__thanks-for-download {
+ padding-top: 30px;
+ font-size: 26px;
+ font-weight: bold;
+}
+
+.PlusPromoModal__choose-your-plan {
+ font-size: 18px;
+ font-weight: bold;
+
+ &.in-hub { padding-top: 10px; }
+ &.in-panel { padding-top: 17px; }
+}
+
+.PlusPromoModal__options-container {
+ height: 100%;
+ margin-top: 44px;
+ display: flex;
+
+ &.in-hub { justify-content: space-evenly; }
+ &.in-panel { justify-content: space-around; }
+}
+
+.PlusPromoModal__option-container {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+}
+
+.PlusPromoModal__option-description-box {
+ border-style: solid;
+ border-width: 3px;
+ background-color: #FFFFFF;
+
+ &.basic {
+ border-color: #1dafed;
+ }
+
+ &.plus {
+ position: relative; // so that the recommended banner is positioned relative to this element
+ border-image-source: linear-gradient(39deg, #f2daa2, #eab968);
+ border-image-slice: 1;
+ }
+
+ &.in-hub {
+ margin-bottom: 45px;
+ width: 240px;
+ height: 298px;
+ }
+
+ &.in-panel {
+ margin-bottom: 30px;
+ width: 221px;
+ height: 294px;
+ }
+}
+
+.PlusPromoModal__recommended-banner {
+ position: absolute;
+
+ &.in-hub {
+ left: -30px;
+ top: -30px;
+ }
+
+ &.in-panel {
+ left: -10px;
+ top: -32px;
+ }
+}
+
+.PlusPromoModal__recommended-banner-text {
+ position: relative;
+ left: 18px;
+ top: -47px;
+ transform: rotate(-15deg);
+ color: white;
+ font-size: 16px;
+ font-weight: bold;
+}
+
+.PlusPromoModal__option-header {
+ margin-top: 20px;
+ font-size: 19px;
+ font-weight: bold;
+ letter-spacing: -0.5px;
+ text-align: center;
+
+ &.basic { color: #1dafed; }
+ &.plus { color: #ebbf73; }
+}
+
+.PlusPromoModal__price-text {
+ line-height: 1.3;
+ text-align: center;
+
+ &.basic { color: #1dafed; }
+ &.plus { color: #ebbf73; }
+}
+
+.PlusPromoModal__currency-sign {
+ font-size: 30px;
+ font-weight: bold;
+}
+
+.PlusPromoModal__amount {
+ vertical-align: middle;
+ font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 58px;
+}
+
+.PlusPromoModal__per-month {
+ vertical-align: sub;
+ font-size: 18px;
+ font-weight: bold;
+}
+
+.PlusPromoModal__option-description-item {
+ padding-bottom: 15px;
+ font-size: 16px;
+ text-align: center;
+ color: #333333;
+
+ &.italic {
+ font-style: italic;
+ }
+}
+
+.PlusPromoModal__check-icon {
+ padding-right: 5px;
+ margin-top: -18px;
+}
+
+.PlusPromoModal__plus-option-description-item-container {
+ display: flex;
+ justify-content: center;
+}
+
+.PlusPromoModal__button-container {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ position: absolute;
+ bottom: 50px;
+}
+
+.PlusPromoModal__button {
+ border-radius: 3px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-weight: bold;
+ font-family: $standard-font-family;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ cursor: pointer;
+ transition: background-color 0.25s ease-out, color 0.25s ease-out;
+ -webkit-appearance: none;
+
+ &.basic {
+ font-size: 11px;
+ width: 135px;
+ height: 40px;
+ border: solid 2px #15b4f2;
+ background-color: white;
+ color: #2cbcf4;
+ box-shadow: none;
+ }
+ &.basic:hover {
+ background-color: #2cbcf4;
+ color: white;
+ }
+
+ &.plus {
+ font-size: 11px;
+ width: 163px;
+ height: 38px;
+ border: none;
+ background-image: linear-gradient(to bottom, #2fdbfa, #15b4f2);
+ color: white;
+ box-shadow: none;
+ }
+ &.plus:hover {
+ background-image: linear-gradient(to bottom, #1fcbea, #05a4e2);
+ }
+
+ &.upgrade {
+ font-size: 13px;
+ height: 36px;
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.24), 0 0 2px 0 rgba(0, 0, 0, 0.12);
+ background-color: #1dafed;
+ color: white;
+ }
+ &.upgrade:hover {
+ background-color: #0698d6;
+ }
+
+ .button-text {
+ padding: 0px 20px 0px;
+ color: white;
+ text-decoration: none;
+ }
+}
+
+.PlusPromoModal__text-link-container {
+ position: absolute;
+ bottom: 10px;
+ width: 100%;
+ display: flex;
+ justify-content: space-evenly;
+}
+
+.PlusPromoModal__text-link {
+ margin-left: 10px;
+ margin-right: 10px;
+ font-size: 15px;
+ font-family: $standard-font-family;
+ color: #4a4a4a;
+ text-decoration: underline;
+ cursor: pointer;
+}
diff --git a/app/shared-components/PlusPromoModal/index.js b/app/shared-components/PlusPromoModal/index.js
new file mode 100644
index 000000000..da26a8b7e
--- /dev/null
+++ b/app/shared-components/PlusPromoModal/index.js
@@ -0,0 +1,16 @@
+/**
+ * Point of entry index.js file for Plus Promo Modal Component
+ *
+ * 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 PlusPromoModal from './PlusPromoModal';
+
+export default PlusPromoModal;
diff --git a/app/shared-components/index.js b/app/shared-components/index.js
index 7910b2ef5..a7fe2f139 100644
--- a/app/shared-components/index.js
+++ b/app/shared-components/index.js
@@ -17,6 +17,7 @@
import ExitButton from './ExitButton';
import Modal from './Modal';
+import PlusPromoModal from './PlusPromoModal';
import SteppedNavigation from './SteppedNavigation';
import ToastMessage from './ToastMessage';
import ToggleCheckbox from './ToggleCheckbox';
@@ -25,6 +26,7 @@ import ToggleSwitch from './ToggleSwitch';
export {
ExitButton,
Modal,
+ PlusPromoModal,
SteppedNavigation,
ToastMessage,
ToggleCheckbox,
diff --git a/src/background.js b/src/background.js
index de12238b3..6541673a3 100644
--- a/src/background.js
+++ b/src/background.js
@@ -42,6 +42,7 @@ import metrics from './classes/Metrics';
import rewards from './classes/Rewards';
import account from './classes/Account';
import GhosteryModule from './classes/Module';
+import promoModals from './classes/PromoModals';
// utilities
import { allowAllwaysC2P } from './utils/click2play';
@@ -541,6 +542,9 @@ function handleRewards(name, message, callback) {
*/
function handleGhosteryHub(name, message, callback) {
switch (name) {
+ case 'SET_PLUS_PROMO_MODAL_SEEN':
+ promoModals.recordPlusPromoSighting();
+ break;
case 'SEND_PING': {
const { type } = message;
metrics.ping(type);
@@ -1074,6 +1078,18 @@ function onMessageHandler(request, sender, callback) {
});
return true;
}
+ if (name === 'promoModals.sawPlusPromo') {
+ promoModals.recordPlusPromoSighting();
+ return false;
+ }
+ if (name === 'promoModals.sawInsightsPromo') {
+ promoModals.recordInsightsPromoSighting();
+ return false;
+ }
+ if (name === 'promoModals.turnOffPromos') {
+ promoModals.turnOffPromos();
+ return false;
+ }
}
/**
diff --git a/src/classes/ConfData.js b/src/classes/ConfData.js
index 121c77ef2..01678777f 100644
--- a/src/classes/ConfData.js
+++ b/src/classes/ConfData.js
@@ -115,14 +115,17 @@ class ConfData {
_initProperty('hide_alert_trusted', false);
_initProperty('ignore_first_party', true);
_initProperty('import_callout_dismissed', true);
+ _initProperty('insights_promo_modal_last_seen', 0);
_initProperty('install_random_number', 0);
_initProperty('install_date', 0);
_initProperty('is_expanded', false);
_initProperty('is_expert', false);
_initProperty('last_cmp_date', 0);
_initProperty('notify_library_updates', false);
+ _initProperty('notify_promotions', true);
_initProperty('notify_upgrade_updates', true);
_initProperty('paid_subscription', false);
+ _initProperty('plus_promo_modal_last_seen', 0);
_initProperty('rewards_accepted', false);
_initProperty('rewards_opted_in', false);
_initProperty('settings_last_imported', 0);
diff --git a/src/classes/Globals.js b/src/classes/Globals.js
index ed481d1bd..900874ff8 100644
--- a/src/classes/Globals.js
+++ b/src/classes/Globals.js
@@ -114,6 +114,7 @@ class Globals {
'is_expanded',
'is_expert',
'notify_library_updates',
+ 'notify_promotions',
'notify_upgrade_updates',
'reload_banner_status',
'selected_app_ids',
diff --git a/src/classes/Metrics.js b/src/classes/Metrics.js
index 145e9239e..71864c1d7 100644
--- a/src/classes/Metrics.js
+++ b/src/classes/Metrics.js
@@ -748,16 +748,24 @@ class Metrics {
*/
_recordEngaged() {
const engaged_daily_velocity = conf.metrics.engaged_daily_velocity || [];
- const today = Math.floor(Number(new Date().getTime()) / 86400000);
+ const engaged_daily_count = conf.metrics.engaged_daily_count || new Array(engaged_daily_velocity.length).fill(0);
+
+ const today = Math.floor(Number(new Date().getTime()) / 86400000); // Today's time
+
engaged_daily_velocity.sort();
if (!engaged_daily_velocity.includes(today)) {
engaged_daily_velocity.push(today);
+ engaged_daily_count.push(1);
if (engaged_daily_velocity.length > 7) {
+ engaged_daily_count.shift();
engaged_daily_velocity.shift();
}
+ } else {
+ engaged_daily_count[engaged_daily_velocity.indexOf(today)]++;
}
- conf.metrics.engaged_daily_velocity = engaged_daily_velocity;
+ conf.metrics.engaged_daily_count = engaged_daily_count;
+ conf.metrics.engaged_daily_velocity = engaged_daily_velocity;
this._sendReq('engaged', ['daily', 'weekly', 'monthly']);
}
diff --git a/src/classes/PanelData.js b/src/classes/PanelData.js
index 006738f2e..4cc1772dc 100644
--- a/src/classes/PanelData.js
+++ b/src/classes/PanelData.js
@@ -27,6 +27,7 @@ import tabInfo from './TabInfo';
import rewards from './Rewards';
import account from './Account';
import dispatcher from './Dispatcher';
+import promoModals from './PromoModals';
import { getCliqzGhosteryBugs, sendCliqzModuleCounts } from '../utils/cliqzModulesData';
import { getActiveTab, flushChromeMemoryCache, processUrl } from '../utils/utils';
import { objectEntries, log } from '../utils/common';
@@ -365,6 +366,7 @@ class PanelData {
is_expert,
is_android: globals.BROWSER_INFO.os === 'android',
language,
+ promoModal: promoModals.whichPromoModalShouldWeDisplay(),
reload_banner_status,
tab_id,
trackers_banner_status,
@@ -507,7 +509,7 @@ class PanelData {
alert_bubble_pos, alert_bubble_timeout, block_by_default, enable_autoupdate,
enable_click2play, enable_click2play_social, enable_human_web, enable_offers,
enable_metrics, hide_alert_trusted, ignore_first_party, notify_library_updates,
- notify_upgrade_updates, selected_app_ids, show_alert, show_badge,
+ notify_promotions, notify_upgrade_updates, selected_app_ids, show_alert, show_badge,
show_cmp, show_tracker_urls, toggle_individual_trackers
} = userSettingsSource;
@@ -524,6 +526,7 @@ class PanelData {
hide_alert_trusted,
ignore_first_party,
notify_library_updates,
+ notify_promotions,
notify_upgrade_updates,
selected_app_ids,
show_alert,
diff --git a/src/classes/PromoModals.js b/src/classes/PromoModals.js
new file mode 100644
index 000000000..e569ec4ff
--- /dev/null
+++ b/src/classes/PromoModals.js
@@ -0,0 +1,97 @@
+/**
+ * PromoModals Class
+ *
+ * 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 conf from './Conf';
+import globals from './Globals';
+import panelData from './PanelData';
+
+const DAYS_BETWEEN_PROMOS = {
+ plus: globals.DEBUG ? 0.00025 : 30,
+ insights: globals.DEBUG ? 0.00025 : 30
+};
+const WEEKLY_INSIGHTS_TARGET = globals.DEBUG ? 1 : 3;
+const DAILY_INSIGHTS_TARGET = 3;
+
+const MSECS_IN_DAY = 86400000; // 1000 msecs-in-sec * 60 secs-in-min * 60 mins-in-hour * 24 hours-in-day
+const PLUS = 'plus';
+const PLUS_INITIAL = 'plus_initial';
+const PLUS_UPGRADE = 'plus_upgrade';
+const INSIGHTS = 'insights';
+const PROMO_MODAL_LAST_SEEN = 'promo_modal_last_seen';
+
+/**
+ * Static 'namespace' class for handling the business logic for the display of promo modals (Plus, Insights, etc...)
+ * @memberOf BackgroundClasses
+ */
+class PromoModals {
+ static whichPromoModalShouldWeDisplay() {
+ if (this._isTimeForAPromo(INSIGHTS)) return INSIGHTS;
+
+ if (this._isTimeForAPromo(PLUS)) {
+ if (this._haveSeenInitialPlusPromo()) return PLUS_UPGRADE;
+
+ return PLUS_INITIAL;
+ }
+
+ return null;
+ }
+
+ static recordPlusPromoSighting() { this._recordPromoSighting(PLUS); }
+
+ static recordInsightsPromoSighting() { this._recordPromoSighting(INSIGHTS); }
+
+ static turnOffPromos() { panelData.set({ notify_promotions: false }); }
+
+ static _haveSeenInitialPlusPromo() {
+ const lastSeenTime = conf[`${PLUS}_${PROMO_MODAL_LAST_SEEN}`];
+ return (lastSeenTime !== 0);
+ }
+
+ static _isTimeForAPromo(type) {
+ if (conf.notify_promotions === false) { return false; }
+
+ const lastSeenPlusPromo = conf[`${PLUS}_${PROMO_MODAL_LAST_SEEN}`];
+ const lastSeenInsightsPromo = conf[`${INSIGHTS}_${PROMO_MODAL_LAST_SEEN}`];
+ const lastSeenPromo = lastSeenPlusPromo > lastSeenInsightsPromo ? lastSeenPlusPromo : lastSeenInsightsPromo;
+
+ if (type === INSIGHTS && !this._hasEngagedFrequently()) {
+ return false;
+ }
+
+ return (
+ (Date.now() - lastSeenPromo) >
+ (MSECS_IN_DAY * DAYS_BETWEEN_PROMOS[type])
+ );
+ }
+
+ static _recordPromoSighting(type) {
+ conf[`${type}_${PROMO_MODAL_LAST_SEEN}`] = Date.now();
+ }
+
+ static _hasEngagedFrequently() {
+ const { engaged_daily_count } = conf.metrics || [];
+
+ let very_engaged_days = 0;
+ engaged_daily_count.forEach((count) => {
+ very_engaged_days = count >= DAILY_INSIGHTS_TARGET ? ++very_engaged_days : very_engaged_days;
+ });
+
+ if (very_engaged_days >= WEEKLY_INSIGHTS_TARGET) return true;
+
+ return false;
+ }
+}
+
+// the class is simply a namespace for some static methods,
+// as we do not need to maintain any state
+export default PromoModals;
diff --git a/tools/i18n-checker.js b/tools/i18n-checker.js
index dbf91e0af..0f5d96f36 100644
--- a/tools/i18n-checker.js
+++ b/tools/i18n-checker.js
@@ -24,7 +24,7 @@ const oboe = require('oboe');
const LOCALES_FOLDER = './_locales';
const GATHER_FILE_PATHS_EXCEPTIONS = ['.DS_Store'];
const LANG_FILES_COUNT = 14;
-const DEFAULT_LOCALE_PATH = '../_locales/en/messages.json';
+const DEFAULT_LOCALE_PATH = './_locales/en/messages.json';
const DUPLICATE_TOKENS_FILE = './tools/i18n_results/duplicate_tokens.txt';
const MISSING_TOKENS_FILE = './tools/i18n_results/missing_tokens.txt';
const EXTRA_TOKENS_FILE = './tools/i18n_results/extra_tokens.txt';
@@ -175,7 +175,7 @@ function findMissingKeys(paths) {
let hasMissingKeys = false;
const missingKeys = {};
paths.forEach((path) => {
- const localeJson = jsonfile.readFileSync(`.${path}`);
+ const localeJson = jsonfile.readFileSync(`${path}`);
const locale = path.match(/_locales\/(.*)\/messages.json/)[1];
missingKeys[locale] = [];
Object.keys(defaultLocaleJson).forEach((key) => {
@@ -210,7 +210,7 @@ function findExtraKeys(paths) {
let hasExtraKeys = false;
const extraKeys = {};
paths.forEach((path) => {
- const localeJson = jsonfile.readFileSync(`.${path}`);
+ const localeJson = jsonfile.readFileSync(`${path}`);
const locale = path.match(/_locales\/(.*)\/messages.json/)[1];
extraKeys[locale] = [];
Object.keys(localeJson).forEach((key) => {
@@ -243,7 +243,7 @@ function findMalformedKeys(paths) {
let hasMalformedKeys = false;
const malformedKeys = {};
paths.forEach((path) => {
- const localeJson = jsonfile.readFileSync(`.${path}`);
+ const localeJson = jsonfile.readFileSync(`${path}`);
const locale = path.match(/_locales\/(.*)\/messages.json/)[1];
malformedKeys[locale] = [];
Object.keys(localeJson).forEach((key) => {
@@ -278,7 +278,7 @@ function findMissingPlaceholders(paths) {
let hasMissingPlaceholders = false;
const missingPlaceholders = {};
paths.forEach((path) => {
- const localeJson = jsonfile.readFileSync(`.${path}`);
+ const localeJson = jsonfile.readFileSync(`${path}`);
const locale = path.match(/_locales\/(.*)\/messages.json/)[1];
missingPlaceholders[locale] = [];
Object.keys(defaultLocaleJson).forEach((key) => {
@@ -322,7 +322,7 @@ function findExtraPlaceholders(paths) {
let hasExtraPlaceholders = false;
const extraPlaceholders = {};
paths.forEach((path) => {
- const localeJson = jsonfile.readFileSync(`.${path}`);
+ const localeJson = jsonfile.readFileSync(`${path}`);
const locale = path.match(/_locales\/(.*)\/messages.json/)[1];
extraPlaceholders[locale] = [];
Object.keys(localeJson).forEach((key) => {
@@ -364,7 +364,7 @@ function findMalformedPlaceholders(paths) {
let hasMalformedPlaceholders = false;
const malformedPlaceholders = [];
paths.forEach((path) => {
- const localeJson = jsonfile.readFileSync(`.${path}`);
+ const localeJson = jsonfile.readFileSync(`${path}`);
const locale = path.match(/_locales\/(.*)\/messages.json/)[1];
malformedPlaceholders[locale] = [];
Object.keys(localeJson).forEach((key) => {