From 834bb52098eacb14efe0bd713be10cbbdc5d4a4c Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 30 Nov 2020 22:49:14 -0500 Subject: [PATCH 01/35] Make form --- _locales/en/messages.json | 18 ++ .../BrowserCreateAccountView.jsx | 243 ++++++++++++++++++ .../BrowserCreateAccountView.scss | 144 +++++++++++ .../Views/BrowserCreateAccountView/index.js | 3 + .../CreateAccountView/CreateAccountView.jsx | 5 +- app/hub/index.jsx | 3 +- app/scss/hub.scss | 1 + 7 files changed, 414 insertions(+), 3 deletions(-) create mode 100644 app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx create mode 100644 app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss create mode 100644 app/hub/Views/BrowserCreateAccountView/index.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 041d0b141..4d04b74a1 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1734,6 +1734,21 @@ "hub_create_account_toast_error": { "message": "That email address is already in use. Please choose another." }, + "hub_browser_create_a_ghostery_account": { + "message": "Create a Ghostery Account" + }, + "hub_browser_sync_settings": { + "message": "Allows you to sync settings across browsers and devices" + }, + "hub_browser_already_have_account": { + "message": "I already have an account." + }, + "hub_browser_send_me": { + "message": "Send me" + }, + "hub_browser_updates_and_promotions": { + "message": "updates & promotions." + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, @@ -2054,6 +2069,9 @@ "password_colon": { "message": "Password:" }, + "confirm_password_colon": { + "message": "Password:" + }, "please_enter_a_valid_email": { "message": "Please enter a valid email." }, diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx new file mode 100644 index 000000000..b25d111d3 --- /dev/null +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -0,0 +1,243 @@ +/** + * Browser Create Account View + * + * 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 { NavLink } from 'react-router-dom'; +import { ToggleCheckbox } from '../../../shared-components'; + +const promoString = `${t('hub_browser_send_me')} Ghostery ${t('hub_browser_updates_and_promotions')}`; +/** + * A Functional React component for rendering the Browser Create Account View + * @return {JSX} JSX for rendering the Browser Create Account View of the Hub app + * @memberof HubComponents + */ +const BrowserCreateAccountView = (props) => { + const { + email, + emailError, + confirmEmail, + confirmEmailError, + firstName, + lastName, + password, + confirmPassword, + passwordInvalidError, + passwordLengthError, + isUpdatesChecked, + isUpdatesNotCheckedError, + handleInputChange, + handleUpdatesCheckboxChange, + handleSubmit, + } = props; + + const emailInputClassNames = ClassNames('BrowserCreateAccountView__inputBox', { + error: emailError, + }); + const confirmInputClassNames = ClassNames('BrowserCreateAccountView__inputBox', { + error: confirmEmailError, + }); + const updatesCheckboxInputLabelClassNames = ClassNames('BrowserCreateAccountView__inputLabel clickable', { + error: isUpdatesNotCheckedError, + }); + const passwordInputClassNames = ClassNames('BrowserCreateAccountView__inputBox', { + error: passwordInvalidError || passwordLengthError, + }); + + return ( +
+
{ t('hub_browser_create_a_ghostery_account') }
+
{ t('hub_browser_sync_settings') }
+
+ {/* add onclick to sign in page */} +
{t('hub_browser_already_have_account')}
+
+
+
+
+
+ + + {emailError && ( +
+ {t('please_enter_a_valid_email')} +
+ )} +
+
+ + + {confirmEmailError && ( +
+ {t('your_email_do_not_match')} +
+ )} +
+
+
+
+ + +
+
+ + +
+
+
+
+ + + {passwordInvalidError && ( +
+ {t('hub_create_account_label_password_invalid')} +
+ )} + {passwordLengthError && ( +
+ {t('hub_create_account_label_password_invalid_length')} +
+ )} +
+
+ + + {passwordInvalidError && ( +
+ {t('hub_create_account_label_password_invalid')} +
+ )} + {passwordLengthError && ( +
+ {t('hub_create_account_label_password_invalid_length')} +
+ )} +
+
+
+
+
+ + +
+
+
+
+
+
+ +
+
+ +
+ ); +}; + +// PropTypes ensure we pass required props of the correct type +BrowserCreateAccountView.propTypes = { + email: PropTypes.string.isRequired, + emailError: PropTypes.bool.isRequired, + confirmEmail: PropTypes.string.isRequired, + confirmEmailError: PropTypes.bool.isRequired, + firstName: PropTypes.string.isRequired, + lastName: PropTypes.string.isRequired, + isUpdatesChecked: PropTypes.bool.isRequired, + isUpdatesNotCheckedError: PropTypes.bool.isRequired, + password: PropTypes.string.isRequired, + confirmPassword: PropTypes.string.isRequired, + passwordInvalidError: PropTypes.bool.isRequired, + passwordLengthError: PropTypes.bool.isRequired, + handleInputChange: PropTypes.func.isRequired, + handleUpdatesCheckboxChange: PropTypes.func.isRequired, + handleSubmit: PropTypes.func.isRequired, +}; + +export default BrowserCreateAccountView; diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss new file mode 100644 index 000000000..a50f8bdc7 --- /dev/null +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -0,0 +1,144 @@ +/** + * Browser Create Account View 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 + */ + +$color-create-account-form-error-red: #e74055; + +// Browser Create Account View +.BrowserCreateAccountView__title { + display: flex; + justify-content: center; + font-size: 24px; + font-weight: 600; +} +.BrowserCreateAccountView__subtitle { + margin-top: 10px; + display: flex; + justify-content: center; + font-size: 18px; +} +.BrowserCreateAccountView__alreadyHaveAccount { + margin-top: 38px; + color: $ghosty-blue; + text-decoration: underline; + cursor: pointer; +} +.BrowserCreateAccountView { + padding-top: 80px; + padding-bottom: 40px; +} +.BrowserCreateAccountView--addPaddingTop { + padding-top: 20px; +} +.BrowserCreateAccountView--addMarginSide { + margin-left: 10px; + margin-right: 10px; +} +.BrowserCreateAccountView--addMarginBottom { + margin-bottom: 20px; +} +.BrowserCreateAccountView__headerImage { + max-width: 180px; +} +.BrowserCreateAccountView__headerTitle h3 { + font-size: 24px; + line-height: 1.75; + color: #4a4a4a; + margin: 0 25px; +} +.BrowserCreateAccountView__inputLabel { + font-size: 14px; + font-weight: 500; + line-height: 2.86; + text-transform: uppercase; + color: #4a4a4a; +} +.BrowserCreateAccountView__inputBox { + font-size: 14; + line-height: 24px; + color: #4a4a4a; + + // Foundation Overrides + border-radius: 6px; + box-shadow: none; + border: 1px solid #9b9b9b; + + &::placeholder { + color: #c4ced1; + } +} +.BrowserCreateAccountView__inputBox.error { + margin-bottom: 8px; + border-color: $color-create-account-form-error-red; +} +.BrowserCreateAccountView__inputBox:focus { + // Foundation Overrides + box-shadow: none; + border-color: $color-create-account-form-error-red; +} +.BrowserCreateAccountView__inputError { + font-size: 12; + line-height: 14px; + color: $color-create-account-form-error-red; + margin-bottom: 13px; +} +.BrowserCreateAccountView__promoString { + margin-top: 15px; +} +.BrowserCreateAccountView__link { + font-size: 14px; + line-height: 30px; +} +.BrowserCreateAccountView__termsStatement { + font-size: 12px; +} +.BrowserCreateAccountView__button { + min-width: 180px; +} +.BrowserCreateAccountView__inputLabel { + flex-grow: 1; // ensure left-justify alignment in single column layout + padding-top: 10px; // align with checkbox top +} +.BrowserCreateAccountView__inputLabel.error{ + color: $color-create-account-form-error-red; +} +@media only screen and (max-width: 740px) { + .BrowserCreateAccountView { + padding-top: 20px; + } + .BrowserCreateAccountView__header { + flex-direction: column; + } + .BrowserCreateAccountView__headerTitle { + padding-top: 30px; + text-align: center; + } + .BrowserCreateAccountView__submit { + display: flex; + justify-content: center; + } + .BrowserCreateAccountView__checkboxContainer { + display: flex; + align-items: center; + padding-right: 12px; + justify-content: center; + } + .BrowserCreateAccountView__linkContainer { + text-align: center; + } +} +@media only screen and (max-width: 500px) { + .BrowserCreateAccountView__headerTitle h3 { + font-size: 20px; + margin: 0 10px; + } +} diff --git a/app/hub/Views/BrowserCreateAccountView/index.js b/app/hub/Views/BrowserCreateAccountView/index.js new file mode 100644 index 000000000..ea8b89431 --- /dev/null +++ b/app/hub/Views/BrowserCreateAccountView/index.js @@ -0,0 +1,3 @@ +import BrowserCreateAccountView from './BrowserCreateAccountView'; + +export default BrowserCreateAccountView; diff --git a/app/hub/Views/CreateAccountView/CreateAccountView.jsx b/app/hub/Views/CreateAccountView/CreateAccountView.jsx index 7804b0c62..31f18084e 100644 --- a/app/hub/Views/CreateAccountView/CreateAccountView.jsx +++ b/app/hub/Views/CreateAccountView/CreateAccountView.jsx @@ -17,6 +17,7 @@ import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; import { ToggleCheckbox } from '../../../shared-components'; + /** * A Functional React component for rendering the Create Account View * @return {JSX} JSX for rendering the Create Account View of the Hub app @@ -145,7 +146,7 @@ const CreateAccountView = (props) => {
{
diff --git a/app/hub/index.jsx b/app/hub/index.jsx index 7e3a19a3c..c611efd32 100644 --- a/app/hub/index.jsx +++ b/app/hub/index.jsx @@ -31,6 +31,7 @@ import CreateAccountView from './Views/CreateAccountView'; import ForgotPasswordView from '../shared-components/ForgotPassword/ForgotPasswordContainer'; import LogInView from './Views/LogInView'; import UpgradePlanView from './Views/UpgradePlanView'; +import BrowserCreateAccountView from './Views/BrowserCreateAccountView'; const store = createStore(); @@ -43,7 +44,7 @@ const ah = (QueryString.parse(window.location.search).ah === 'true') || false; */ const Hub = () => ( - + diff --git a/app/scss/hub.scss b/app/scss/hub.scss index 759692615..816dcf162 100644 --- a/app/scss/hub.scss +++ b/app/scss/hub.scss @@ -86,6 +86,7 @@ html, body, #root { @import '../hub/Views/LogInView/LogInView.scss'; @import '../hub/Views/CreateAccountView/CreateAccountView.scss'; @import '../hub/Views/UpgradePlanView/UpgradePlanView.scss'; +@import '../hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss'; // Imports from ../shared-components directory @import '../shared-components/ExitButton/ExitButton.scss'; From 3300d83707d972aea900deae4d19f4d882b98ac5 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 30 Nov 2020 23:30:59 -0500 Subject: [PATCH 02/35] Add skip and learn more links --- _locales/en/messages.json | 6 +++ .../BrowserCreateAccountView.jsx | 22 +++++--- .../BrowserCreateAccountView.scss | 51 +++++++++++++++++++ .../CreateAccountView/CreateAccountView.jsx | 5 +- 4 files changed, 73 insertions(+), 11 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 4d04b74a1..51c92dac1 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1749,6 +1749,12 @@ "hub_browser_updates_and_promotions": { "message": "updates & promotions." }, + "hub_browser_skip": { + "message": "Skip" + }, + "hub_browser_we_take_your_privacy_very_seriously": { + "message": "We take your privacy very seriously. Learn more" + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index b25d111d3..13caf9c95 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -18,6 +18,7 @@ import { NavLink } from 'react-router-dom'; import { ToggleCheckbox } from '../../../shared-components'; const promoString = `${t('hub_browser_send_me')} Ghostery ${t('hub_browser_updates_and_promotions')}`; + /** * A Functional React component for rendering the Browser Create Account View * @return {JSX} JSX for rendering the Browser Create Account View of the Hub app @@ -48,7 +49,7 @@ const BrowserCreateAccountView = (props) => { const confirmInputClassNames = ClassNames('BrowserCreateAccountView__inputBox', { error: confirmEmailError, }); - const updatesCheckboxInputLabelClassNames = ClassNames('BrowserCreateAccountView__inputLabel clickable', { + const updatesCheckboxInputLabelClassNames = ClassNames('BrowserCreateAccountView__promoString clickable', { error: isUpdatesNotCheckedError, }); const passwordInputClassNames = ClassNames('BrowserCreateAccountView__inputBox', { @@ -168,7 +169,7 @@ const BrowserCreateAccountView = (props) => {
{ onChange={handleUpdatesCheckboxChange} /> @@ -209,13 +210,18 @@ const BrowserCreateAccountView = (props) => {
-
-
- +
+ +
+
+
+
+
{t('hub_browser_skip')}
+
+
{t('hub_browser_we_take_your_privacy_very_seriously')}
+
); diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index a50f8bdc7..c73e48134 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -111,6 +111,57 @@ $color-create-account-form-error-red: #e74055; .BrowserCreateAccountView__inputLabel.error{ color: $color-create-account-form-error-red; } +.BrowserCreateAccountView__ctaButtonContainer { + display: flex; + justify-content: center; + + .BrowserCreateAccountView__ctaButton { + margin: 48px auto 0 auto; + height: 44px; + width: 162px; + padding: 7.7px 14px; + line-height: 22px; + background: linear-gradient( + 45deg, + #ff7e74 50%, + #00aef0 + ); + background-size: 200% 100%; + background-position: 100% 50%; + transition: 0.25s all; + border: none; + &:hover { + background-position: 0% 50%; + transition: 0.25s all; + } + color: #FFF; + font-size: 14.1px; + font-weight: 700; + border-radius: 3.5px; + text-align: center; + line-height: 2.05; + cursor: pointer; + } +} +.BrowserCreateAccountView__skip { + margin-top: -37px; + float: right; + font-size: 16px; + color: $ghosty-blue; + text-decoration: underline; + cursor: pointer; +} +.BrowserCreateAccountView__learnMoreContainer { + margin: 25px auto 0 auto; + width: 251px; + text-align: center; +} +.BrowserCreateAccountView__learnMore { + font-size: 16px; + color: $ghosty-blue; + text-decoration: underline; + cursor: pointer; +} @media only screen and (max-width: 740px) { .BrowserCreateAccountView { padding-top: 20px; diff --git a/app/hub/Views/CreateAccountView/CreateAccountView.jsx b/app/hub/Views/CreateAccountView/CreateAccountView.jsx index 31f18084e..7804b0c62 100644 --- a/app/hub/Views/CreateAccountView/CreateAccountView.jsx +++ b/app/hub/Views/CreateAccountView/CreateAccountView.jsx @@ -17,7 +17,6 @@ import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; import { ToggleCheckbox } from '../../../shared-components'; - /** * A Functional React component for rendering the Create Account View * @return {JSX} JSX for rendering the Create Account View of the Hub app @@ -146,7 +145,7 @@ const CreateAccountView = (props) => {
{
From 5911f470ed352a76fb5e1c9a87544649587acda7 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 30 Nov 2020 23:49:01 -0500 Subject: [PATCH 03/35] Set arrow up/down depending on expanded state --- .../BrowserCreateAccountView.jsx | 26 +++++++++++++++++-- .../BrowserCreateAccountView.scss | 15 +++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 13caf9c95..c5179e6f1 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -11,7 +11,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -import React from 'react'; +import React, { useRef, useState } from 'react'; import PropTypes from 'prop-types'; import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; @@ -56,6 +56,24 @@ const BrowserCreateAccountView = (props) => { error: passwordInvalidError || passwordLengthError, }); + const FAQRef = useRef(null); + const scrollToFAQ = () => { + FAQRef.current.scrollIntoView({ behavior: 'smooth' }); + }; + + const [expanded, setExpanded] = useState(false); + + const arrowClassNames = ClassNames('BrowserCreateAccountView__arrow', { + up: expanded, + down: !expanded, + error: passwordInvalidError || passwordLengthError, + }); + + const handleArrowClick = () => { + scrollToFAQ(); + setExpanded(!expanded); + }; + return (
{ t('hub_browser_create_a_ghostery_account') }
@@ -219,9 +237,13 @@ const BrowserCreateAccountView = (props) => {
{t('hub_browser_skip')}
-
+
{t('hub_browser_we_take_your_privacy_very_seriously')}
+
+
+ {/* map here */} +
); diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index c73e48134..aa2bf3c00 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -162,6 +162,21 @@ $color-create-account-form-error-red: #e74055; text-decoration: underline; cursor: pointer; } +.BrowserCreateAccountView__arrow { + margin: 15px auto 0 auto; + height: 12px; + width: 12px; + border-left: 2px solid #00aef0; + border-top: 2px solid #00aef0; + cursor: pointer; + + &.up { + transform: rotate(45deg); + } + &.down { + transform: rotate(225deg); + } +} @media only screen and (max-width: 740px) { .BrowserCreateAccountView { padding-top: 20px; From a56094f81ed18a3204b48db1f465bdc0b55d3ba5 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 00:46:13 -0500 Subject: [PATCH 04/35] Make FAQ --- _locales/en/messages.json | 33 +++++++++++ .../BrowserCreateAccountView.jsx | 56 ++++++++++++++++--- .../BrowserCreateAccountView.scss | 29 ++++++++++ .../ghosty-box.svg | 1 + .../ghosty-letter.svg | 1 + .../ghosty-lock.svg | 1 + .../ghosty-shield-letter.svg | 1 + .../ghosty-shield.svg | 1 + 8 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 app/images/hub/browser-create-account-view/ghosty-box.svg create mode 100644 app/images/hub/browser-create-account-view/ghosty-letter.svg create mode 100644 app/images/hub/browser-create-account-view/ghosty-lock.svg create mode 100644 app/images/hub/browser-create-account-view/ghosty-shield-letter.svg create mode 100644 app/images/hub/browser-create-account-view/ghosty-shield.svg diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 51c92dac1..1867170db 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1755,6 +1755,39 @@ "hub_browser_we_take_your_privacy_very_seriously": { "message": "We take your privacy very seriously. Learn more" }, + "hub_browser_private_by_design": { + "message": "Private by design" + }, + "hub_browser_private_by_design_description": { + "message": "Privacy is incredibly important to us at Ghostery and we've taken extra care to design our products that limits the amount of personal information collected." + }, + "hub_browser_why_do_you_need_my_email": { + "message": "Why do you need my email?" + }, + "hub_browser_why_do_you_need_my_email_description": { + "message": "We've found email is the simplest way to create and secure a unique account without sharing your information. It helps sync your custom settings across your devices." + }, + "hub_browser_what_do_you_use_my_email_for": { + "message": "What do you use my email for?" + }, + "hub_browser_what_do_you_use_my_email_for_description": { + "message": "We never share or sell your personal information. Your email address is used for account management, technical support, product-related communications, and some opt-in features." + }, + "hub_browser_how_secure_is_": { + "message": "How secure is" + }, + "hub_browser_how_secure_is_ghostery_description": { + "message": "We never share or sell your personal information. Your email address is used for account management, technical support, product-related communications, and some opt-in features." + }, + "hub_browser_can_i_remove_my_account": { + "message": "Can I remove my account?" + }, + "hub_browser_can_i_remove_my_account_description": { + "message": "We hope you enjoy using Ghostery, but if you do decide to leave we will remove all of your personal information within 90 days from the date of request." + }, + "hub_browser_visit_our_privacy_policy": { + "message": "Visit our Privacy Policy for more information" + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index c5179e6f1..64a85a17d 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -56,9 +56,9 @@ const BrowserCreateAccountView = (props) => { error: passwordInvalidError || passwordLengthError, }); - const FAQRef = useRef(null); + const faqRef = useRef(null); const scrollToFAQ = () => { - FAQRef.current.scrollIntoView({ behavior: 'smooth' }); + faqRef.current.scrollIntoView({ behavior: 'smooth' }); }; const [expanded, setExpanded] = useState(false); @@ -69,11 +69,49 @@ const BrowserCreateAccountView = (props) => { error: passwordInvalidError || passwordLengthError, }); - const handleArrowClick = () => { - scrollToFAQ(); + const handleFAQLearnMoreClick = () => { + setTimeout(scrollToFAQ, 1); setExpanded(!expanded); }; + const faqList = [ + { + icon: 'ghosty-shield.svg', + label: t('hub_browser_private_by_design'), + description: t('hub_browser_private_by_design_description'), + }, + { + icon: 'ghosty-letter.svg', + label: t('hub_browser_why_do_you_need_my_email'), + description: t('hub_browser_why_do_you_need_my_email_description'), + }, + { + icon: 'ghosty-shield-letter.svg', + label: t('hub_browser_what_do_you_use_my_email_for'), + description: t('hub_browser_what_do_you_use_my_email_for_description'), + }, + { + icon: 'ghosty-lock.svg', + label: `${t('hub_browser_how_secure_is_')} Ghostery?`, + description: t('hub_browser_how_secure_is_ghostery_description'), + }, + { + icon: 'ghosty-box.svg', + label: t('hub_browser_can_i_remove_my_account'), + description: t('hub_browser_can_i_remove_my_account_description'), + } + ]; + + const renderFAQListItem = (icon, label, description) => ( +
+ +
+
{label}
+
{ description }
+
+
+ ); + return (
{ t('hub_browser_create_a_ghostery_account') }
@@ -237,12 +275,14 @@ const BrowserCreateAccountView = (props) => {
{t('hub_browser_skip')}
-
+
{t('hub_browser_we_take_your_privacy_very_seriously')}
-
-
- {/* map here */} +
+
+ {expanded && + faqList.map(item => renderFAQListItem(item.icon, item.label, item.description)) + }
diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index aa2bf3c00..0920b9d6e 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -177,8 +177,37 @@ $color-create-account-form-error-red: #e74055; transform: rotate(225deg); } } +.BrowserCreateAccountView__FAQContainer { + margin-top: 30px; +} +.BrowserCreateAccountView__faqItemContainer { + margin-bottom: 40px; + display: flex; + justify-content: center; +} +.BrowserCreateAccountView__faqIcon { + margin-right: 48px; + height: 71px; + width: 71px; +} +.BrowserCreateAccountView__faqItemTextContainer { + display: flex; + flex-direction: column; +} +.BrowserCreateAccountView__faqItemLabel { + font-size: 18px; + font-weight: 600; + color: #4a4a4a; +} +.BrowserCreateAccountView__faqItemDescription { + margin-top: 10px; + width: 607px; + font-size: 16px; + color: #4a4a4a; +} @media only screen and (max-width: 740px) { .BrowserCreateAccountView { + margin-bottom: 40px; padding-top: 20px; } .BrowserCreateAccountView__header { diff --git a/app/images/hub/browser-create-account-view/ghosty-box.svg b/app/images/hub/browser-create-account-view/ghosty-box.svg new file mode 100644 index 000000000..c2fe79ee6 --- /dev/null +++ b/app/images/hub/browser-create-account-view/ghosty-box.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/images/hub/browser-create-account-view/ghosty-letter.svg b/app/images/hub/browser-create-account-view/ghosty-letter.svg new file mode 100644 index 000000000..2921eee09 --- /dev/null +++ b/app/images/hub/browser-create-account-view/ghosty-letter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/images/hub/browser-create-account-view/ghosty-lock.svg b/app/images/hub/browser-create-account-view/ghosty-lock.svg new file mode 100644 index 000000000..03f9465db --- /dev/null +++ b/app/images/hub/browser-create-account-view/ghosty-lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/images/hub/browser-create-account-view/ghosty-shield-letter.svg b/app/images/hub/browser-create-account-view/ghosty-shield-letter.svg new file mode 100644 index 000000000..2fb520cf9 --- /dev/null +++ b/app/images/hub/browser-create-account-view/ghosty-shield-letter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/images/hub/browser-create-account-view/ghosty-shield.svg b/app/images/hub/browser-create-account-view/ghosty-shield.svg new file mode 100644 index 000000000..6c7d7cc2d --- /dev/null +++ b/app/images/hub/browser-create-account-view/ghosty-shield.svg @@ -0,0 +1 @@ + \ No newline at end of file From f623f2256ea443bde297bec8e3e9f8de677560ca Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 15:25:33 -0500 Subject: [PATCH 05/35] Make list responsive --- .../BrowserCreateAccountView.jsx | 10 ++++++---- .../BrowserCreateAccountView.scss | 13 ++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 64a85a17d..97a29e121 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -61,7 +61,7 @@ const BrowserCreateAccountView = (props) => { faqRef.current.scrollIntoView({ behavior: 'smooth' }); }; - const [expanded, setExpanded] = useState(false); + const [expanded, setExpanded] = useState(true); const arrowClassNames = ClassNames('BrowserCreateAccountView__arrow', { up: expanded, @@ -103,9 +103,11 @@ const BrowserCreateAccountView = (props) => { ]; const renderFAQListItem = (icon, label, description) => ( -
- -
+
+
+ +
+
{label}
{ description }
diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index 0920b9d6e..908ca241d 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -179,16 +179,19 @@ $color-create-account-form-error-red: #e74055; } .BrowserCreateAccountView__FAQContainer { margin-top: 30px; + @include breakpoint(small down) { + text-align: center; + } } .BrowserCreateAccountView__faqItemContainer { - margin-bottom: 40px; - display: flex; - justify-content: center; + margin-bottom: 30px; } .BrowserCreateAccountView__faqIcon { - margin-right: 48px; height: 71px; width: 71px; + min-height: 71px; + min-width: 71px; + margin-bottom: 10px; } .BrowserCreateAccountView__faqItemTextContainer { display: flex; @@ -201,7 +204,7 @@ $color-create-account-form-error-red: #e74055; } .BrowserCreateAccountView__faqItemDescription { margin-top: 10px; - width: 607px; + max-width: 607px; font-size: 16px; color: #4a4a4a; } From 9d641f9ae672a2f7cf129921968514d32f160412 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 15:28:00 -0500 Subject: [PATCH 06/35] Adjust padding of FAQContainer to scroll onto nice spot --- .../BrowserCreateAccountView/BrowserCreateAccountView.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index 908ca241d..941fc0b9a 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -178,7 +178,8 @@ $color-create-account-form-error-red: #e74055; } } .BrowserCreateAccountView__FAQContainer { - margin-top: 30px; + margin-top: 10px; + padding-top: 20px; @include breakpoint(small down) { text-align: center; } From f9ad55eb81f394907df41eb9b3306ce5b1472c6c Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 15:30:48 -0500 Subject: [PATCH 07/35] Make sure promoString checkbox text does not wrap --- .../BrowserCreateAccountView/BrowserCreateAccountView.jsx | 4 ++-- .../BrowserCreateAccountView/BrowserCreateAccountView.scss | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 97a29e121..cb282c689 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -252,7 +252,7 @@ const BrowserCreateAccountView = (props) => {
-
+
{ />
-
+
diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index 941fc0b9a..2568f092b 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -93,6 +93,9 @@ $color-create-account-form-error-red: #e74055; } .BrowserCreateAccountView__promoString { margin-top: 15px; + @include breakpoint(small down) { + margin-top: 0; + } } .BrowserCreateAccountView__link { font-size: 14px; From 13d10ee448e77a65382d8b06b1c693b8b03fac6a Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 15:56:58 -0500 Subject: [PATCH 08/35] Add privacy policy link --- .../BrowserCreateAccountView.jsx | 3 +++ .../BrowserCreateAccountView.scss | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index cb282c689..c0c728394 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -287,6 +287,9 @@ const BrowserCreateAccountView = (props) => { }
+
+ {t('hub_browser_visit_our_privacy_policy')} +
); }; diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index 2568f092b..c86131345 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -25,6 +25,7 @@ $color-create-account-form-error-red: #e74055; display: flex; justify-content: center; font-size: 18px; + text-align: center; } .BrowserCreateAccountView__alreadyHaveAccount { margin-top: 38px; @@ -212,6 +213,21 @@ $color-create-account-form-error-red: #e74055; font-size: 16px; color: #4a4a4a; } +.BrowserCreateAccountView__faqItemDescription { + margin-top: 10px; + max-width: 607px; + font-size: 16px; + color: #4a4a4a; +} +.BrowserCreateAccountView__privacyPolicyLink { + font-size: 16px; + color: $ghosty-blue; + text-decoration: underline; + cursor: pointer; + @include breakpoint(small down) { + text-align: center; + } +} @media only screen and (max-width: 740px) { .BrowserCreateAccountView { margin-bottom: 40px; From 11f908c850c3180029e2eaa6fef26abcc8ee2cab Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 16:04:42 -0500 Subject: [PATCH 09/35] Make privacy policy link more responsive --- .../BrowserCreateAccountView/BrowserCreateAccountView.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index c0c728394..42e0547a4 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -287,9 +287,12 @@ const BrowserCreateAccountView = (props) => { }
-
- {t('hub_browser_visit_our_privacy_policy')} +
+
+ {t('hub_browser_visit_our_privacy_policy')} +
+
); }; From 6cfcdce835adf49042bfc9d74f7665db386ec255 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 20:11:23 -0500 Subject: [PATCH 10/35] Make BrowserLogInForm and style responsively --- _locales/en/messages.json | 3 + .../BrowserCreateAccountView.jsx | 340 +++++++++--------- .../BrowserLoginForm/BrowserLogInForm.jsx | 119 ++++++ .../BrowserLoginForm/BrowserLogInForm.scss | 106 ++++++ app/hub/Views/BrowserLoginForm/index.js | 3 + app/scss/hub.scss | 1 + 6 files changed, 408 insertions(+), 164 deletions(-) create mode 100644 app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx create mode 100644 app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss create mode 100644 app/hub/Views/BrowserLoginForm/index.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 1867170db..042a27e53 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1788,6 +1788,9 @@ "hub_browser_visit_our_privacy_policy": { "message": "Visit our Privacy Policy for more information" }, + "hub_browser_create_an_account": { + "message": "Create an account." + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 42e0547a4..237d1604c 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -16,7 +16,11 @@ import PropTypes from 'prop-types'; import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; import { ToggleCheckbox } from '../../../shared-components'; +import BrowserLogInForm from '../BrowserLoginForm'; +const SIGN_IN = 'SIGN_IN'; +const FORGOT_PASSWORD = 'FORGOT_PASSWORD'; +const CREATE_ACCOUNT = 'CREATE_ACCOUNT'; const promoString = `${t('hub_browser_send_me')} Ghostery ${t('hub_browser_updates_and_promotions')}`; /** @@ -61,7 +65,8 @@ const BrowserCreateAccountView = (props) => { faqRef.current.scrollIntoView({ behavior: 'smooth' }); }; - const [expanded, setExpanded] = useState(true); + const [expanded, setExpanded] = useState(false); + const [view, setView] = useState(SIGN_IN); const arrowClassNames = ClassNames('BrowserCreateAccountView__arrow', { up: expanded, @@ -119,180 +124,187 @@ const BrowserCreateAccountView = (props) => {
{ t('hub_browser_create_a_ghostery_account') }
{ t('hub_browser_sync_settings') }
- {/* add onclick to sign in page */} -
{t('hub_browser_already_have_account')}
+ {view === CREATE_ACCOUNT && ( +
setView(SIGN_IN)}>{t('hub_browser_already_have_account')}
+ )} + {view === SIGN_IN && ( +
setView(CREATE_ACCOUNT)}>{t('hub_browser_create_an_account')}
+ )}
-
-
-
- - - {emailError && ( -
- {t('please_enter_a_valid_email')} -
- )} -
-
- - - {confirmEmailError && ( -
- {t('your_email_do_not_match')} -
- )} + {view === CREATE_ACCOUNT ? ( + +
+
+ + + {emailError && ( +
+ {t('please_enter_a_valid_email')} +
+ )} +
+
+ + + {confirmEmailError && ( +
+ {t('your_email_do_not_match')} +
+ )} +
-
-
-
- - +
+
+ + +
+
+ + +
-
- - +
+
+ + + {passwordInvalidError && ( +
+ {t('hub_create_account_label_password_invalid')} +
+ )} + {passwordLengthError && ( +
+ {t('hub_create_account_label_password_invalid_length')} +
+ )} +
+
+ + + {passwordInvalidError && ( +
+ {t('hub_create_account_label_password_invalid')} +
+ )} + {passwordLengthError && ( +
+ {t('hub_create_account_label_password_invalid_length')} +
+ )} +
-
-
-
- - - {passwordInvalidError && ( -
- {t('hub_create_account_label_password_invalid')} +
+
+
+ +
- )} - {passwordLengthError && ( -
- {t('hub_create_account_label_password_invalid_length')} -
- )} +
+
-
- - - {passwordInvalidError && ( -
- {t('hub_create_account_label_password_invalid')} -
- )} - {passwordLengthError && ( -
- {t('hub_create_account_label_password_invalid_length')} -
- )} +
+
-
-
-
-
- - +
+
+
+
{t('hub_browser_skip')}
-
-
-
- -
-
-
-
-
{t('hub_browser_skip')}
+
+
{t('hub_browser_we_take_your_privacy_very_seriously')}
-
-
-
{t('hub_browser_we_take_your_privacy_very_seriously')}
-
-
-
- {expanded && - faqList.map(item => renderFAQListItem(item.icon, item.label, item.description)) - } -
- -
-
- {t('hub_browser_visit_our_privacy_policy')} -
-
- +
+
+ {expanded && + faqList.map(item => renderFAQListItem(item.icon, item.label, item.description)) + } +
+
+
+ {t('hub_browser_visit_our_privacy_policy')} +
+
+ + ) : ( + + )}
); }; diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx new file mode 100644 index 000000000..a24b5c834 --- /dev/null +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx @@ -0,0 +1,119 @@ +/** + * Browser LogIn View + * + * 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 { NavLink } from 'react-router-dom'; + +/** + * A Functional React component for rendering the Login View + * @return {JSX} JSX for rendering the Login View of the Hub app + * @memberof HubComponents + */ +const BrowserLogInForm = (props) => { + const { + email, + password, + emailError, + passwordError, + handleSubmit, + handleInputChange, + } = props; + + const emailInputClassNames = ClassNames('BrowserLogInForm__inputBox', { + error: emailError, + }); + const passwordInputClassNames = ClassNames('BrowserLogInForm__inputBox', { + error: passwordError, + }); + + return ( +
+
+
+ + + {emailError && ( +
+ {t('please_enter_a_valid_email')} +
+ )} +
+
+
+
+ + + {passwordError && ( +
+ {t('hub_login_label_password_invalid')} +
+ )} +
+
+
+
+ + + {t('forgot_password')} + + +
+
+
+ +
+
+
+
+
{t('hub_browser_skip')}
+
+
+ + ); +}; + +// PropTypes ensure we pass required props of the correct type +BrowserLogInForm.propTypes = { + email: PropTypes.string.isRequired, + password: PropTypes.string.isRequired, + emailError: PropTypes.bool.isRequired, + passwordError: PropTypes.bool.isRequired, + handleSubmit: PropTypes.func.isRequired, + handleInputChange: PropTypes.func.isRequired, +}; + +export default BrowserLogInForm; diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss new file mode 100644 index 000000000..575f700f4 --- /dev/null +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss @@ -0,0 +1,106 @@ +/** + * Log In Form 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 + */ + +// Log In Form +.BrowserLogInForm { + margin-top: 40px; + padding-bottom: 40px; +} +.BrowserLogInForm__headerImage { + line-height: 1.5; + color: #4a4a4a; + margin: 20px 25px 0; +} +.BrowserLogInForm__inputContainer { + margin: auto; +} +.BrowserLogInForm__inputLabel { + text-align: left; + font-size: 14px; + font-weight: 500; + line-height: 2.86; + text-transform: uppercase; + color: #4a4a4a; +} +.BrowserLogInForm__inputBox { + line-height: 24px; + color: #4a4a4a; + + // Foundation Overrides + border-radius: 6px; + box-shadow: none; + border: 1px solid #9b9b9b; + + &::placeholder { + color: #c4ced1; + } +} +.BrowserLogInForm__inputBox.error { + margin-bottom: 8px; + border-color: #e74055; +} +.BrowserLogInForm__inputBox:focus { + // Foundation Overrides + box-shadow: none; + border-color: #4a4a4a; +} +.BrowserLogInForm__inputError { + font-size: 12; + line-height: 14px; + color: #e74055; + margin-bottom: 13px; +} +.BrowserLogInForm__link { + font-size: 14px; + line-height: 30px; +} +.BrowserLogInForm__button { + min-width: 180px; +} +.BrowserLogInForm__ctaButtonContainer { + display: flex; + justify-content: center; + + .BrowserLogInForm__ctaButton { + margin: 48px auto 0 auto; + height: 44px; + width: 162px; + padding: 7.7px 14px; + line-height: 22px; + background: linear-gradient( + 45deg, + #ff7e74 50%, + #00aef0 + ); + background-size: 200% 100%; + background-position: 100% 50%; + transition: 0.25s all; + border: none; + &:hover { + background-position: 0% 50%; + transition: 0.25s all; + } + color: #FFF; + font-size: 14.1px; + font-weight: 700; + border-radius: 3.5px; + text-align: center; + line-height: 2.05; + cursor: pointer; + } +} +@media only screen and (max-width: 740px) { + .BrowserLogInForm__header { + flex-direction: column; + } +} diff --git a/app/hub/Views/BrowserLoginForm/index.js b/app/hub/Views/BrowserLoginForm/index.js new file mode 100644 index 000000000..94e95273b --- /dev/null +++ b/app/hub/Views/BrowserLoginForm/index.js @@ -0,0 +1,3 @@ +import BrowserLoginForm from './BrowserLogInForm'; + +export default BrowserLoginForm; diff --git a/app/scss/hub.scss b/app/scss/hub.scss index 816dcf162..9034a8daa 100644 --- a/app/scss/hub.scss +++ b/app/scss/hub.scss @@ -87,6 +87,7 @@ html, body, #root { @import '../hub/Views/CreateAccountView/CreateAccountView.scss'; @import '../hub/Views/UpgradePlanView/UpgradePlanView.scss'; @import '../hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss'; +@import '../hub/Views/BrowserLogInForm/BrowserLogInForm.scss'; // Imports from ../shared-components directory @import '../shared-components/ExitButton/ExitButton.scss'; From 9f024a57e5c8f86fe4271359652e0d282adc8cd1 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Dec 2020 21:59:47 -0500 Subject: [PATCH 11/35] Refactor Create Account form into a component --- .../BrowserCreateAccountForm.jsx | 235 ++++++++++++++ .../BrowserCreateAccountForm.scss | 74 +++++ .../Views/BrowserCreateAccountForm/index.js | 3 + .../BrowserCreateAccountView.jsx | 298 +++--------------- .../BrowserCreateAccountView.scss | 71 ----- .../BrowserLoginForm/BrowserLogInForm.jsx | 6 +- app/scss/hub.scss | 1 + 7 files changed, 367 insertions(+), 321 deletions(-) create mode 100644 app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx create mode 100644 app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss create mode 100644 app/hub/Views/BrowserCreateAccountForm/index.js diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx new file mode 100644 index 000000000..01477962d --- /dev/null +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx @@ -0,0 +1,235 @@ +/** + * Browser Create Account View + * + * 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, { useRef, useState } from 'react'; +import PropTypes from 'prop-types'; +import ClassNames from 'classnames'; +import { NavLink } from 'react-router-dom'; +import { ToggleCheckbox } from '../../../shared-components'; +import BrowserLogInForm from '../BrowserLoginForm'; + +const SIGN_IN = 'SIGN_IN'; +const FORGOT_PASSWORD = 'FORGOT_PASSWORD'; +const CREATE_ACCOUNT = 'CREATE_ACCOUNT'; +const promoString = `${t('hub_browser_send_me')} Ghostery ${t('hub_browser_updates_and_promotions')}`; + +/** + * A Functional React component for rendering the Browser Create Account View + * @return {JSX} JSX for rendering the Browser Create Account View of the Hub app + * @memberof HubComponents + */ +const BrowserCreateAccountForm = (props) => { + const { + email, + emailError, + confirmEmail, + confirmEmailError, + firstName, + lastName, + password, + confirmPassword, + passwordInvalidError, + passwordLengthError, + isUpdatesChecked, + isUpdatesNotCheckedError, + handleInputChange, + handleUpdatesCheckboxChange, + handleSubmit, + } = props; + + const emailInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { + error: emailError, + }); + const confirmInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { + error: confirmEmailError, + }); + const updatesCheckboxInputLabelClassNames = ClassNames('BrowserCreateAccountForm__promoString clickable', { + error: isUpdatesNotCheckedError, + }); + const passwordInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { + error: passwordInvalidError || passwordLengthError, + }); + + return ( +
+
+
+ + + {emailError && ( +
+ {t('please_enter_a_valid_email')} +
+ )} +
+
+ + + {confirmEmailError && ( +
+ {t('your_email_do_not_match')} +
+ )} +
+
+
+
+ + +
+
+ + +
+
+
+
+ + + {passwordInvalidError && ( +
+ {t('hub_create_account_label_password_invalid')} +
+ )} + {passwordLengthError && ( +
+ {t('hub_create_account_label_password_invalid_length')} +
+ )} +
+
+ + + {passwordInvalidError && ( +
+ {t('hub_create_account_label_password_invalid')} +
+ )} + {passwordLengthError && ( +
+ {t('hub_create_account_label_password_invalid_length')} +
+ )} +
+
+
+
+
+ + +
+
+
+
+
+ +
+ + ); +}; + +// PropTypes ensure we pass required props of the correct type +BrowserCreateAccountForm.propTypes = { + email: PropTypes.string.isRequired, + emailError: PropTypes.bool.isRequired, + confirmEmail: PropTypes.string.isRequired, + confirmEmailError: PropTypes.bool.isRequired, + firstName: PropTypes.string.isRequired, + lastName: PropTypes.string.isRequired, + isUpdatesChecked: PropTypes.bool.isRequired, + isUpdatesNotCheckedError: PropTypes.bool.isRequired, + password: PropTypes.string.isRequired, + confirmPassword: PropTypes.string.isRequired, + passwordInvalidError: PropTypes.bool.isRequired, + passwordLengthError: PropTypes.bool.isRequired, + handleInputChange: PropTypes.func.isRequired, + handleUpdatesCheckboxChange: PropTypes.func.isRequired, + handleSubmit: PropTypes.func.isRequired, +}; + +export default BrowserCreateAccountForm; diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss new file mode 100644 index 000000000..493157ea4 --- /dev/null +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss @@ -0,0 +1,74 @@ +.BrowserCreateAccountForm--addPaddingTop { + padding-top: 20px; +} +.BrowserCreateAccountForm__inputLabel { + font-size: 14px; + font-weight: 500; + line-height: 2.86; + text-transform: uppercase; + color: #4a4a4a; +} +.BrowserCreateAccountForm__inputBox { + font-size: 14; + line-height: 24px; + color: #4a4a4a; + + // Foundation Overrides + border-radius: 6px; + box-shadow: none; + border: 1px solid #9b9b9b; + + &::placeholder { + color: #c4ced1; + } +} +.BrowserCreateAccountForm__inputBox.error { + margin-bottom: 8px; + border-color: $color-create-account-form-error-red; +} +.BrowserCreateAccountForm__promoString { + margin-top: 15px; + @include breakpoint(small down) { + margin-top: 0; + } +} +.BrowserCreateAccountForm__ctaButtonContainer { + display: flex; + justify-content: center; + + .BrowserCreateAccountForm__ctaButton { + margin: 48px auto 0 auto; + height: 44px; + width: 162px; + padding: 7.7px 14px; + line-height: 22px; + background: linear-gradient( + 45deg, + #ff7e74 50%, + #00aef0 + ); + background-size: 200% 100%; + background-position: 100% 50%; + transition: 0.25s all; + border: none; + &:hover { + background-position: 0% 50%; + transition: 0.25s all; + } + color: #FFF; + font-size: 14.1px; + font-weight: 700; + border-radius: 3.5px; + text-align: center; + line-height: 2.05; + cursor: pointer; + } +} +@media only screen and (max-width: 740px) { + .BrowserCreateAccountForm__checkboxContainer { + display: flex; + align-items: center; + padding-right: 12px; + justify-content: center; + } +} diff --git a/app/hub/Views/BrowserCreateAccountForm/index.js b/app/hub/Views/BrowserCreateAccountForm/index.js new file mode 100644 index 000000000..4e9b4f73b --- /dev/null +++ b/app/hub/Views/BrowserCreateAccountForm/index.js @@ -0,0 +1,3 @@ +import BrowserCreateAccountForm from './BrowserCreateAccountForm'; + +export default BrowserCreateAccountForm; diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 237d1604c..886f83783 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -11,53 +11,71 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -import React, { useRef, useState } from 'react'; +import React, { Fragment, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; import { ToggleCheckbox } from '../../../shared-components'; import BrowserLogInForm from '../BrowserLoginForm'; +import BrowserCreateAccountForm from '../BrowserCreateAccountForm'; const SIGN_IN = 'SIGN_IN'; const FORGOT_PASSWORD = 'FORGOT_PASSWORD'; const CREATE_ACCOUNT = 'CREATE_ACCOUNT'; const promoString = `${t('hub_browser_send_me')} Ghostery ${t('hub_browser_updates_and_promotions')}`; +const faqList = [ + { + icon: 'ghosty-shield.svg', + label: t('hub_browser_private_by_design'), + description: t('hub_browser_private_by_design_description'), + }, + { + icon: 'ghosty-letter.svg', + label: t('hub_browser_why_do_you_need_my_email'), + description: t('hub_browser_why_do_you_need_my_email_description'), + }, + { + icon: 'ghosty-shield-letter.svg', + label: t('hub_browser_what_do_you_use_my_email_for'), + description: t('hub_browser_what_do_you_use_my_email_for_description'), + }, + { + icon: 'ghosty-lock.svg', + label: `${t('hub_browser_how_secure_is_')} Ghostery?`, + description: t('hub_browser_how_secure_is_ghostery_description'), + }, + { + icon: 'ghosty-box.svg', + label: t('hub_browser_can_i_remove_my_account'), + description: t('hub_browser_can_i_remove_my_account_description'), + } +]; + +const renderFAQListItem = (icon, label, description) => ( +
+
+ +
+
+
{label}
+
{description}
+
+
+); + /** * A Functional React component for rendering the Browser Create Account View * @return {JSX} JSX for rendering the Browser Create Account View of the Hub app * @memberof HubComponents */ -const BrowserCreateAccountView = (props) => { - const { - email, - emailError, - confirmEmail, - confirmEmailError, - firstName, - lastName, - password, - confirmPassword, - passwordInvalidError, - passwordLengthError, - isUpdatesChecked, - isUpdatesNotCheckedError, - handleInputChange, - handleUpdatesCheckboxChange, - handleSubmit, - } = props; +const BrowserCreateAccountView = () => { + const [expanded, setExpanded] = useState(false); + const [view, setView] = useState(CREATE_ACCOUNT); - const emailInputClassNames = ClassNames('BrowserCreateAccountView__inputBox', { - error: emailError, - }); - const confirmInputClassNames = ClassNames('BrowserCreateAccountView__inputBox', { - error: confirmEmailError, - }); - const updatesCheckboxInputLabelClassNames = ClassNames('BrowserCreateAccountView__promoString clickable', { - error: isUpdatesNotCheckedError, - }); - const passwordInputClassNames = ClassNames('BrowserCreateAccountView__inputBox', { - error: passwordInvalidError || passwordLengthError, + const arrowClassNames = ClassNames('BrowserCreateAccountView__arrow', { + up: expanded, + down: !expanded, }); const faqRef = useRef(null); @@ -65,60 +83,11 @@ const BrowserCreateAccountView = (props) => { faqRef.current.scrollIntoView({ behavior: 'smooth' }); }; - const [expanded, setExpanded] = useState(false); - const [view, setView] = useState(SIGN_IN); - - const arrowClassNames = ClassNames('BrowserCreateAccountView__arrow', { - up: expanded, - down: !expanded, - error: passwordInvalidError || passwordLengthError, - }); - const handleFAQLearnMoreClick = () => { setTimeout(scrollToFAQ, 1); setExpanded(!expanded); }; - const faqList = [ - { - icon: 'ghosty-shield.svg', - label: t('hub_browser_private_by_design'), - description: t('hub_browser_private_by_design_description'), - }, - { - icon: 'ghosty-letter.svg', - label: t('hub_browser_why_do_you_need_my_email'), - description: t('hub_browser_why_do_you_need_my_email_description'), - }, - { - icon: 'ghosty-shield-letter.svg', - label: t('hub_browser_what_do_you_use_my_email_for'), - description: t('hub_browser_what_do_you_use_my_email_for_description'), - }, - { - icon: 'ghosty-lock.svg', - label: `${t('hub_browser_how_secure_is_')} Ghostery?`, - description: t('hub_browser_how_secure_is_ghostery_description'), - }, - { - icon: 'ghosty-box.svg', - label: t('hub_browser_can_i_remove_my_account'), - description: t('hub_browser_can_i_remove_my_account_description'), - } - ]; - - const renderFAQListItem = (icon, label, description) => ( -
-
- -
-
-
{label}
-
{ description }
-
-
- ); - return (
{ t('hub_browser_create_a_ghostery_account') }
@@ -133,154 +102,8 @@ const BrowserCreateAccountView = (props) => {
{view === CREATE_ACCOUNT ? ( -
-
-
- - - {emailError && ( -
- {t('please_enter_a_valid_email')} -
- )} -
-
- - - {confirmEmailError && ( -
- {t('your_email_do_not_match')} -
- )} -
-
-
-
- - -
-
- - -
-
-
-
- - - {passwordInvalidError && ( -
- {t('hub_create_account_label_password_invalid')} -
- )} - {passwordLengthError && ( -
- {t('hub_create_account_label_password_invalid_length')} -
- )} -
-
- - - {passwordInvalidError && ( -
- {t('hub_create_account_label_password_invalid')} -
- )} - {passwordLengthError && ( -
- {t('hub_create_account_label_password_invalid_length')} -
- )} -
-
-
-
-
- - -
-
-
-
-
- -
+ +
@@ -301,7 +124,7 @@ const BrowserCreateAccountView = (props) => { {t('hub_browser_visit_our_privacy_policy')}
- + ) : ( )} @@ -309,23 +132,4 @@ const BrowserCreateAccountView = (props) => { ); }; -// PropTypes ensure we pass required props of the correct type -BrowserCreateAccountView.propTypes = { - email: PropTypes.string.isRequired, - emailError: PropTypes.bool.isRequired, - confirmEmail: PropTypes.string.isRequired, - confirmEmailError: PropTypes.bool.isRequired, - firstName: PropTypes.string.isRequired, - lastName: PropTypes.string.isRequired, - isUpdatesChecked: PropTypes.bool.isRequired, - isUpdatesNotCheckedError: PropTypes.bool.isRequired, - password: PropTypes.string.isRequired, - confirmPassword: PropTypes.string.isRequired, - passwordInvalidError: PropTypes.bool.isRequired, - passwordLengthError: PropTypes.bool.isRequired, - handleInputChange: PropTypes.func.isRequired, - handleUpdatesCheckboxChange: PropTypes.func.isRequired, - handleSubmit: PropTypes.func.isRequired, -}; - export default BrowserCreateAccountView; diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index c86131345..ab57c1de0 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -37,9 +37,6 @@ $color-create-account-form-error-red: #e74055; padding-top: 80px; padding-bottom: 40px; } -.BrowserCreateAccountView--addPaddingTop { - padding-top: 20px; -} .BrowserCreateAccountView--addMarginSide { margin-left: 10px; margin-right: 10px; @@ -56,31 +53,7 @@ $color-create-account-form-error-red: #e74055; color: #4a4a4a; margin: 0 25px; } -.BrowserCreateAccountView__inputLabel { - font-size: 14px; - font-weight: 500; - line-height: 2.86; - text-transform: uppercase; - color: #4a4a4a; -} -.BrowserCreateAccountView__inputBox { - font-size: 14; - line-height: 24px; - color: #4a4a4a; - // Foundation Overrides - border-radius: 6px; - box-shadow: none; - border: 1px solid #9b9b9b; - - &::placeholder { - color: #c4ced1; - } -} -.BrowserCreateAccountView__inputBox.error { - margin-bottom: 8px; - border-color: $color-create-account-form-error-red; -} .BrowserCreateAccountView__inputBox:focus { // Foundation Overrides box-shadow: none; @@ -92,12 +65,6 @@ $color-create-account-form-error-red: #e74055; color: $color-create-account-form-error-red; margin-bottom: 13px; } -.BrowserCreateAccountView__promoString { - margin-top: 15px; - @include breakpoint(small down) { - margin-top: 0; - } -} .BrowserCreateAccountView__link { font-size: 14px; line-height: 30px; @@ -115,38 +82,6 @@ $color-create-account-form-error-red: #e74055; .BrowserCreateAccountView__inputLabel.error{ color: $color-create-account-form-error-red; } -.BrowserCreateAccountView__ctaButtonContainer { - display: flex; - justify-content: center; - - .BrowserCreateAccountView__ctaButton { - margin: 48px auto 0 auto; - height: 44px; - width: 162px; - padding: 7.7px 14px; - line-height: 22px; - background: linear-gradient( - 45deg, - #ff7e74 50%, - #00aef0 - ); - background-size: 200% 100%; - background-position: 100% 50%; - transition: 0.25s all; - border: none; - &:hover { - background-position: 0% 50%; - transition: 0.25s all; - } - color: #FFF; - font-size: 14.1px; - font-weight: 700; - border-radius: 3.5px; - text-align: center; - line-height: 2.05; - cursor: pointer; - } -} .BrowserCreateAccountView__skip { margin-top: -37px; float: right; @@ -244,12 +179,6 @@ $color-create-account-form-error-red: #e74055; display: flex; justify-content: center; } - .BrowserCreateAccountView__checkboxContainer { - display: flex; - align-items: center; - padding-right: 12px; - justify-content: center; - } .BrowserCreateAccountView__linkContainer { text-align: center; } diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx index a24b5c834..1ed256574 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx @@ -1,5 +1,5 @@ /** - * Browser LogIn View + * Browser Log In Form * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -17,8 +17,8 @@ import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; /** - * A Functional React component for rendering the Login View - * @return {JSX} JSX for rendering the Login View of the Hub app + * A Functional React component for rendering the Log In Form + * @return {JSX} JSX for rendering the Log In Form of the Browser Hub app * @memberof HubComponents */ const BrowserLogInForm = (props) => { diff --git a/app/scss/hub.scss b/app/scss/hub.scss index 9034a8daa..7effd20ec 100644 --- a/app/scss/hub.scss +++ b/app/scss/hub.scss @@ -87,6 +87,7 @@ html, body, #root { @import '../hub/Views/CreateAccountView/CreateAccountView.scss'; @import '../hub/Views/UpgradePlanView/UpgradePlanView.scss'; @import '../hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss'; +@import '../hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss'; @import '../hub/Views/BrowserLogInForm/BrowserLogInForm.scss'; // Imports from ../shared-components directory From 03715133573966fdaf64908cfef6ba7de55d9e13 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 11:14:28 -0500 Subject: [PATCH 12/35] Create BrowserCreateAccountFormContainer and add handlers --- .../BrowserCreateAccountForm.jsx | 30 ++- .../BrowserCreateAccountFormContainer.jsx | 218 ++++++++++++++++++ .../Views/BrowserCreateAccountForm/index.js | 44 +++- .../BrowserCreateAccountView.jsx | 1 - 4 files changed, 286 insertions(+), 7 deletions(-) create mode 100644 app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx index 01477962d..73f64a73c 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx @@ -16,11 +16,8 @@ import PropTypes from 'prop-types'; import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; import { ToggleCheckbox } from '../../../shared-components'; -import BrowserLogInForm from '../BrowserLoginForm'; +import I18nWithLink from '../../../shared-components/I18nWithLink'; -const SIGN_IN = 'SIGN_IN'; -const FORGOT_PASSWORD = 'FORGOT_PASSWORD'; -const CREATE_ACCOUNT = 'CREATE_ACCOUNT'; const promoString = `${t('hub_browser_send_me')} Ghostery ${t('hub_browser_updates_and_promotions')}`; /** @@ -40,6 +37,9 @@ const BrowserCreateAccountForm = (props) => { confirmPassword, passwordInvalidError, passwordLengthError, + legalConsentChecked, + legalConsentNotCheckedError, + handleLegalConsentCheckboxChange, isUpdatesChecked, isUpdatesNotCheckedError, handleInputChange, @@ -47,6 +47,8 @@ const BrowserCreateAccountForm = (props) => { handleSubmit, } = props; + console.log('BrowserCreateAccountForm props: ', props); + const emailInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { error: emailError, }); @@ -206,6 +208,26 @@ const BrowserCreateAccountForm = (props) => {
+
+
+
+ + + {/* */} +
+
+
+
diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx new file mode 100644 index 000000000..c1325bbb5 --- /dev/null +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx @@ -0,0 +1,218 @@ +/** + * Create Account View Container + * + * 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, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { + validateEmail, + validatePassword, + validateEmailsMatch, + validateConfirmEmail +} from '../../../panel/utils/utils'; +import BrowserCreateAccountForm from './BrowserCreateAccountForm'; + +/** + * @class Implement the Create Account View for the Ghostery Hub + * @extends Component + * @memberof HubContainers + */ +class CreateAccountFormContainer extends Component { + constructor(props) { + super(props); + this.state = { + email: '', + emailError: false, + confirmEmail: '', + confirmEmailError: false, + firstName: '', + lastName: '', + legalConsentChecked: false, + legalConsentNotCheckedError: false, + isUpdatesChecked: false, + password: '', + passwordInvalidError: false, + passwordLengthError: false, + validateInput: false, + }; + + const { actions } = this.props; + actions.setToast({ + toastMessage: '', + toastClass: '', + }); + } + + /** + * Update input values by updating state. + * @param {Object} event the 'change' event + */ + _handleInputChange = (event) => { + const { name, value } = event.target; + this.setState({ [name]: value }); + + const { validateInput } = this.state; + if (!validateInput) { + return; + } + + switch (name) { + case 'email': { + const emailIsValid = value && validateEmail(value); + this.setState({ + emailError: !emailIsValid, + }); + break; + } + case 'confirmEmail': { + const { email } = this.state; + const confirmIsValid = value && validateEmailsMatch(email, value); + this.setState({ + confirmEmailError: !confirmIsValid, + }); + break; + } + case 'password': { + const passwordIsValid = value && validatePassword(value); + const invalidChars = !passwordIsValid && value.length >= 8 && value.length <= 50; + const invalidLength = !passwordIsValid && !invalidChars; + this.setState({ + passwordInvalidError: invalidChars, + passwordLengthError: invalidLength, + }); + break; + } + default: break; + } + } + + /** + * Update legal consent checkbox value by updating state + */ + _handleLegalConsentCheckboxChange = () => { + this.setState(prevState => ({ legalConsentChecked: !prevState.legalConsentChecked })); + } + + /** + * Update updates checkbox value by updating state + */ + _handleUpdatesCheckboxChange = () => { + this.setState(prevState => ({ isUpdatesChecked: !prevState.isUpdatesChecked })); + } + + /** + * Handle creating an account, but validate the data first. + * @param {Object} event the 'submit' event + */ + _handleCreateAccountAttempt = (event) => { + event.preventDefault(); + const { + email, + confirmEmail, + firstName, + lastName, + legalConsentChecked, + password, + } = this.state; + const emailIsValid = email && validateEmail(email); + const confirmIsValid = confirmEmail && validateConfirmEmail(email, confirmEmail); + const passwordIsValid = password && validatePassword(password); + const invalidChars = !passwordIsValid && password.length >= 8 && password.length <= 50; + const invalidLength = !passwordIsValid && !invalidChars; + + this.setState({ + emailError: !emailIsValid, + confirmEmailError: !confirmIsValid, + legalConsentNotCheckedError: !legalConsentChecked, + passwordInvalidError: invalidChars, + passwordLengthError: invalidLength, + validateInput: true, + }); + + if (!emailIsValid || !confirmIsValid || !legalConsentChecked || !passwordIsValid) { + return; + } + const { actions } = this.props; + actions.setToast({ + toastMessage: '', + toastClass: '' + }); + actions.register(email, confirmEmail, firstName, lastName, password).then((success) => { + if (success) { + actions.getUser(); + // Toggle legal consent checked here + actions.setToast({ + toastMessage: t('hub_create_account_toast_success'), + toastClass: 'success' + }); + // Route to next screen + } else { + actions.setToast({ + toastMessage: t('hub_create_account_toast_error'), + toastClass: 'alert' + }); + } + }); + } + + /** + * React's required render function. Returns JSX + * @return {JSX} JSX for rendering the Create Account View of the Hub app + */ + render() { + // const { user } = this.props; + const { + email, + emailError, + confirmEmail, + confirmEmailError, + firstName, + lastName, + legalConsentChecked, + legalConsentNotCheckedError, + isUpdatesChecked, + password, + passwordInvalidError, + passwordLengthError, + } = this.state; + + return ( + + ); + } +} + +// PropTypes ensure we pass required props of the correct type +CreateAccountFormContainer.propTypes = { + actions: PropTypes.shape({ + setToast: PropTypes.func.isRequired, + register: PropTypes.func.isRequired, + getUser: PropTypes.func.isRequired, + }).isRequired, +}; + +export default CreateAccountFormContainer; diff --git a/app/hub/Views/BrowserCreateAccountForm/index.js b/app/hub/Views/BrowserCreateAccountForm/index.js index 4e9b4f73b..977335a49 100644 --- a/app/hub/Views/BrowserCreateAccountForm/index.js +++ b/app/hub/Views/BrowserCreateAccountForm/index.js @@ -1,3 +1,43 @@ -import BrowserCreateAccountForm from './BrowserCreateAccountForm'; +/** + * Point of entry index.js file for Create Account Form + * + * 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 + */ -export default BrowserCreateAccountForm; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; + +import BrowserCreateAccountFormContainer from './BrowserCreateAccountFormContainer'; +import { register, getUser } from '../../../Account/AccountActions'; +import { setToast } from '../AppView/AppViewActions'; + +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => ({ ...state.account }); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof SetupContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators({ + setToast, + register, + getUser + }, dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(BrowserCreateAccountFormContainer); diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 886f83783..a6d592f7f 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -22,7 +22,6 @@ import BrowserCreateAccountForm from '../BrowserCreateAccountForm'; const SIGN_IN = 'SIGN_IN'; const FORGOT_PASSWORD = 'FORGOT_PASSWORD'; const CREATE_ACCOUNT = 'CREATE_ACCOUNT'; -const promoString = `${t('hub_browser_send_me')} Ghostery ${t('hub_browser_updates_and_promotions')}`; const faqList = [ { From 7a04bd3347a1a2ffc33ad220bd7819013eb73477 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 11:19:18 -0500 Subject: [PATCH 13/35] Add error handling to legal consent label --- .../BrowserCreateAccountForm.jsx | 16 ++++++++-------- .../BrowserCreateAccountForm.scss | 7 +++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx index 73f64a73c..d0a3c4dd9 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx @@ -61,6 +61,9 @@ const BrowserCreateAccountForm = (props) => { const passwordInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { error: passwordInvalidError || passwordLengthError, }); + const legalConsentClassNames = ClassNames('BrowserCreateAccountForm__legalConsentCheckedLabel', { + error: legalConsentNotCheckedError + }); return (
@@ -216,14 +219,11 @@ const BrowserCreateAccountForm = (props) => { className="ToggleCheckbox--flush-left" onChange={handleLegalConsentCheckboxChange} /> - - {/* */} +
diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss index 493157ea4..e10867788 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss @@ -32,6 +32,13 @@ margin-top: 0; } } +.BrowserCreateAccountForm__legalConsentCheckedLabel { + font-size: 14px; + + &.error { + color: red; + } +} .BrowserCreateAccountForm__ctaButtonContainer { display: flex; justify-content: center; From 31b8e8ee1a0ea75f20b999ad559208087cdbcfe6 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 11:45:12 -0500 Subject: [PATCH 14/35] Remove privacy policy link if learn more is not expanded --- .../BrowserCreateAccountForm.scss | 3 +++ .../BrowserCreateAccountView.jsx | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss index e10867788..5e940bbaa 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss @@ -26,6 +26,9 @@ margin-bottom: 8px; border-color: $color-create-account-form-error-red; } +.BrowserCreateAccountForm__inputError { + color: red; +} .BrowserCreateAccountForm__promoString { margin-top: 15px; @include breakpoint(small down) { diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index a6d592f7f..ef85a4bb6 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -18,6 +18,7 @@ import { NavLink } from 'react-router-dom'; import { ToggleCheckbox } from '../../../shared-components'; import BrowserLogInForm from '../BrowserLoginForm'; import BrowserCreateAccountForm from '../BrowserCreateAccountForm'; +import globals from '../../../../src/classes/Globals'; const SIGN_IN = 'SIGN_IN'; const FORGOT_PASSWORD = 'FORGOT_PASSWORD'; @@ -118,11 +119,13 @@ const BrowserCreateAccountView = () => { faqList.map(item => renderFAQListItem(item.icon, item.label, item.description)) }
-
-
- {t('hub_browser_visit_our_privacy_policy')} + {expanded && ( + -
+ )} ) : ( From 2071175ca78125829d7ea8b39006c66d72058ad6 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 12:36:30 -0500 Subject: [PATCH 15/35] Add handlers for log in view and replace strings --- .../BrowserCreateAccountForm.scss | 4 + .../BrowserCreateAccountView.jsx | 9 +- .../BrowserLoginForm/BrowserLogInForm.jsx | 2 +- .../BrowserLogInFormContainer.jsx | 160 ++++++++++++++++++ app/hub/Views/BrowserLoginForm/index.js | 47 ++++- 5 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss index 5e940bbaa..184de9473 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss @@ -30,6 +30,7 @@ color: red; } .BrowserCreateAccountForm__promoString { + font-size: 14px; margin-top: 15px; @include breakpoint(small down) { margin-top: 0; @@ -37,6 +38,9 @@ } .BrowserCreateAccountForm__legalConsentCheckedLabel { font-size: 14px; + @include breakpoint(small down) { + width: 258px; + } &.error { color: red; diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index ef85a4bb6..cef3420cc 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -71,7 +71,7 @@ const renderFAQListItem = (icon, label, description) => ( */ const BrowserCreateAccountView = () => { const [expanded, setExpanded] = useState(false); - const [view, setView] = useState(CREATE_ACCOUNT); + const [view, setView] = useState(SIGN_IN); const arrowClassNames = ClassNames('BrowserCreateAccountView__arrow', { up: expanded, @@ -90,7 +90,12 @@ const BrowserCreateAccountView = () => { return (
-
{ t('hub_browser_create_a_ghostery_account') }
+ {view === CREATE_ACCOUNT && ( +
{t('hub_browser_create_a_ghostery_account')}
+ )} + {view === SIGN_IN && ( +
{t('sign_in')}
+ )}
{ t('hub_browser_sync_settings') }
{view === CREATE_ACCOUNT && ( diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx index 1ed256574..11cda1f1e 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx @@ -94,7 +94,7 @@ const BrowserLogInForm = (props) => {
- +
diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx b/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx new file mode 100644 index 000000000..8dffbf897 --- /dev/null +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx @@ -0,0 +1,160 @@ +/** + * Browser Log In Form Container + * + * 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, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { validateEmail } from '../../../panel/utils/utils'; +import BrowserLogInForm from './BrowserLogInForm'; +import SignedInView from '../SignedInView'; +/** + * @class Implement the Browser Log In Form for the Ghostery Hub + * @extends Component + * @memberof HubContainers + */ +class BrowserLogInFormContainer extends Component { + constructor(props) { + super(props); + this.state = { + email: '', + password: '', + emailError: false, + passwordError: false, + validateInput: false, + }; + + const { actions } = this.props; + actions.setToast({ + toastMessage: '', + toastClass: '', + }); + } + + /** + * Update input values by updating state. + * @param {Object} event the 'change' event + */ + _handleInputChange = (event) => { + const { name, value } = event.target; + this.setState({ [name]: value }); + + const { validateInput } = this.state; + if (!validateInput) { + return; + } + + switch (name) { + case 'email': { + const emailIsValid = value && validateEmail(value); + this.setState({ + emailError: !emailIsValid, + }); + break; + } + case 'password': { + this.setState({ + passwordError: !value, + }); + break; + } + default: break; + } + } + + /** + * Handle logging in, but validate the data first. + * @param {Object} event the 'submit' event + */ + _handleLoginAttempt = (event) => { + event.preventDefault(); + const { email, password } = this.state; + const emailIsValid = email && validateEmail(email); + + this.setState({ + emailError: !emailIsValid, + passwordError: !password, + validateInput: true, + }); + + if (!emailIsValid || !password) { + return; + } + + const { actions, history } = this.props; + actions.setToast({ + toastMessage: '', + toastClass: '' + }); + actions.login(email, password).then((success) => { + if (success) { + const { origin, pathname, hash } = window.location; + window.history.pushState({}, '', `${origin}${pathname}${hash}`); + + actions.getUser(); + actions.getUserSettings() + .then((settings) => { + const { current_theme } = settings; + return actions.getTheme(current_theme); + }); + actions.setToast({ + toastMessage: t('hub_login_toast_success'), + toastClass: 'success' + }); + // Move to second screen + } else { + actions.setToast({ + toastMessage: t('no_such_email_password_combo'), + toastClass: 'alert' + }); + } + }); + } + + /** + * React's required render function. Returns JSX + * @return {JSX} JSX for rendering the Log In View of the Hub app + */ + render() { + const { loggedIn, user } = this.props; + const { + email, + password, + emailError, + passwordError, + } = this.state; + + return loggedIn ? ( + + ) : ( + + ); + } +} + +// PropTypes ensure we pass required props of the correct type +BrowserLogInFormContainer.propTypes = { + actions: PropTypes.shape({ + setToast: PropTypes.func.isRequired, + login: PropTypes.func.isRequired, + getUser: PropTypes.func.isRequired, + getUserSettings: PropTypes.func.isRequired, + }).isRequired, +}; + +export default BrowserLogInFormContainer; diff --git a/app/hub/Views/BrowserLoginForm/index.js b/app/hub/Views/BrowserLoginForm/index.js index 94e95273b..7fbff23c5 100644 --- a/app/hub/Views/BrowserLoginForm/index.js +++ b/app/hub/Views/BrowserLoginForm/index.js @@ -1,3 +1,46 @@ -import BrowserLoginForm from './BrowserLogInForm'; +/** + * Point of entry index.js file for Browser Log In Form + * + * 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 + */ -export default BrowserLoginForm; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; + +import BrowserLogInFormContainer from './BrowserLogInFormContainer'; +import { login, getUser, getUserSettings } from '../../../Account/AccountActions'; +import { getTheme } from '../../../panel/actions/PanelActions'; +import { setToast } from '../AppView/AppViewActions'; + +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => ({ ...state.account }); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof SetupContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators({ + setToast, + login, + getUser, + getUserSettings, + getTheme + }, dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(BrowserLogInFormContainer); From 74b0a41df519832ab4fc5370b3dca2f212e21716 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 13:16:30 -0500 Subject: [PATCH 16/35] Add handlers for forgot password and throttle it --- .../BrowserLoginForm/BrowserLogInForm.jsx | 7 ++-- .../BrowserLoginForm/BrowserLogInForm.scss | 5 +++ .../BrowserLogInFormContainer.jsx | 32 ++++++++++++++++++- app/hub/Views/BrowserLoginForm/index.js | 10 ++++-- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx index 11cda1f1e..102ece6f6 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx @@ -29,6 +29,7 @@ const BrowserLogInForm = (props) => { passwordError, handleSubmit, handleInputChange, + handleForgotPassword, } = props; const emailInputClassNames = ClassNames('BrowserLogInForm__inputBox', { @@ -86,10 +87,10 @@ const BrowserLogInForm = (props) => {
- - + +
{t('forgot_password')} - +
diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss index 575f700f4..56f47d710 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss @@ -64,6 +64,11 @@ font-size: 14px; line-height: 30px; } +.BrowserLogInForm__forgotPassword { + color: $ghosty-blue; + text-decoration: underline; + cursor: pointer; +} .BrowserLogInForm__button { min-width: 180px; } diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx b/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx index 8dffbf897..7d29f257b 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx @@ -13,9 +13,11 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import { throttle } from 'underscore'; import { validateEmail } from '../../../panel/utils/utils'; import BrowserLogInForm from './BrowserLogInForm'; import SignedInView from '../SignedInView'; + /** * @class Implement the Browser Log In Form for the Ghostery Hub * @extends Component @@ -89,7 +91,7 @@ class BrowserLogInFormContainer extends Component { return; } - const { actions, history } = this.props; + const { actions } = this.props; actions.setToast({ toastMessage: '', toastClass: '' @@ -119,6 +121,33 @@ class BrowserLogInFormContainer extends Component { }); } + _unthrottledHandleForgotPassword = (e) => { + e.preventDefault(); + const { email } = this.state; + + // validate the email and password + if (!validateEmail(email)) { + this.setState({ + emailError: true, + }); + return; + } + + const { actions } = this.props; + actions.resetPassword(email) + .then((success) => { + if (success) { + actions.setToast({ + toastMessage: t('banner_check_your_email_title'), + toastClass: 'success', + }); + } + }); + } + + // eslint-disable-next-line react/sort-comp + _handleForgotPassword = throttle(this._unthrottledHandleForgotPassword, 10000) + /** * React's required render function. Returns JSX * @return {JSX} JSX for rendering the Log In View of the Hub app @@ -142,6 +171,7 @@ class BrowserLogInFormContainer extends Component { passwordError={passwordError} handleInputChange={this._handleInputChange} handleSubmit={this._handleLoginAttempt} + handleForgotPassword={this._handleForgotPassword} /> ); } diff --git a/app/hub/Views/BrowserLoginForm/index.js b/app/hub/Views/BrowserLoginForm/index.js index 7fbff23c5..e4a351973 100644 --- a/app/hub/Views/BrowserLoginForm/index.js +++ b/app/hub/Views/BrowserLoginForm/index.js @@ -15,7 +15,12 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import BrowserLogInFormContainer from './BrowserLogInFormContainer'; -import { login, getUser, getUserSettings } from '../../../Account/AccountActions'; +import { + login, + getUser, + getUserSettings, + resetPassword +} from '../../../Account/AccountActions'; import { getTheme } from '../../../panel/actions/PanelActions'; import { setToast } from '../AppView/AppViewActions'; @@ -39,7 +44,8 @@ const mapDispatchToProps = dispatch => ({ login, getUser, getUserSettings, - getTheme + getTheme, + resetPassword }, dispatch), }); From 7d9bd4736c63f20745f8e0dcea5c1cf934e33f63 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 13:35:17 -0500 Subject: [PATCH 17/35] Lower throttle time in case user enters a wrong email --- app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx b/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx index 7d29f257b..46c9a6f9a 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx @@ -146,7 +146,7 @@ class BrowserLogInFormContainer extends Component { } // eslint-disable-next-line react/sort-comp - _handleForgotPassword = throttle(this._unthrottledHandleForgotPassword, 10000) + _handleForgotPassword = throttle(this._unthrottledHandleForgotPassword, 3000) /** * React's required render function. Returns JSX From ba6f3c98f3648fe835db9236d03ae625dd0f644e Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 13:54:17 -0500 Subject: [PATCH 18/35] Make updates checkbox work --- .../BrowserCreateAccountForm.jsx | 9 +-------- .../BrowserCreateAccountFormContainer.jsx | 2 ++ .../BrowserCreateAccountView.jsx | 2 +- app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss | 2 +- app/hub/Views/CreateAccountView/CreateAccountView.scss | 2 +- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx index d0a3c4dd9..e258cb7c1 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx @@ -16,7 +16,6 @@ import PropTypes from 'prop-types'; import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; import { ToggleCheckbox } from '../../../shared-components'; -import I18nWithLink from '../../../shared-components/I18nWithLink'; const promoString = `${t('hub_browser_send_me')} Ghostery ${t('hub_browser_updates_and_promotions')}`; @@ -41,23 +40,17 @@ const BrowserCreateAccountForm = (props) => { legalConsentNotCheckedError, handleLegalConsentCheckboxChange, isUpdatesChecked, - isUpdatesNotCheckedError, handleInputChange, handleUpdatesCheckboxChange, handleSubmit, } = props; - console.log('BrowserCreateAccountForm props: ', props); - const emailInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { error: emailError, }); const confirmInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { error: confirmEmailError, }); - const updatesCheckboxInputLabelClassNames = ClassNames('BrowserCreateAccountForm__promoString clickable', { - error: isUpdatesNotCheckedError, - }); const passwordInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { error: passwordInvalidError || passwordLengthError, }); @@ -203,7 +196,7 @@ const BrowserCreateAccountForm = (props) => { onChange={handleUpdatesCheckboxChange} /> diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx index c1325bbb5..d77951090 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx @@ -201,6 +201,8 @@ class CreateAccountFormContainer extends Component { handleInputChange={this._handleInputChange} handleLegalConsentCheckboxChange={this._handleLegalConsentCheckboxChange} handleSubmit={this._handleCreateAccountAttempt} + isUpdatesChecked={isUpdatesChecked} + handleUpdatesCheckboxChange={this._handleUpdatesCheckboxChange} /> ); } diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index cef3420cc..3e09aed02 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -21,8 +21,8 @@ import BrowserCreateAccountForm from '../BrowserCreateAccountForm'; import globals from '../../../../src/classes/Globals'; const SIGN_IN = 'SIGN_IN'; -const FORGOT_PASSWORD = 'FORGOT_PASSWORD'; const CREATE_ACCOUNT = 'CREATE_ACCOUNT'; +const ALREADY_SIGNED_IN = 'ALREADRY_SALREADY_SIGNED_IN'; const faqList = [ { diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss index 56f47d710..2f8003841 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss @@ -47,7 +47,7 @@ } .BrowserLogInForm__inputBox.error { margin-bottom: 8px; - border-color: #e74055; + border: 2px solid #e74055; } .BrowserLogInForm__inputBox:focus { // Foundation Overrides diff --git a/app/hub/Views/CreateAccountView/CreateAccountView.scss b/app/hub/Views/CreateAccountView/CreateAccountView.scss index 489e3ecbe..d9f128613 100644 --- a/app/hub/Views/CreateAccountView/CreateAccountView.scss +++ b/app/hub/Views/CreateAccountView/CreateAccountView.scss @@ -56,7 +56,7 @@ $color-create-account-form-error-red: #e74055; } .CreateAccountView__inputBox.error { margin-bottom: 8px; - border-color: $color-create-account-form-error-red; + border: 2px solid $color-create-account-form-error-red; } .CreateAccountView__inputBox:focus { // Foundation Overrides From c098331f99ccb05d77d27797e6e7c1a7dafdc84a Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 16:07:39 -0500 Subject: [PATCH 19/35] Add signed in view --- _locales/en/messages.json | 3 ++ .../BrowserCreateAccountForm.jsx | 1 - .../BrowserCreateAccountView.jsx | 17 +++++-- .../BrowserCreateAccountView.scss | 51 +++++++++++++++++-- .../Views/BrowserCreateAccountView/index.js | 34 ++++++++++++- 5 files changed, 97 insertions(+), 9 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 042a27e53..9a7be6717 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1791,6 +1791,9 @@ "hub_browser_create_an_account": { "message": "Create an account." }, + "hub_browser_you_are_signed_in_as": { + "message": "You are signed in as" + }, "enable_when_paused": { "message": "To use this function, Resume Ghostery." }, diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx index e258cb7c1..6c8238ff3 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx @@ -237,7 +237,6 @@ BrowserCreateAccountForm.propTypes = { firstName: PropTypes.string.isRequired, lastName: PropTypes.string.isRequired, isUpdatesChecked: PropTypes.bool.isRequired, - isUpdatesNotCheckedError: PropTypes.bool.isRequired, password: PropTypes.string.isRequired, confirmPassword: PropTypes.string.isRequired, passwordInvalidError: PropTypes.bool.isRequired, diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 3e09aed02..64061cd4e 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -69,7 +69,10 @@ const renderFAQListItem = (icon, label, description) => ( * @return {JSX} JSX for rendering the Browser Create Account View of the Hub app * @memberof HubComponents */ -const BrowserCreateAccountView = () => { +const BrowserCreateAccountView = (props) => { + const { user } = props; + const email = user && user.email; + const [expanded, setExpanded] = useState(false); const [view, setView] = useState(SIGN_IN); @@ -88,7 +91,15 @@ const BrowserCreateAccountView = () => { setExpanded(!expanded); }; - return ( + return (user ? ( +
+
{t('hub_browser_you_are_signed_in_as')}
+
{user.email}
+
+ +
+
+ ) : (
{view === CREATE_ACCOUNT && (
{t('hub_browser_create_a_ghostery_account')}
@@ -136,7 +147,7 @@ const BrowserCreateAccountView = () => { )}
- ); + )); }; export default BrowserCreateAccountView; diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index ab57c1de0..5608b6c34 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -14,6 +14,53 @@ $color-create-account-form-error-red: #e74055; // Browser Create Account View +.BrowserCreateAccountView { + padding-top: 80px; + padding-bottom: 40px; +} +.BrowserCreateAccountView__alreadySignedIn { + margin-top: 245px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.BrowserCreateAccountView__email { + font-size: 24px; + color: $ghosty-blue; +} +.BrowserCreateAccountView__ctaButtonContainer { + display: flex; + justify-content: center; + + .BrowserCreateAccountView__ctaButton { + margin: 48px auto 0 auto; + height: 44px; + width: 162px; + padding: 7.7px 14px; + line-height: 22px; + background: linear-gradient( + 45deg, + #ff7e74 50%, + #00aef0 + ); + background-size: 200% 100%; + background-position: 100% 50%; + transition: 0.25s all; + border: none; + &:hover { + background-position: 0% 50%; + transition: 0.25s all; + } + color: #FFF; + font-size: 14.1px; + font-weight: 700; + border-radius: 3.5px; + text-align: center; + line-height: 2.05; + cursor: pointer; + } +} .BrowserCreateAccountView__title { display: flex; justify-content: center; @@ -33,10 +80,6 @@ $color-create-account-form-error-red: #e74055; text-decoration: underline; cursor: pointer; } -.BrowserCreateAccountView { - padding-top: 80px; - padding-bottom: 40px; -} .BrowserCreateAccountView--addMarginSide { margin-left: 10px; margin-right: 10px; diff --git a/app/hub/Views/BrowserCreateAccountView/index.js b/app/hub/Views/BrowserCreateAccountView/index.js index ea8b89431..5c27b6d79 100644 --- a/app/hub/Views/BrowserCreateAccountView/index.js +++ b/app/hub/Views/BrowserCreateAccountView/index.js @@ -1,3 +1,35 @@ +/** + * Point of entry index.js file for UpgradePlanView + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2020 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom'; + import BrowserCreateAccountView from './BrowserCreateAccountView'; -export default BrowserCreateAccountView; +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => ({ ...state.account }); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof SetupContainers + */ +const mapDispatchToProps = dispatch => ({}); + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(BrowserCreateAccountView)); From 1087c465153960d37e81762daa4ad589010b1e52 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 16:58:00 -0500 Subject: [PATCH 20/35] Change spacing of title and subtitle for small screens --- .../BrowserCreateAccountView.jsx | 6 +++--- .../BrowserCreateAccountView.scss | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 64061cd4e..c6ceda454 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -22,7 +22,6 @@ import globals from '../../../../src/classes/Globals'; const SIGN_IN = 'SIGN_IN'; const CREATE_ACCOUNT = 'CREATE_ACCOUNT'; -const ALREADY_SIGNED_IN = 'ALREADRY_SALREADY_SIGNED_IN'; const faqList = [ { @@ -74,7 +73,7 @@ const BrowserCreateAccountView = (props) => { const email = user && user.email; const [expanded, setExpanded] = useState(false); - const [view, setView] = useState(SIGN_IN); + const [view, setView] = useState(CREATE_ACCOUNT); const arrowClassNames = ClassNames('BrowserCreateAccountView__arrow', { up: expanded, @@ -94,8 +93,9 @@ const BrowserCreateAccountView = (props) => { return (user ? (
{t('hub_browser_you_are_signed_in_as')}
-
{user.email}
+
{email}
+ {/* Link to next page */}
diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index 5608b6c34..b52445bdb 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -66,6 +66,11 @@ $color-create-account-form-error-red: #e74055; justify-content: center; font-size: 24px; font-weight: 600; + @include breakpoint(small down) { + margin: auto; + max-width: 237px; + text-align: center; + } } .BrowserCreateAccountView__subtitle { margin-top: 10px; @@ -73,6 +78,12 @@ $color-create-account-form-error-red: #e74055; justify-content: center; font-size: 18px; text-align: center; + @include breakpoint(small down) { + margin: auto; + max-width: 237px; + text-align: center; + line-height: 2.33; + } } .BrowserCreateAccountView__alreadyHaveAccount { margin-top: 38px; From b8c2629fe1fe2737c79ee7c09f4c30ef960c9a89 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 17:04:55 -0500 Subject: [PATCH 21/35] Update create account design for small screens --- .../BrowserCreateAccountForm.jsx | 20 +++++++++---------- .../BrowserCreateAccountView.scss | 5 +++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx index 6c8238ff3..ac5d90e8d 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx @@ -61,7 +61,7 @@ const BrowserCreateAccountForm = (props) => { return (
-
+
@@ -82,7 +82,7 @@ const BrowserCreateAccountForm = (props) => {
)}
-
+
@@ -104,7 +104,7 @@ const BrowserCreateAccountForm = (props) => {
-
+
@@ -119,7 +119,7 @@ const BrowserCreateAccountForm = (props) => { autoComplete="off" />
-
+
@@ -136,7 +136,7 @@ const BrowserCreateAccountForm = (props) => {
-
+
@@ -161,7 +161,7 @@ const BrowserCreateAccountForm = (props) => {
)}
-
+
@@ -188,7 +188,7 @@ const BrowserCreateAccountForm = (props) => {
-
+
{ />
-
+
-
+
{ />
-
+
diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index b52445bdb..b777b4b55 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -87,9 +87,14 @@ $color-create-account-form-error-red: #e74055; } .BrowserCreateAccountView__alreadyHaveAccount { margin-top: 38px; + font-size: 16px; color: $ghosty-blue; text-decoration: underline; cursor: pointer; + @include breakpoint(small down) { + margin: 38px auto 0 auto; + text-align: center; + } } .BrowserCreateAccountView--addMarginSide { margin-left: 10px; From e1876098c305e10389229be445a008f04d8a41fc Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 17:15:38 -0500 Subject: [PATCH 22/35] Center skip link on small screens --- .../BrowserCreateAccountView.jsx | 21 ++++++++++++------- .../BrowserCreateAccountView.scss | 5 +++++ .../BrowserLoginForm/BrowserLogInForm.jsx | 6 ------ .../BrowserLoginForm/BrowserLogInForm.scss | 1 - 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index c6ceda454..121b5899b 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -63,6 +63,15 @@ const renderFAQListItem = (icon, label, description) => (
); +const renderSkipLink = () => ( +
+
+
+
{t('hub_browser_skip')}
+
+
+); + /** * A Functional React component for rendering the Browser Create Account View * @return {JSX} JSX for rendering the Browser Create Account View of the Hub app @@ -120,12 +129,7 @@ const BrowserCreateAccountView = (props) => { {view === CREATE_ACCOUNT ? ( -
-
-
-
{t('hub_browser_skip')}
-
-
+ {renderSkipLink()}
{t('hub_browser_we_take_your_privacy_very_seriously')}
@@ -144,7 +148,10 @@ const BrowserCreateAccountView = (props) => { )} ) : ( - + + + {renderSkipLink()} + )}
)); diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index b777b4b55..61949ebb7 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -148,6 +148,11 @@ $color-create-account-form-error-red: #e74055; color: $ghosty-blue; text-decoration: underline; cursor: pointer; + @include breakpoint(small down) { + margin: 39px auto 0 auto; + text-align: center; + float: none; + } } .BrowserCreateAccountView__learnMoreContainer { margin: 25px auto 0 auto; diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx index 102ece6f6..cbdc660b0 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.jsx @@ -97,12 +97,6 @@ const BrowserLogInForm = (props) => {
-
-
-
-
{t('hub_browser_skip')}
-
-
); }; diff --git a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss index 2f8003841..de0980f42 100644 --- a/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss +++ b/app/hub/Views/BrowserLoginForm/BrowserLogInForm.scss @@ -14,7 +14,6 @@ // Log In Form .BrowserLogInForm { margin-top: 40px; - padding-bottom: 40px; } .BrowserLogInForm__headerImage { line-height: 1.5; From a6e92570d7e658a662ce815eebb701de6c98ca00 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 17:38:23 -0500 Subject: [PATCH 23/35] Decrease spacing for small sreens on already have account/create account link --- .../BrowserCreateAccountView/BrowserCreateAccountView.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index 61949ebb7..c38d26ba8 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -94,6 +94,10 @@ $color-create-account-form-error-red: #e74055; @include breakpoint(small down) { margin: 38px auto 0 auto; text-align: center; + + &:nth-child(2) { + margin: 0; + } } } .BrowserCreateAccountView--addMarginSide { From f715cf7ac5047fc0d4bbc87c995aa5dedc3094a8 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 17:44:27 -0500 Subject: [PATCH 24/35] Decrease width of faqDescription items and privacy policy link --- .../BrowserCreateAccountView/BrowserCreateAccountView.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss index c38d26ba8..a9031859a 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss @@ -221,6 +221,10 @@ $color-create-account-form-error-red: #e74055; max-width: 607px; font-size: 16px; color: #4a4a4a; + @include breakpoint(small down) { + margin: 16px auto 0 auto; + width: 245px; + } } .BrowserCreateAccountView__privacyPolicyLink { font-size: 16px; @@ -228,6 +232,8 @@ $color-create-account-form-error-red: #e74055; text-decoration: underline; cursor: pointer; @include breakpoint(small down) { + margin: auto; + max-width: 271px; text-align: center; } } From 8b6838dee7e49948cf76f9f57d395b34ee22843e Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 2 Dec 2020 17:47:16 -0500 Subject: [PATCH 25/35] Open privacy policy link in new tab --- .../Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index 121b5899b..f630b837b 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -141,7 +141,7 @@ const BrowserCreateAccountView = (props) => {
{expanded && ( From 817ce0b2a1a4707fa3eb85eb27a9f25d7cb1091c Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 4 Dec 2020 14:02:38 -0500 Subject: [PATCH 26/35] Add confirm password functionality --- _locales/en/messages.json | 3 +++ app/Account/AccountActions.js | 10 +++++++- app/Account/AccountConstants.js | 3 +++ app/Account/AccountReducer.js | 15 +++++++++++- .../BrowserCreateAccountForm.jsx | 15 +++++------- .../BrowserCreateAccountFormContainer.jsx | 24 +++++++++++++++++-- .../Views/BrowserCreateAccountForm/index.js | 5 ++-- .../BrowserCreateAccountView.jsx | 1 - app/panel/utils/utils.js | 14 +++++++++++ 9 files changed, 74 insertions(+), 16 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 9a7be6717..108478644 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1722,6 +1722,9 @@ "hub_create_account_label_password_invalid_length": { "message": "Use between 8 and 50 characters." }, + "hub_create_account_confirm_password_do_not_match": { + "message": "Passwords do not match." + }, "hub_create_account_already_have_account": { "message": "Already have a Ghostery Account?" }, diff --git a/app/Account/AccountActions.js b/app/Account/AccountActions.js index 4114a025b..c51317dec 100644 --- a/app/Account/AccountActions.js +++ b/app/Account/AccountActions.js @@ -27,7 +27,8 @@ import { GET_USER_SETTINGS_SUCCESS, GET_USER_SETTINGS_FAIL, GET_USER_SUBSCRIPTION_DATA_FAIL, - GET_USER_SUBSCRIPTION_DATA_SUCCESS + GET_USER_SUBSCRIPTION_DATA_SUCCESS, + ACCOUNT_DATA_EMAIL_PREFERENCES_CHECKBOX_CHANGE } from './AccountConstants'; import { SET_TOAST } from '../hub/Views/AppView/AppViewConstants'; import { CLEAR_THEME } from '../panel/constants/constants'; @@ -201,3 +202,10 @@ export const resetPassword = email => dispatch => ( }); }) ); + +export const handleEmailPreferencesCheckboxChange = (name, checked) => dispatch => ( + dispatch({ + type: ACCOUNT_DATA_EMAIL_PREFERENCES_CHECKBOX_CHANGE, + payload: { name, checked }, + }) +); diff --git a/app/Account/AccountConstants.js b/app/Account/AccountConstants.js index 64eb24a63..0f95a09c4 100644 --- a/app/Account/AccountConstants.js +++ b/app/Account/AccountConstants.js @@ -36,3 +36,6 @@ export const GET_USER_SETTINGS_FAIL = 'GET_USER_SETTINGS_FAIL'; // Update Subscription Data export const GET_USER_SUBSCRIPTION_DATA_FAIL = 'GET_USER_SUBSCRIPTION_DATA_FAIL'; export const GET_USER_SUBSCRIPTION_DATA_SUCCESS = 'GET_USER_SUBSCRIPTION_DATA_SUCCESS'; + +// Opt into/out of updates and promotions sendgrid emails +export const ACCOUNT_DATA_EMAIL_PREFERENCES_CHECKBOX_CHANGE = 'ACCOUNT_DATA_EMAIL_PREFERENCES_CHECKBOX_CHANGE'; diff --git a/app/Account/AccountReducer.js b/app/Account/AccountReducer.js index ebc31da25..db459b8e2 100644 --- a/app/Account/AccountReducer.js +++ b/app/Account/AccountReducer.js @@ -20,7 +20,8 @@ import { GET_USER_SUBSCRIPTION_DATA_FAIL, GET_USER_SUBSCRIPTION_DATA_SUCCESS, RESET_PASSWORD_SUCCESS, - RESET_PASSWORD_FAIL + RESET_PASSWORD_FAIL, + ACCOUNT_DATA_EMAIL_PREFERENCES_CHECKBOX_CHANGE } from './AccountConstants'; import { UPDATE_PANEL_DATA } from '../panel/constants/constants'; @@ -118,6 +119,18 @@ export default (state = initialState, action) => { resetPasswordError: true }; } + case ACCOUNT_DATA_EMAIL_PREFERENCES_CHECKBOX_CHANGE: { + console.log('test'); + const { name, checked } = action.payload; + let emailPreferences; + if (name === 'global') { + console.log('inside global'); + emailPreferences = { ...state.user.emailPreferences, ...{ global: checked } }; + } + const user = { ...state.user, ...{ emailPreferences } }; + console.log('state user: ', { ...state, ...{ user } }); + return { ...state, ...{ user } }; + } default: return state; } diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx index ac5d90e8d..7b19fa911 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx @@ -33,9 +33,10 @@ const BrowserCreateAccountForm = (props) => { firstName, lastName, password, - confirmPassword, passwordInvalidError, passwordLengthError, + confirmPassword, + confirmPasswordError, legalConsentChecked, legalConsentNotCheckedError, handleLegalConsentCheckboxChange, @@ -168,21 +169,16 @@ const BrowserCreateAccountForm = (props) => { - {passwordInvalidError && ( + {confirmPasswordError && (
- {t('hub_create_account_label_password_invalid')} -
- )} - {passwordLengthError && ( -
- {t('hub_create_account_label_password_invalid_length')} + {t('hub_create_account_confirm_password_do_not_match')}
)}
@@ -208,6 +204,7 @@ const BrowserCreateAccountForm = (props) => {
= 8 && password.length <= 50; const invalidLength = !passwordIsValid && !invalidChars; + const confirmPasswordError = password !== confirmPassword; this.setState({ emailError: !emailIsValid, @@ -138,7 +152,8 @@ class CreateAccountFormContainer extends Component { validateInput: true, }); - if (!emailIsValid || !confirmIsValid || !legalConsentChecked || !passwordIsValid) { + if (!emailIsValid || !confirmIsValid || !legalConsentChecked || !passwordIsValid || confirmPasswordError) { + console.log('password != confirm password'); return; } const { actions } = this.props; @@ -155,6 +170,7 @@ class CreateAccountFormContainer extends Component { toastClass: 'success' }); // Route to next screen + if (isUpdatesChecked) actions.handleEmailPreferencesCheckboxChange(); } else { actions.setToast({ toastMessage: t('hub_create_account_toast_error'), @@ -183,6 +199,8 @@ class CreateAccountFormContainer extends Component { password, passwordInvalidError, passwordLengthError, + confirmPassword, + confirmPasswordError } = this.state; return ( @@ -198,6 +216,8 @@ class CreateAccountFormContainer extends Component { password={password} passwordInvalidError={passwordInvalidError} passwordLengthError={passwordLengthError} + confirmPassword={confirmPassword} + confirmPasswordError={confirmPasswordError} handleInputChange={this._handleInputChange} handleLegalConsentCheckboxChange={this._handleLegalConsentCheckboxChange} handleSubmit={this._handleCreateAccountAttempt} diff --git a/app/hub/Views/BrowserCreateAccountForm/index.js b/app/hub/Views/BrowserCreateAccountForm/index.js index 977335a49..19f3edd71 100644 --- a/app/hub/Views/BrowserCreateAccountForm/index.js +++ b/app/hub/Views/BrowserCreateAccountForm/index.js @@ -15,7 +15,7 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import BrowserCreateAccountFormContainer from './BrowserCreateAccountFormContainer'; -import { register, getUser } from '../../../Account/AccountActions'; +import { register, getUser, handleEmailPreferencesCheckboxChange } from '../../../Account/AccountActions'; import { setToast } from '../AppView/AppViewActions'; /** @@ -36,7 +36,8 @@ const mapDispatchToProps = dispatch => ({ actions: bindActionCreators({ setToast, register, - getUser + getUser, + handleEmailPreferencesCheckboxChange }, dispatch), }); diff --git a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx index f630b837b..e3c744231 100644 --- a/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx +++ b/app/hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx @@ -15,7 +15,6 @@ import React, { Fragment, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import ClassNames from 'classnames'; import { NavLink } from 'react-router-dom'; -import { ToggleCheckbox } from '../../../shared-components'; import BrowserLogInForm from '../BrowserLoginForm'; import BrowserCreateAccountForm from '../BrowserCreateAccountForm'; import globals from '../../../../src/classes/Globals'; diff --git a/app/panel/utils/utils.js b/app/panel/utils/utils.js index ce438df33..632d2e1ac 100644 --- a/app/panel/utils/utils.js +++ b/app/panel/utils/utils.js @@ -165,6 +165,20 @@ export function validatePassword(pwd) { return pwd !== '' && pwdRegex.test(pwd); } +/** + * Check for confirm password equality to password + * @memberOf PanelUtils + * @param {string} password password + * @param {string} confirmPassword confirm password to validate + * @return {boolean} true if equal, false otherwise + */ +export function validatePasswordsMatch(password, confirmPassword) { + if (!password || !confirmPassword) { + return false; + } + return password === confirmPassword; +} + /** * Helper method for making XHR requests * @memberOf PanelUtils From dfc6ec9b4a9a4c2854cdba0916b01f5baa1c7591 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 4 Dec 2020 14:16:28 -0500 Subject: [PATCH 27/35] Update passwords not match string --- _locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 108478644..59766a12b 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1723,7 +1723,7 @@ "message": "Use between 8 and 50 characters." }, "hub_create_account_confirm_password_do_not_match": { - "message": "Passwords do not match." + "message": "Your passwords do not match." }, "hub_create_account_already_have_account": { "message": "Already have a Ghostery Account?" From 7ff259f4db8b6f500ea29124dbc8d7ddbe57de2d Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 4 Dec 2020 14:31:28 -0500 Subject: [PATCH 28/35] Add global email preferences to user object on account creation success --- app/Account/AccountReducer.js | 3 --- .../BrowserCreateAccountFormContainer.jsx | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/Account/AccountReducer.js b/app/Account/AccountReducer.js index db459b8e2..0a91127a1 100644 --- a/app/Account/AccountReducer.js +++ b/app/Account/AccountReducer.js @@ -120,15 +120,12 @@ export default (state = initialState, action) => { }; } case ACCOUNT_DATA_EMAIL_PREFERENCES_CHECKBOX_CHANGE: { - console.log('test'); const { name, checked } = action.payload; let emailPreferences; if (name === 'global') { - console.log('inside global'); emailPreferences = { ...state.user.emailPreferences, ...{ global: checked } }; } const user = { ...state.user, ...{ emailPreferences } }; - console.log('state user: ', { ...state, ...{ user } }); return { ...state, ...{ user } }; } diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx index ef7e83447..4bdbb3b35 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx @@ -153,7 +153,6 @@ class CreateAccountFormContainer extends Component { }); if (!emailIsValid || !confirmIsValid || !legalConsentChecked || !passwordIsValid || confirmPasswordError) { - console.log('password != confirm password'); return; } const { actions } = this.props; @@ -163,14 +162,15 @@ class CreateAccountFormContainer extends Component { }); actions.register(email, confirmEmail, firstName, lastName, password).then((success) => { if (success) { - actions.getUser(); + actions.getUser().then(() => { + if (isUpdatesChecked) actions.handleEmailPreferencesCheckboxChange('global', isUpdatesChecked); + }); // Toggle legal consent checked here actions.setToast({ toastMessage: t('hub_create_account_toast_success'), toastClass: 'success' }); // Route to next screen - if (isUpdatesChecked) actions.handleEmailPreferencesCheckboxChange(); } else { actions.setToast({ toastMessage: t('hub_create_account_toast_error'), From 143cce8defb44577beb610259a4b61813ef7f57e Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 4 Dec 2020 16:11:37 -0500 Subject: [PATCH 29/35] Hold input fields in place when error messages appear --- .../BrowserCreateAccountForm.jsx | 30 ++++++++++++------- .../BrowserCreateAccountForm.scss | 12 ++++++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx index 7b19fa911..8ca0357e7 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx @@ -78,8 +78,10 @@ const BrowserCreateAccountForm = (props) => { placeholder="example@mail.com" /> {emailError && ( -
- {t('please_enter_a_valid_email')} +
+
+ {t('please_enter_a_valid_email')} +
)}
@@ -98,8 +100,10 @@ const BrowserCreateAccountForm = (props) => { autoComplete="off" /> {confirmEmailError && ( -
- {t('your_email_do_not_match')} +
+
+ {t('your_email_do_not_match')} +
)}
@@ -152,13 +156,17 @@ const BrowserCreateAccountForm = (props) => { autoComplete="off" /> {passwordInvalidError && ( -
- {t('hub_create_account_label_password_invalid')} +
+
+ {t('hub_create_account_label_password_invalid')} +
)} {passwordLengthError && ( -
- {t('hub_create_account_label_password_invalid_length')} +
+
+ {t('hub_create_account_label_password_invalid_length')} +
)}
@@ -177,8 +185,10 @@ const BrowserCreateAccountForm = (props) => { autoComplete="off" /> {confirmPasswordError && ( -
- {t('hub_create_account_confirm_password_do_not_match')} +
+
+ {t('hub_create_account_confirm_password_do_not_match')} +
)}
diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss index 184de9473..f60adf62b 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss +++ b/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss @@ -9,6 +9,7 @@ color: #4a4a4a; } .BrowserCreateAccountForm__inputBox { + margin-bottom: 20px; font-size: 14; line-height: 24px; color: #4a4a4a; @@ -23,11 +24,16 @@ } } .BrowserCreateAccountForm__inputBox.error { - margin-bottom: 8px; border-color: $color-create-account-form-error-red; } -.BrowserCreateAccountForm__inputError { - color: red; +.BrowserCreateAccountForm__inputErrorContainer { + position: relative; + + > .BrowserCreateAccountForm__inputError { + position: absolute; + margin-top: -15px; + color: red; + } } .BrowserCreateAccountForm__promoString { font-size: 14px; From eda38ca844c677d37991db7c4dcbcf3876e77850 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 4 Dec 2020 18:46:38 -0500 Subject: [PATCH 30/35] Rename components --- .../Step1_CreateAccountForm.jsx} | 62 ++++++++-------- .../Step1_CreateAccountForm.scss} | 22 +++--- .../Step1_CreateAccountFormContainer.jsx} | 4 +- .../Step1_CreateAccountForm}/index.js | 4 +- .../Step1_CreateAccountView.jsx} | 52 ++++++------- .../Step1_CreateAccountView.scss} | 74 +++++++++---------- .../Step1_CreateAccountView}/index.js | 4 +- .../Step1_LogInForm/Step1_LogInForm.jsx} | 34 ++++----- .../Step1_LogInForm/Step1_LogInForm.scss} | 29 ++++---- .../Step1_LogInFormContainer.jsx} | 14 ++-- .../OnboardingViews/Step1_LogInForm}/index.js | 4 +- app/hub/index.jsx | 3 +- 12 files changed, 153 insertions(+), 153 deletions(-) rename app/{hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx => ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountForm/Step1_CreateAccountForm.jsx} (72%) rename app/{hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.scss => ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountForm/Step1_CreateAccountForm.scss} (73%) rename app/{hub/Views/BrowserCreateAccountForm/BrowserCreateAccountFormContainer.jsx => ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountForm/Step1_CreateAccountFormContainer.jsx} (98%) rename app/{hub/Views/BrowserCreateAccountForm => ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountForm}/index.js (88%) rename app/{hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.jsx => ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountView/Step1_CreateAccountView.jsx} (56%) rename app/{hub/Views/BrowserCreateAccountView/BrowserCreateAccountView.scss => ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountView/Step1_CreateAccountView.scss} (72%) rename app/{hub/Views/BrowserCreateAccountView => ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountView}/index.js (92%) rename app/{hub/Views/BrowserLoginForm/BrowserLogInForm.jsx => ghostery-browser-hub/Views/OnboardingViews/Step1_LogInForm/Step1_LogInForm.jsx} (67%) rename app/{hub/Views/BrowserLoginForm/BrowserLogInForm.scss => ghostery-browser-hub/Views/OnboardingViews/Step1_LogInForm/Step1_LogInForm.scss} (79%) rename app/{hub/Views/BrowserLoginForm/BrowserLogInFormContainer.jsx => ghostery-browser-hub/Views/OnboardingViews/Step1_LogInForm/Step1_LogInFormContainer.jsx} (92%) rename app/{hub/Views/BrowserLoginForm => ghostery-browser-hub/Views/OnboardingViews/Step1_LogInForm}/index.js (90%) diff --git a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx b/app/ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountForm/Step1_CreateAccountForm.jsx similarity index 72% rename from app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx rename to app/ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountForm/Step1_CreateAccountForm.jsx index c69d476e0..7fc195b9e 100644 --- a/app/hub/Views/BrowserCreateAccountForm/BrowserCreateAccountForm.jsx +++ b/app/ghostery-browser-hub/Views/OnboardingViews/Step1_CreateAccountForm/Step1_CreateAccountForm.jsx @@ -24,7 +24,7 @@ const promoString = `${t('ghostery_browser_hub_onboarding_send_me')} Ghostery ${ * @return {JSX} JSX for rendering the Browser Create Account View of the Hub app * @memberof HubComponents */ -const BrowserCreateAccountForm = (props) => { +const Step1_CreateAccountForm = (props) => { const { email, emailError, @@ -46,24 +46,24 @@ const BrowserCreateAccountForm = (props) => { handleSubmit, } = props; - const emailInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { + const emailInputClassNames = ClassNames('Step1_CreateAccountForm__inputBox', { error: emailError, }); - const confirmInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { + const confirmInputClassNames = ClassNames('Step1_CreateAccountForm__inputBox', { error: confirmEmailError, }); - const passwordInputClassNames = ClassNames('BrowserCreateAccountForm__inputBox', { + const passwordInputClassNames = ClassNames('Step1_CreateAccountForm__inputBox', { error: passwordInvalidError || passwordLengthError, }); - const legalConsentClassNames = ClassNames('BrowserCreateAccountForm__legalConsentCheckedLabel', { + const legalConsentClassNames = ClassNames('Step1_CreateAccountForm__legalConsentCheckedLabel', { error: legalConsentNotCheckedError }); return (
-
+
-