From c0e9b92a3ae486b853600f3729e3b124c07db60f Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Wed, 10 Jan 2018 21:41:51 -0800 Subject: [PATCH 01/16] Added phone verification option --- src/renderer/component/userVerify/view.jsx | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/renderer/component/userVerify/view.jsx b/src/renderer/component/userVerify/view.jsx index 07cadba99..424682013 100644 --- a/src/renderer/component/userVerify/view.jsx +++ b/src/renderer/component/userVerify/view.jsx @@ -66,7 +66,29 @@ class UserVerify extends React.PureComponent {
-

{__('2) Proof via YouTube')}

+

{__('2) Proof via Phone')}

+
+
+ {`${__( + 'You will receive an SMS text message confirming that your phone number is correct.' + )}`} +
+
+ {errorMessage &&

{errorMessage}

} + +
+
+
{__('Standard messaging rates apply.')}
+
+
+
+
+

{__('3) Proof via YouTube')}

@@ -96,7 +118,7 @@ class UserVerify extends React.PureComponent {

-

{__('3) Proof via Chat')}

+

{__('4) Proof via Chat')}

From c52c75758bafaaf9bf80a5ef5719884bfdb2b009 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Wed, 10 Jan 2018 22:00:51 -0800 Subject: [PATCH 02/16] Rename modalEmailCollection to modalPhoneCollection --- .../{modalEmailCollection => modalPhoneCollection}/index.js | 4 ++-- .../{modalEmailCollection => modalPhoneCollection}/view.jsx | 4 ++-- src/renderer/modal/modalRouter/view.jsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename src/renderer/modal/{modalEmailCollection => modalPhoneCollection}/index.js (84%) rename src/renderer/modal/{modalEmailCollection => modalPhoneCollection}/view.jsx (91%) diff --git a/src/renderer/modal/modalEmailCollection/index.js b/src/renderer/modal/modalPhoneCollection/index.js similarity index 84% rename from src/renderer/modal/modalEmailCollection/index.js rename to src/renderer/modal/modalPhoneCollection/index.js index 242b9e509..aae6952f7 100644 --- a/src/renderer/modal/modalEmailCollection/index.js +++ b/src/renderer/modal/modalPhoneCollection/index.js @@ -4,7 +4,7 @@ import { connect } from 'react-redux'; import { doCloseModal } from 'redux/actions/app'; import { doSetClientSetting } from 'redux/actions/settings'; import { selectEmailToVerify, selectUser } from 'redux/selectors/user'; -import ModalEmailCollection from './view'; +import ModalPhoneCollection from './view'; const select = state => ({ email: selectEmailToVerify(state), @@ -18,4 +18,4 @@ const perform = dispatch => () => ({ }, }); -export default connect(select, perform)(ModalEmailCollection); +export default connect(select, perform)(ModalPhoneCollection); diff --git a/src/renderer/modal/modalEmailCollection/view.jsx b/src/renderer/modal/modalPhoneCollection/view.jsx similarity index 91% rename from src/renderer/modal/modalEmailCollection/view.jsx rename to src/renderer/modal/modalPhoneCollection/view.jsx index a17ecf7df..16b8cbe08 100644 --- a/src/renderer/modal/modalEmailCollection/view.jsx +++ b/src/renderer/modal/modalPhoneCollection/view.jsx @@ -4,7 +4,7 @@ import Link from 'component/link/index'; import UserEmailNew from 'component/userEmailNew'; import UserEmailVerify from 'component/userEmailVerify'; -class ModalEmailCollection extends React.PureComponent { +class ModalPhoneCollection extends React.PureComponent { renderInner() { const { closeModal, email, user } = this.props; @@ -37,4 +37,4 @@ class ModalEmailCollection extends React.PureComponent { } } -export default ModalEmailCollection; +export default ModalPhoneCollection; diff --git a/src/renderer/modal/modalRouter/view.jsx b/src/renderer/modal/modalRouter/view.jsx index b2d68fbf2..019a799fe 100644 --- a/src/renderer/modal/modalRouter/view.jsx +++ b/src/renderer/modal/modalRouter/view.jsx @@ -12,7 +12,7 @@ import ModalTransactionFailed from 'modal/modalTransactionFailed'; import ModalFileTimeout from 'modal/modalFileTimeout'; import ModalAffirmPurchase from 'modal/modalAffirmPurchase'; import ModalRevokeClaim from 'modal/modalRevokeClaim'; -import ModalEmailCollection from '../modalEmailCollection'; +import ModalPhoneCollection from '../modalPhoneCollection'; import * as modals from 'constants/modal_types'; class ModalRouter extends React.PureComponent { @@ -125,7 +125,7 @@ class ModalRouter extends React.PureComponent { case modals.CONFIRM_CLAIM_REVOKE: return ; case modals.EMAIL_COLLECTION: - return ; + return ; default: return null; } From b9b7af2bbd543f4bfd98a4dec1f2a821cdcb85eb Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Wed, 10 Jan 2018 22:16:03 -0800 Subject: [PATCH 03/16] Renamed userEmail... to userField... --- .../{userEmailNew => userFieldNew}/index.js | 8 ++++---- .../{userEmailNew => userFieldNew}/view.jsx | 4 ++-- .../{userEmailVerify => userFieldVerify}/index.js | 10 +++++----- .../{userEmailVerify => userFieldVerify}/view.jsx | 4 ++-- src/renderer/index.js | 4 ++-- src/renderer/modal/modalPhoneCollection/view.jsx | 12 ++++++------ src/renderer/page/auth/view.jsx | 8 ++++---- src/renderer/redux/actions/user.js | 8 ++++---- 8 files changed, 29 insertions(+), 29 deletions(-) rename src/renderer/component/{userEmailNew => userFieldNew}/index.js (60%) rename src/renderer/component/{userEmailNew => userFieldNew}/view.jsx (94%) rename src/renderer/component/{userEmailVerify => userFieldVerify}/index.js (61%) rename src/renderer/component/{userEmailVerify => userFieldVerify}/view.jsx (95%) diff --git a/src/renderer/component/userEmailNew/index.js b/src/renderer/component/userFieldNew/index.js similarity index 60% rename from src/renderer/component/userEmailNew/index.js rename to src/renderer/component/userFieldNew/index.js index 0228a4aaa..78c7810be 100644 --- a/src/renderer/component/userEmailNew/index.js +++ b/src/renderer/component/userFieldNew/index.js @@ -1,8 +1,8 @@ import React from 'react'; import { connect } from 'react-redux'; -import { doUserEmailNew, doUserInviteNew } from 'redux/actions/user'; +import { doUserFieldNew, doUserInviteNew } from 'redux/actions/user'; import { selectEmailNewIsPending, selectEmailNewErrorMessage } from 'redux/selectors/user'; -import UserEmailNew from './view'; +import UserFieldNew from './view'; const select = state => ({ isPending: selectEmailNewIsPending(state), @@ -10,7 +10,7 @@ const select = state => ({ }); const perform = dispatch => ({ - addUserEmail: email => dispatch(doUserEmailNew(email)), + addUserEmail: email => dispatch(doUserFieldNew(email)), }); -export default connect(select, perform)(UserEmailNew); +export default connect(select, perform)(UserFieldNew); diff --git a/src/renderer/component/userEmailNew/view.jsx b/src/renderer/component/userFieldNew/view.jsx similarity index 94% rename from src/renderer/component/userEmailNew/view.jsx rename to src/renderer/component/userFieldNew/view.jsx index 661adb611..2dd0fffd6 100644 --- a/src/renderer/component/userEmailNew/view.jsx +++ b/src/renderer/component/userFieldNew/view.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { Form, FormRow, Submit } from 'component/form.js'; -class UserEmailNew extends React.PureComponent { +class UserFieldNew extends React.PureComponent { constructor(props) { super(props); @@ -52,4 +52,4 @@ class UserEmailNew extends React.PureComponent { } } -export default UserEmailNew; +export default UserFieldNew; diff --git a/src/renderer/component/userEmailVerify/index.js b/src/renderer/component/userFieldVerify/index.js similarity index 61% rename from src/renderer/component/userEmailVerify/index.js rename to src/renderer/component/userFieldVerify/index.js index f8c854ca1..677df5b25 100644 --- a/src/renderer/component/userEmailVerify/index.js +++ b/src/renderer/component/userFieldVerify/index.js @@ -1,12 +1,12 @@ import React from 'react'; import { connect } from 'react-redux'; -import { doUserEmailVerify, doUserEmailVerifyFailure } from 'redux/actions/user'; +import { doUserFieldVerify, doUserFieldVerifyFailure } from 'redux/actions/user'; import { selectEmailVerifyIsPending, selectEmailToVerify, selectEmailVerifyErrorMessage, } from 'redux/selectors/user'; -import UserEmailVerify from './view'; +import UserFieldVerify from './view'; const select = state => ({ isPending: selectEmailVerifyIsPending(state), @@ -15,8 +15,8 @@ const select = state => ({ }); const perform = dispatch => ({ - verifyUserEmail: (code, recaptcha) => dispatch(doUserEmailVerify(code, recaptcha)), - verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)), + verifyUserEmail: (code, recaptcha) => dispatch(doUserFieldVerify(code, recaptcha)), + verifyUserEmailFailure: error => dispatch(doUserFieldVerifyFailure(error)), }); -export default connect(select, perform)(UserEmailVerify); +export default connect(select, perform)(UserFieldVerify); diff --git a/src/renderer/component/userEmailVerify/view.jsx b/src/renderer/component/userFieldVerify/view.jsx similarity index 95% rename from src/renderer/component/userEmailVerify/view.jsx rename to src/renderer/component/userFieldVerify/view.jsx index 3304730b9..450571b8e 100644 --- a/src/renderer/component/userEmailVerify/view.jsx +++ b/src/renderer/component/userFieldVerify/view.jsx @@ -2,7 +2,7 @@ import React from 'react'; import Link from 'component/link'; import { Form, FormRow, Submit } from 'component/form.js'; -class UserEmailVerify extends React.PureComponent { +class UserFieldVerify extends React.PureComponent { constructor(props) { super(props); @@ -59,4 +59,4 @@ class UserEmailVerify extends React.PureComponent { } } -export default UserEmailVerify; +export default UserFieldVerify; diff --git a/src/renderer/index.js b/src/renderer/index.js index fd6dcc1f7..8d92c6ba2 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -12,7 +12,7 @@ import { Provider } from 'react-redux'; import { doConditionalAuthNavigate, doDaemonReady, doShowSnackBar } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation'; import { doDownloadLanguages } from 'redux/actions/settings'; -import { doUserEmailVerify } from 'redux/actions/user'; +import { doUserFieldVerify } from 'redux/actions/user'; import 'scss/all.scss'; import store from 'store'; import app from './app'; @@ -35,7 +35,7 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => { } if (verification.token && verification.recaptcha) { app.store.dispatch(doConditionalAuthNavigate(newSession)); - app.store.dispatch(doUserEmailVerify(verification.token, verification.recaptcha)); + app.store.dispatch(doUserFieldVerify(verification.token, verification.recaptcha)); } else { app.store.dispatch(doShowSnackBar({ message: 'Invalid Verification URI' })); } diff --git a/src/renderer/modal/modalPhoneCollection/view.jsx b/src/renderer/modal/modalPhoneCollection/view.jsx index 16b8cbe08..a8b56c844 100644 --- a/src/renderer/modal/modalPhoneCollection/view.jsx +++ b/src/renderer/modal/modalPhoneCollection/view.jsx @@ -1,8 +1,8 @@ import React from 'react'; import { Modal } from 'modal/modal'; import Link from 'component/link/index'; -import UserEmailNew from 'component/userEmailNew'; -import UserEmailVerify from 'component/userEmailVerify'; +import UserFieldNew from 'component/userFieldNew'; +import UserFieldVerify from 'component/userFieldVerify'; class ModalPhoneCollection extends React.PureComponent { renderInner() { @@ -11,9 +11,9 @@ class ModalPhoneCollection extends React.PureComponent { const cancelButton = ; if (!user.has_verified_email && !email) { - return ; + return ; } else if (!user.has_verified_email) { - return ; + return ; } closeModal(); } @@ -27,9 +27,9 @@ class ModalPhoneCollection extends React.PureComponent { } return ( - +

-

Can We Stay In Touch?

+

Verify Your Phone

{this.renderInner()}
diff --git a/src/renderer/page/auth/view.jsx b/src/renderer/page/auth/view.jsx index 423ce8597..908431e26 100644 --- a/src/renderer/page/auth/view.jsx +++ b/src/renderer/page/auth/view.jsx @@ -1,8 +1,8 @@ import React from 'react'; import { BusyMessage } from 'component/common'; import Link from 'component/link'; -import UserEmailNew from 'component/userEmailNew'; -import UserEmailVerify from 'component/userEmailVerify'; +import UserFieldNew from 'component/userFieldNew'; +import UserFieldVerify from 'component/userFieldVerify'; import UserVerify from 'component/userVerify'; export class AuthPage extends React.PureComponent { @@ -45,9 +45,9 @@ export class AuthPage extends React.PureComponent { if (isPending) { return [, true]; } else if (user && !user.has_verified_email && !email) { - return [, true]; + return [, true]; } else if (user && !user.has_verified_email) { - return [, true]; + return [, true]; } else if (user && !user.is_identity_verified) { return [, false]; } diff --git a/src/renderer/redux/actions/user.js b/src/renderer/redux/actions/user.js index 785a45a09..0c289e2ca 100644 --- a/src/renderer/redux/actions/user.js +++ b/src/renderer/redux/actions/user.js @@ -78,7 +78,7 @@ export function doUserFetch() { }; } -export function doUserEmailNew(email) { +export function doUserFieldNew(email) { return dispatch => { dispatch({ type: ACTIONS.USER_EMAIL_NEW_STARTED, @@ -116,14 +116,14 @@ export function doUserEmailNew(email) { }; } -export function doUserEmailVerifyFailure(error) { +export function doUserFieldVerifyFailure(error) { return { type: ACTIONS.USER_EMAIL_VERIFY_FAILURE, data: { error }, }; } -export function doUserEmailVerify(verificationToken, recaptcha) { +export function doUserFieldVerify(verificationToken, recaptcha) { return (dispatch, getState) => { const email = selectEmailToVerify(getState()); @@ -154,7 +154,7 @@ export function doUserEmailVerify(verificationToken, recaptcha) { throw new Error('Your email is still not verified.'); // shouldn't happen } }) - .catch(error => dispatch(doUserEmailVerifyFailure(error))); + .catch(error => dispatch(doUserFieldVerifyFailure(error))); }; } From 4409315353be7bc89ad5a79de070a1476cf7de4f Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Mon, 15 Jan 2018 05:32:01 -0800 Subject: [PATCH 04/16] Added phone verification functionality --- src/renderer/component/userFieldNew/index.js | 5 +- src/renderer/component/userFieldNew/view.jsx | 47 ++++++++++-- .../component/userFieldVerify/index.js | 9 ++- .../component/userFieldVerify/view.jsx | 19 +++-- src/renderer/component/userVerify/index.js | 5 ++ src/renderer/component/userVerify/view.jsx | 13 ++-- src/renderer/constants/action_types.js | 8 ++ src/renderer/constants/modal_types.js | 2 +- src/renderer/index.js | 4 +- .../modal/modalPhoneCollection/index.js | 7 +- .../modal/modalPhoneCollection/view.jsx | 10 +-- src/renderer/modal/modalRouter/view.jsx | 23 ++---- src/renderer/redux/actions/user.js | 75 +++++++++++++++++-- src/renderer/redux/reducers/user.js | 46 ++++++++++++ src/renderer/redux/selectors/user.js | 11 +++ 15 files changed, 225 insertions(+), 59 deletions(-) diff --git a/src/renderer/component/userFieldNew/index.js b/src/renderer/component/userFieldNew/index.js index 78c7810be..477a383e1 100644 --- a/src/renderer/component/userFieldNew/index.js +++ b/src/renderer/component/userFieldNew/index.js @@ -1,6 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; -import { doUserFieldNew, doUserInviteNew } from 'redux/actions/user'; +import { doUserEmailNew, doUserPhoneNew, doUserInviteNew } from 'redux/actions/user'; import { selectEmailNewIsPending, selectEmailNewErrorMessage } from 'redux/selectors/user'; import UserFieldNew from './view'; @@ -10,7 +10,8 @@ const select = state => ({ }); const perform = dispatch => ({ - addUserEmail: email => dispatch(doUserFieldNew(email)), + addUserEmail: email => dispatch(doUserEmailNew(email)), + addUserPhone: phone => dispatch(doUserPhoneNew(phone)), }); export default connect(select, perform)(UserFieldNew); diff --git a/src/renderer/component/userFieldNew/view.jsx b/src/renderer/component/userFieldNew/view.jsx index 2dd0fffd6..6cd29679a 100644 --- a/src/renderer/component/userFieldNew/view.jsx +++ b/src/renderer/component/userFieldNew/view.jsx @@ -6,25 +6,58 @@ class UserFieldNew extends React.PureComponent { super(props); this.state = { + phone: '', email: '', }; } - handleEmailChanged(event) { + handleChanged(event, fieldType) { + console.log({ + [fieldType]: event.target.value, + }); this.setState({ - email: event.target.value, + [fieldType]: event.target.value, }); } handleSubmit() { - const { email } = this.state; - this.props.addUserEmail(email); + const { email, phone } = this.state; + if (phone) { + this.props.addUserPhone(phone); + } else { + this.props.addUserEmail(email); + } } render() { - const { cancelButton, errorMessage, isPending } = this.props; + const { cancelButton, errorMessage, isPending, fieldType } = this.props; - return ( + return fieldType === 'phone' ? ( +
+

+ {__( + 'Enter your phone number and we will send you a verification code. We will not share your phone number with third parties.' + )} +

+
+ { + this.handleChanged(event, 'phone'); + }} + /> +
+ + {cancelButton} +
+ +
+ ) : (

{__("We'll let you know about LBRY updates, security issues, and great new content.")} @@ -39,7 +72,7 @@ class UserFieldNew extends React.PureComponent { value={this.state.email} errorMessage={errorMessage} onChange={event => { - this.handleEmailChanged(event); + this.handleChanged(event, 'email'); }} />

diff --git a/src/renderer/component/userFieldVerify/index.js b/src/renderer/component/userFieldVerify/index.js index 677df5b25..a8fab1120 100644 --- a/src/renderer/component/userFieldVerify/index.js +++ b/src/renderer/component/userFieldVerify/index.js @@ -1,9 +1,10 @@ import React from 'react'; import { connect } from 'react-redux'; -import { doUserFieldVerify, doUserFieldVerifyFailure } from 'redux/actions/user'; +import { doUserEmailVerify, doUserPhoneVerify, doUserEmailVerifyFailure } from 'redux/actions/user'; import { selectEmailVerifyIsPending, selectEmailToVerify, + selectPhoneToVerify, selectEmailVerifyErrorMessage, } from 'redux/selectors/user'; import UserFieldVerify from './view'; @@ -11,12 +12,14 @@ import UserFieldVerify from './view'; const select = state => ({ isPending: selectEmailVerifyIsPending(state), email: selectEmailToVerify(state), + phone: selectPhoneToVerify(state), errorMessage: selectEmailVerifyErrorMessage(state), }); const perform = dispatch => ({ - verifyUserEmail: (code, recaptcha) => dispatch(doUserFieldVerify(code, recaptcha)), - verifyUserEmailFailure: error => dispatch(doUserFieldVerifyFailure(error)), + verifyUserEmail: (code, recaptcha) => dispatch(doUserEmailVerify(code, recaptcha)), + verifyUserPhone: code => dispatch(doUserPhoneVerify(code)), + verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)), }); export default connect(select, perform)(UserFieldVerify); diff --git a/src/renderer/component/userFieldVerify/view.jsx b/src/renderer/component/userFieldVerify/view.jsx index 450571b8e..0bd2e3a03 100644 --- a/src/renderer/component/userFieldVerify/view.jsx +++ b/src/renderer/component/userFieldVerify/view.jsx @@ -19,19 +19,24 @@ class UserFieldVerify extends React.PureComponent { handleSubmit() { const { code } = this.state; - try { - const verification = JSON.parse(atob(code)); - this.props.verifyUserEmail(verification.token, verification.recaptcha); - } catch (error) { - this.props.verifyUserEmailFailure('Invalid Verification Token'); + const { fieldType } = this.props; + if (fieldType === 'phone') { + this.props.verifyUserPhone(code); + } else { + try { + const verification = JSON.parse(atob(code)); + this.props.verifyUserEmail(verification.token, verification.recaptcha); + } catch (error) { + this.props.verifyUserEmailFailure('Invalid Verification Token'); + } } } render() { - const { cancelButton, errorMessage, email, isPending } = this.props; + const { cancelButton, errorMessage, email, isPending, phone } = this.props; return (
-

Please enter the verification code emailed to {email}.

+

Please enter the verification code sent to {phone || email}.

{ const selectReward = makeSelectRewardByType(); @@ -17,12 +20,14 @@ const select = (state, props) => { isPending: selectIdentityVerifyIsPending(state), errorMessage: selectIdentityVerifyErrorMessage(state), reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }), + modal: selectCurrentModal(state), }; }; const perform = dispatch => ({ navigate: uri => dispatch(doNavigate(uri)), verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)), + verifyPhone: () => dispatch(doOpenModal(PHONE_COLLECTION)), }); export default connect(select, perform)(UserVerify); diff --git a/src/renderer/component/userVerify/view.jsx b/src/renderer/component/userVerify/view.jsx index 424682013..5aa05948e 100644 --- a/src/renderer/component/userVerify/view.jsx +++ b/src/renderer/component/userVerify/view.jsx @@ -23,7 +23,7 @@ class UserVerify extends React.PureComponent { } render() { - const { errorMessage, isPending, navigate } = this.props; + const { errorMessage, isPending, navigate, verifyPhone, modal } = this.props; return (
@@ -74,12 +74,13 @@ class UserVerify extends React.PureComponent { )}`}
- {errorMessage &&

{errorMessage}

} - { + verifyPhone(); + }} + button="alt" + icon="icon-phone" label={__('Submit Phone Number')} - disabled={isPending} - token={this.onToken.bind(this)} - stripeKey={lbryio.getStripeToken()} />
diff --git a/src/renderer/constants/action_types.js b/src/renderer/constants/action_types.js index 3c828f5cb..6e0f40344 100644 --- a/src/renderer/constants/action_types.js +++ b/src/renderer/constants/action_types.js @@ -108,6 +108,14 @@ export const USER_EMAIL_NEW_FAILURE = 'USER_EMAIL_NEW_FAILURE'; export const USER_EMAIL_VERIFY_STARTED = 'USER_EMAIL_VERIFY_STARTED'; export const USER_EMAIL_VERIFY_SUCCESS = 'USER_EMAIL_VERIFY_SUCCESS'; export const USER_EMAIL_VERIFY_FAILURE = 'USER_EMAIL_VERIFY_FAILURE'; +export const USER_PHONE_DECLINE = 'USER_PHONE_DECLINE'; +export const USER_PHONE_NEW_STARTED = 'USER_PHONE_NEW_STARTED'; +export const USER_PHONE_NEW_SUCCESS = 'USER_PHONE_NEW_SUCCESS'; +export const USER_PHONE_NEW_EXISTS = 'USER_PHONE_NEW_EXISTS'; +export const USER_PHONE_NEW_FAILURE = 'USER_PHONE_NEW_FAILURE'; +export const USER_PHONE_VERIFY_STARTED = 'USER_PHONE_VERIFY_STARTED'; +export const USER_PHONE_VERIFY_SUCCESS = 'USER_PHONE_VERIFY_SUCCESS'; +export const USER_PHONE_VERIFY_FAILURE = 'USER_PHONE_VERIFY_FAILURE'; export const USER_IDENTITY_VERIFY_STARTED = 'USER_IDENTITY_VERIFY_STARTED'; export const USER_IDENTITY_VERIFY_SUCCESS = 'USER_IDENTITY_VERIFY_SUCCESS'; export const USER_IDENTITY_VERIFY_FAILURE = 'USER_IDENTITY_VERIFY_FAILURE'; diff --git a/src/renderer/constants/modal_types.js b/src/renderer/constants/modal_types.js index 9c6d457f9..995060647 100644 --- a/src/renderer/constants/modal_types.js +++ b/src/renderer/constants/modal_types.js @@ -6,7 +6,7 @@ export const ERROR = 'error'; export const INSUFFICIENT_CREDITS = 'insufficient_credits'; export const UPGRADE = 'upgrade'; export const WELCOME = 'welcome'; -export const EMAIL_COLLECTION = 'email_collection'; +export const PHONE_COLLECTION = 'phone_collection'; export const FIRST_REWARD = 'first_reward'; export const AUTHENTICATION_FAILURE = 'auth_failure'; export const TRANSACTION_FAILED = 'transaction_failed'; diff --git a/src/renderer/index.js b/src/renderer/index.js index 8d92c6ba2..fd6dcc1f7 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -12,7 +12,7 @@ import { Provider } from 'react-redux'; import { doConditionalAuthNavigate, doDaemonReady, doShowSnackBar } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation'; import { doDownloadLanguages } from 'redux/actions/settings'; -import { doUserFieldVerify } from 'redux/actions/user'; +import { doUserEmailVerify } from 'redux/actions/user'; import 'scss/all.scss'; import store from 'store'; import app from './app'; @@ -35,7 +35,7 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => { } if (verification.token && verification.recaptcha) { app.store.dispatch(doConditionalAuthNavigate(newSession)); - app.store.dispatch(doUserFieldVerify(verification.token, verification.recaptcha)); + app.store.dispatch(doUserEmailVerify(verification.token, verification.recaptcha)); } else { app.store.dispatch(doShowSnackBar({ message: 'Invalid Verification URI' })); } diff --git a/src/renderer/modal/modalPhoneCollection/index.js b/src/renderer/modal/modalPhoneCollection/index.js index aae6952f7..d3ae17bc6 100644 --- a/src/renderer/modal/modalPhoneCollection/index.js +++ b/src/renderer/modal/modalPhoneCollection/index.js @@ -3,18 +3,19 @@ import * as settings from 'constants/settings'; import { connect } from 'react-redux'; import { doCloseModal } from 'redux/actions/app'; import { doSetClientSetting } from 'redux/actions/settings'; -import { selectEmailToVerify, selectUser } from 'redux/selectors/user'; +import { selectPhoneToVerify, selectUser } from 'redux/selectors/user'; import ModalPhoneCollection from './view'; +import { doNavigate } from 'redux/actions/navigation'; const select = state => ({ - email: selectEmailToVerify(state), + phone: selectPhoneToVerify(state), user: selectUser(state), }); const perform = dispatch => () => ({ closeModal: () => { - dispatch(doSetClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED, true)); dispatch(doCloseModal()); + dispatch(doNavigate('/rewards')); }, }); diff --git a/src/renderer/modal/modalPhoneCollection/view.jsx b/src/renderer/modal/modalPhoneCollection/view.jsx index a8b56c844..5074387db 100644 --- a/src/renderer/modal/modalPhoneCollection/view.jsx +++ b/src/renderer/modal/modalPhoneCollection/view.jsx @@ -6,14 +6,14 @@ import UserFieldVerify from 'component/userFieldVerify'; class ModalPhoneCollection extends React.PureComponent { renderInner() { - const { closeModal, email, user } = this.props; + const { closeModal, phone, user } = this.props; const cancelButton = ; - if (!user.has_verified_email && !email) { - return ; - } else if (!user.has_verified_email) { - return ; + if (!user.phone_number && !phone) { + return ; + } else if (!user.phone_number) { + return ; } closeModal(); } diff --git a/src/renderer/modal/modalRouter/view.jsx b/src/renderer/modal/modalRouter/view.jsx index 019a799fe..ac254ed6d 100644 --- a/src/renderer/modal/modalRouter/view.jsx +++ b/src/renderer/modal/modalRouter/view.jsx @@ -40,11 +40,10 @@ class ModalRouter extends React.PureComponent { return; } - const transitionModal = [ - this.checkShowWelcome, - this.checkShowEmail, - this.checkShowCreditIntro, - ].reduce((acc, func) => (!acc ? func.bind(this)(props) : acc), false); + const transitionModal = [this.checkShowWelcome, this.checkShowCreditIntro].reduce( + (acc, func) => (!acc ? func.bind(this)(props) : acc), + false + ); if ( transitionModal && @@ -65,18 +64,6 @@ class ModalRouter extends React.PureComponent { } } - checkShowEmail(props) { - const { isEmailCollectionAcknowledged, isVerificationCandidate, user } = props; - if ( - !isEmailCollectionAcknowledged && - isVerificationCandidate && - user && - !user.has_verified_email - ) { - return modals.EMAIL_COLLECTION; - } - } - checkShowCreditIntro(props) { const { balance, page, isCreditIntroAcknowledged } = props; @@ -124,7 +111,7 @@ class ModalRouter extends React.PureComponent { return ; case modals.CONFIRM_CLAIM_REVOKE: return ; - case modals.EMAIL_COLLECTION: + case modals.PHONE_COLLECTION: return ; default: return null; diff --git a/src/renderer/redux/actions/user.js b/src/renderer/redux/actions/user.js index 0c289e2ca..ba691541b 100644 --- a/src/renderer/redux/actions/user.js +++ b/src/renderer/redux/actions/user.js @@ -3,7 +3,7 @@ import * as MODALS from 'constants/modal_types'; import Lbryio from 'lbryio'; import { doOpenModal, doShowSnackBar } from 'redux/actions/app'; import { doClaimRewardType, doRewardList } from 'redux/actions/rewards'; -import { selectEmailToVerify } from 'redux/selectors/user'; +import { selectEmailToVerify, selectPhoneToVerify } from 'redux/selectors/user'; import rewards from 'rewards'; export function doFetchInviteStatus() { @@ -78,7 +78,72 @@ export function doUserFetch() { }; } -export function doUserFieldNew(email) { +export function doUserPhoneNew(phone) { + return dispatch => { + dispatch({ + type: ACTIONS.USER_PHONE_NEW_STARTED, + phone, + }); + + const success = () => { + dispatch({ + type: ACTIONS.USER_PHONE_NEW_SUCCESS, + data: { phone }, + }); + }; + + const failure = error => { + dispatch({ + type: ACTIONS.USER_PHONE_NEW_FAILURE, + data: { error }, + }); + }; + + Lbryio.call('user_phone', 'new', { phone_number: phone, country_code: 1 }, 'post').then( + success, + failure + ); + }; +} + +export function doUserPhoneVerifyFailure(error) { + return { + type: ACTIONS.USER_PHONE_VERIFY_FAILURE, + data: { error }, + }; +} + +export function doUserPhoneVerify(verificationCode) { + return (dispatch, getState) => { + const phone_number = selectPhoneToVerify(getState()); + + dispatch({ + type: ACTIONS.USER_PHONE_VERIFY_STARTED, + code: verificationCode, + }); + + Lbryio.call( + 'user_phone', + 'confirm', + { + verification_code: verificationCode, + phone_number, + country_code: '1', + }, + 'post' + ) + .then(userEmail => { + dispatch({ + type: ACTIONS.USER_PHONE_VERIFY_SUCCESS, + data: { phone_number }, + }); + dispatch(doUserFetch()); + }) + .catch(error => dispatch(doUserPhoneVerifyFailure(error))); + }; +} + +export function doUserEmailNew(email) { return dispatch => { dispatch({ type: ACTIONS.USER_EMAIL_NEW_STARTED, @@ -116,14 +181,14 @@ export function doUserFieldNew(email) { }; } -export function doUserFieldVerifyFailure(error) { +export function doUserEmailVerifyFailure(error) { return { type: ACTIONS.USER_EMAIL_VERIFY_FAILURE, data: { error }, }; } -export function doUserFieldVerify(verificationToken, recaptcha) { +export function doUserEmailVerify(verificationToken, recaptcha) { return (dispatch, getState) => { const email = selectEmailToVerify(getState()); @@ -154,7 +219,7 @@ export function doUserFieldVerify(verificationToken, recaptcha) { throw new Error('Your email is still not verified.'); // shouldn't happen } }) - .catch(error => dispatch(doUserFieldVerifyFailure(error))); + .catch(error => dispatch(doUserEmailVerifyFailure(error))); }; } diff --git a/src/renderer/redux/reducers/user.js b/src/renderer/redux/reducers/user.js index f616dd1d1..52c98b925 100644 --- a/src/renderer/redux/reducers/user.js +++ b/src/renderer/redux/reducers/user.js @@ -55,6 +55,52 @@ reducers[ACTIONS.USER_FETCH_FAILURE] = state => user: null, }); +reducers[ACTIONS.USER_PHONE_NEW_STARTED] = state => + Object.assign({}, state, { + phoneNewIsPending: true, + phoneNewErrorMessage: '', + }); + +reducers[ACTIONS.USER_PHONE_NEW_SUCCESS] = (state, action) => + Object.assign({}, state, { + phoneToVerify: action.data.phone, + phoneNewIsPending: false, + }); + +reducers[ACTIONS.USER_PHONE_NEW_EXISTS] = (state, action) => + Object.assign({}, state, { + phoneToVerify: action.data.phone, + phoneNewIsPending: false, + }); + +reducers[ACTIONS.USER_PHONE_NEW_FAILURE] = (state, action) => + Object.assign({}, state, { + phoneNewIsPending: false, + phoneNewErrorMessage: action.data.error, + }); + +reducers[ACTIONS.USER_PHONE_VERIFY_STARTED] = state => + Object.assign({}, state, { + phoneVerifyIsPending: true, + phoneVerifyErrorMessage: '', + }); + +reducers[ACTIONS.USER_PHONE_VERIFY_SUCCESS] = (state, action) => { + const user = Object.assign({}, state.user); + user.phone_number = action.data.phone_number; + return Object.assign({}, state, { + phoneToVerify: '', + phoneVerifyIsPending: false, + user, + }); +}; + +reducers[ACTIONS.USER_PHONE_VERIFY_FAILURE] = (state, action) => + Object.assign({}, state, { + phoneVerifyIsPending: false, + phoneVerifyErrorMessage: action.data.error, + }); + reducers[ACTIONS.USER_EMAIL_NEW_STARTED] = state => Object.assign({}, state, { emailNewIsPending: true, diff --git a/src/renderer/redux/selectors/user.js b/src/renderer/redux/selectors/user.js index de2c6c447..638989931 100644 --- a/src/renderer/redux/selectors/user.js +++ b/src/renderer/redux/selectors/user.js @@ -16,12 +16,23 @@ export const selectUserEmail = createSelector( user => (user ? user.primary_email : null) ); +export const selectUserPhone = createSelector( + selectUser, + user => (user ? user.phone_number : null) +); + export const selectEmailToVerify = createSelector( selectState, selectUserEmail, (state, userEmail) => state.emailToVerify || userEmail ); +export const selectPhoneToVerify = createSelector( + selectState, + selectUserPhone, + (state, userPhone) => state.phoneToVerify || userPhone +); + export const selectUserIsRewardApproved = createSelector( selectUser, user => user && user.is_reward_approved From 247859a1dd6478b9bb77c12c1e7e153c8169e3aa Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Mon, 15 Jan 2018 05:35:15 -0800 Subject: [PATCH 05/16] Remove console.logs --- src/renderer/component/userFieldNew/view.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/renderer/component/userFieldNew/view.jsx b/src/renderer/component/userFieldNew/view.jsx index 6cd29679a..2c2d481c8 100644 --- a/src/renderer/component/userFieldNew/view.jsx +++ b/src/renderer/component/userFieldNew/view.jsx @@ -12,9 +12,6 @@ class UserFieldNew extends React.PureComponent { } handleChanged(event, fieldType) { - console.log({ - [fieldType]: event.target.value, - }); this.setState({ [fieldType]: event.target.value, }); From fa7d265cc0179181a3210aefd4356bb5bcd13ea6 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Mon, 15 Jan 2018 06:30:10 -0800 Subject: [PATCH 06/16] Add error messages in phone verification modal --- src/renderer/component/userFieldNew/index.js | 9 +++++++-- src/renderer/component/userFieldNew/view.jsx | 6 +++--- src/renderer/component/userFieldVerify/index.js | 4 +++- src/renderer/component/userFieldVerify/view.jsx | 11 +++++++++-- src/renderer/redux/actions/user.js | 4 ++-- src/renderer/redux/selectors/user.js | 10 ++++++++++ 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/renderer/component/userFieldNew/index.js b/src/renderer/component/userFieldNew/index.js index 477a383e1..5cda23cc0 100644 --- a/src/renderer/component/userFieldNew/index.js +++ b/src/renderer/component/userFieldNew/index.js @@ -1,12 +1,17 @@ import React from 'react'; import { connect } from 'react-redux'; import { doUserEmailNew, doUserPhoneNew, doUserInviteNew } from 'redux/actions/user'; -import { selectEmailNewIsPending, selectEmailNewErrorMessage } from 'redux/selectors/user'; +import { + selectEmailNewIsPending, + selectEmailNewErrorMessage, + selectPhoneNewErrorMessage, +} from 'redux/selectors/user'; import UserFieldNew from './view'; const select = state => ({ isPending: selectEmailNewIsPending(state), - errorMessage: selectEmailNewErrorMessage(state), + emailErrorMessage: selectEmailNewErrorMessage(state), + phoneErrorMessage: selectPhoneNewErrorMessage(state), }); const perform = dispatch => ({ diff --git a/src/renderer/component/userFieldNew/view.jsx b/src/renderer/component/userFieldNew/view.jsx index 2c2d481c8..86f43cf00 100644 --- a/src/renderer/component/userFieldNew/view.jsx +++ b/src/renderer/component/userFieldNew/view.jsx @@ -27,7 +27,7 @@ class UserFieldNew extends React.PureComponent { } render() { - const { cancelButton, errorMessage, isPending, fieldType } = this.props; + const { cancelButton, emailErrorMessage, phoneErrorMessage, isPending, fieldType } = this.props; return fieldType === 'phone' ? (
@@ -43,7 +43,7 @@ class UserFieldNew extends React.PureComponent { placeholder="(555) 555-5555" name="phone" value={this.state.phone} - errorMessage={errorMessage} + errorMessage={phoneErrorMessage} onChange={event => { this.handleChanged(event, 'phone'); }} @@ -67,7 +67,7 @@ class UserFieldNew extends React.PureComponent { placeholder="youremail@example.org" name="email" value={this.state.email} - errorMessage={errorMessage} + errorMessage={emailErrorMessage} onChange={event => { this.handleChanged(event, 'email'); }} diff --git a/src/renderer/component/userFieldVerify/index.js b/src/renderer/component/userFieldVerify/index.js index a8fab1120..d83396d81 100644 --- a/src/renderer/component/userFieldVerify/index.js +++ b/src/renderer/component/userFieldVerify/index.js @@ -6,6 +6,7 @@ import { selectEmailToVerify, selectPhoneToVerify, selectEmailVerifyErrorMessage, + selectPhoneVerifyErrorMessage, } from 'redux/selectors/user'; import UserFieldVerify from './view'; @@ -13,7 +14,8 @@ const select = state => ({ isPending: selectEmailVerifyIsPending(state), email: selectEmailToVerify(state), phone: selectPhoneToVerify(state), - errorMessage: selectEmailVerifyErrorMessage(state), + emailErrorMessage: selectEmailVerifyErrorMessage(state), + phoneErrorMessage: selectPhoneVerifyErrorMessage(state), }); const perform = dispatch => ({ diff --git a/src/renderer/component/userFieldVerify/view.jsx b/src/renderer/component/userFieldVerify/view.jsx index 0bd2e3a03..0f09bdd78 100644 --- a/src/renderer/component/userFieldVerify/view.jsx +++ b/src/renderer/component/userFieldVerify/view.jsx @@ -33,7 +33,14 @@ class UserFieldVerify extends React.PureComponent { } render() { - const { cancelButton, errorMessage, email, isPending, phone } = this.props; + const { + cancelButton, + emailErrorMessage, + phoneErrorMessage, + email, + isPending, + phone, + } = this.props; return (

Please enter the verification code sent to {phone || email}.

@@ -45,7 +52,7 @@ class UserFieldVerify extends React.PureComponent { onChange={event => { this.handleCodeChanged(event); }} - errorMessage={errorMessage} + errorMessage={emailErrorMessage || phoneErrorMessage} /> {/* render help separately so it always shows */}
diff --git a/src/renderer/redux/actions/user.js b/src/renderer/redux/actions/user.js index ba691541b..ee99f5088 100644 --- a/src/renderer/redux/actions/user.js +++ b/src/renderer/redux/actions/user.js @@ -92,10 +92,10 @@ export function doUserPhoneNew(phone) { }); }; - const failure = error => { + const failure = () => { dispatch({ type: ACTIONS.USER_PHONE_NEW_FAILURE, - data: { error }, + data: { error: 'An error occurred while processing this phone number.' }, }); }; diff --git a/src/renderer/redux/selectors/user.js b/src/renderer/redux/selectors/user.js index 638989931..16f175345 100644 --- a/src/renderer/redux/selectors/user.js +++ b/src/renderer/redux/selectors/user.js @@ -48,6 +48,11 @@ export const selectEmailNewErrorMessage = createSelector( state => state.emailNewErrorMessage ); +export const selectPhoneNewErrorMessage = createSelector( + selectState, + state => state.phoneNewErrorMessage +); + export const selectEmailVerifyIsPending = createSelector( selectState, state => state.emailVerifyIsPending @@ -58,6 +63,11 @@ export const selectEmailVerifyErrorMessage = createSelector( state => state.emailVerifyErrorMessage ); +export const selectPhoneVerifyErrorMessage = createSelector( + selectState, + state => state.phoneVerifyErrorMessage +); + export const selectIdentityVerifyIsPending = createSelector( selectState, state => state.identityVerifyIsPending From faa2753e3591bf9392d34f967f4700234648b643 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Wed, 17 Jan 2018 18:22:52 -0800 Subject: [PATCH 07/16] Change to updated urls for phone verification --- src/renderer/redux/actions/user.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/renderer/redux/actions/user.js b/src/renderer/redux/actions/user.js index ee99f5088..e7b2c1e02 100644 --- a/src/renderer/redux/actions/user.js +++ b/src/renderer/redux/actions/user.js @@ -99,7 +99,7 @@ export function doUserPhoneNew(phone) { }); }; - Lbryio.call('user_phone', 'new', { phone_number: phone, country_code: 1 }, 'post').then( + Lbryio.call('user', 'phone_number_new', { phone_number: phone, country_code: 1 }, 'post').then( success, failure ); @@ -115,7 +115,7 @@ export function doUserPhoneVerifyFailure(error) { export function doUserPhoneVerify(verificationCode) { return (dispatch, getState) => { - const phone_number = selectPhoneToVerify(getState()); + const phoneNumber = selectPhoneToVerify(getState()); dispatch({ type: ACTIONS.USER_PHONE_VERIFY_STARTED, @@ -123,19 +123,19 @@ export function doUserPhoneVerify(verificationCode) { }); Lbryio.call( - 'user_phone', - 'confirm', + 'user', + 'phone_number_confirm', { verification_code: verificationCode, - phone_number, + phone_number: phoneNumber, country_code: '1', }, 'post' ) - .then(userEmail => { + .then(() => { dispatch({ type: ACTIONS.USER_PHONE_VERIFY_SUCCESS, - data: { phone_number }, + data: { phone_number: phoneNumber }, }); dispatch(doUserFetch()); }) From a34a61bce85e3ce73fd8401a0a2cdde8b10ea32d Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Wed, 17 Jan 2018 21:09:08 -0800 Subject: [PATCH 08/16] Add custom country code --- src/renderer/component/userFieldNew/index.js | 2 +- src/renderer/component/userFieldNew/view.jsx | 52 +++++++++++++++++-- .../component/userFieldVerify/index.js | 2 + .../component/userFieldVerify/view.jsx | 6 ++- src/renderer/redux/actions/user.js | 15 ++++-- src/renderer/redux/reducers/user.js | 8 ++- src/renderer/redux/selectors/user.js | 5 ++ 7 files changed, 77 insertions(+), 13 deletions(-) diff --git a/src/renderer/component/userFieldNew/index.js b/src/renderer/component/userFieldNew/index.js index 5cda23cc0..2b2dd6b96 100644 --- a/src/renderer/component/userFieldNew/index.js +++ b/src/renderer/component/userFieldNew/index.js @@ -16,7 +16,7 @@ const select = state => ({ const perform = dispatch => ({ addUserEmail: email => dispatch(doUserEmailNew(email)), - addUserPhone: phone => dispatch(doUserPhoneNew(phone)), + addUserPhone: (phone, country_code) => dispatch(doUserPhoneNew(phone, country_code)), }); export default connect(select, perform)(UserFieldNew); diff --git a/src/renderer/component/userFieldNew/view.jsx b/src/renderer/component/userFieldNew/view.jsx index 86f43cf00..8fd8e4838 100644 --- a/src/renderer/component/userFieldNew/view.jsx +++ b/src/renderer/component/userFieldNew/view.jsx @@ -8,19 +8,53 @@ class UserFieldNew extends React.PureComponent { this.state = { phone: '', email: '', + country_code: '+1', }; + + this.formatPhone = this.formatPhone.bind(this); + } + + formatPhone(value) { + const { country_code } = this.state; + value = value.replace(/\D/g, ''); + if (country_code === '+1') { + if (!value) { + return ''; + } else if (value.length < 4) { + return value; + } else if (value.length < 7) { + return `(${value.substring(0, 3)}) ${value.substring(3)}`; + } + const fullNumber = `(${value.substring(0, 3)}) ${value.substring(3, 6)}-${value.substring( + 6 + )}`; + return fullNumber.length <= 14 ? fullNumber : fullNumber.substring(0, 14); + } + return value; + } + + formatCountryCode(value) { + if (value) { + return `+${value.replace(/\D/g, '')}`; + } + return '+1'; } handleChanged(event, fieldType) { + const formatter = { + email: _ => _, + phone: this.formatPhone, + country_code: this.formatCountryCode, + }; this.setState({ - [fieldType]: event.target.value, + [fieldType]: formatter[fieldType](event.target.value), }); } handleSubmit() { - const { email, phone } = this.state; + const { email, phone, country_code } = this.state; if (phone) { - this.props.addUserPhone(phone); + this.props.addUserPhone(phone.replace(/\D/g, ''), country_code.replace(/\D/g, '')); } else { this.props.addUserEmail(email); } @@ -37,10 +71,20 @@ class UserFieldNew extends React.PureComponent { )}

+ { + this.handleChanged(event, 'country_code'); + }} + /> ({ isPending: selectEmailVerifyIsPending(state), email: selectEmailToVerify(state), phone: selectPhoneToVerify(state), + countryCode: selectUserCountryCode(state), emailErrorMessage: selectEmailVerifyErrorMessage(state), phoneErrorMessage: selectPhoneVerifyErrorMessage(state), }); diff --git a/src/renderer/component/userFieldVerify/view.jsx b/src/renderer/component/userFieldVerify/view.jsx index 0f09bdd78..56d78479e 100644 --- a/src/renderer/component/userFieldVerify/view.jsx +++ b/src/renderer/component/userFieldVerify/view.jsx @@ -40,10 +40,14 @@ class UserFieldVerify extends React.PureComponent { email, isPending, phone, + countryCode, } = this.props; return ( -

Please enter the verification code sent to {phone || email}.

+

+ Please enter the verification code sent to {countryCode ? `+${countryCode}` : ''} + {phone || email}. +

{ dispatch({ type: ACTIONS.USER_PHONE_NEW_STARTED, - phone, + data: { phone, country_code }, }); const success = () => { @@ -99,7 +103,7 @@ export function doUserPhoneNew(phone) { }); }; - Lbryio.call('user', 'phone_number_new', { phone_number: phone, country_code: 1 }, 'post').then( + Lbryio.call('user', 'phone_number_new', { phone_number: phone, country_code }, 'post').then( success, failure ); @@ -116,6 +120,7 @@ export function doUserPhoneVerifyFailure(error) { export function doUserPhoneVerify(verificationCode) { return (dispatch, getState) => { const phoneNumber = selectPhoneToVerify(getState()); + const countryCode = selectUserCountryCode(getState()); dispatch({ type: ACTIONS.USER_PHONE_VERIFY_STARTED, @@ -128,7 +133,7 @@ export function doUserPhoneVerify(verificationCode) { { verification_code: verificationCode, phone_number: phoneNumber, - country_code: '1', + country_code: countryCode, }, 'post' ) diff --git a/src/renderer/redux/reducers/user.js b/src/renderer/redux/reducers/user.js index 52c98b925..3d2ea165c 100644 --- a/src/renderer/redux/reducers/user.js +++ b/src/renderer/redux/reducers/user.js @@ -55,11 +55,15 @@ reducers[ACTIONS.USER_FETCH_FAILURE] = state => user: null, }); -reducers[ACTIONS.USER_PHONE_NEW_STARTED] = state => - Object.assign({}, state, { +reducers[ACTIONS.USER_PHONE_NEW_STARTED] = (state, action) => { + const user = Object.assign({}, state.user); + user.country_code = action.data.country_code; + return Object.assign({}, state, { phoneNewIsPending: true, phoneNewErrorMessage: '', + user, }); +}; reducers[ACTIONS.USER_PHONE_NEW_SUCCESS] = (state, action) => Object.assign({}, state, { diff --git a/src/renderer/redux/selectors/user.js b/src/renderer/redux/selectors/user.js index 16f175345..a1b0df18e 100644 --- a/src/renderer/redux/selectors/user.js +++ b/src/renderer/redux/selectors/user.js @@ -21,6 +21,11 @@ export const selectUserPhone = createSelector( user => (user ? user.phone_number : null) ); +export const selectUserCountryCode = createSelector( + selectUser, + user => (user ? user.country_code : null) +); + export const selectEmailToVerify = createSelector( selectState, selectUserEmail, From 3ac913a28eead88a25262be86dfbc089a8faa4d6 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Sun, 21 Jan 2018 11:29:48 -0800 Subject: [PATCH 09/16] Add new phone select style --- src/renderer/component/userFieldNew/view.jsx | 37 +++++++++----------- src/renderer/scss/_vars.scss | 1 + src/renderer/scss/component/_form-field.scss | 10 +++++- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/renderer/component/userFieldNew/view.jsx b/src/renderer/component/userFieldNew/view.jsx index 8fd8e4838..c9b7ceb34 100644 --- a/src/renderer/component/userFieldNew/view.jsx +++ b/src/renderer/component/userFieldNew/view.jsx @@ -1,5 +1,6 @@ import React from 'react'; import { Form, FormRow, Submit } from 'component/form.js'; +import FormField from 'component/formField'; class UserFieldNew extends React.PureComponent { constructor(props) { @@ -71,27 +72,21 @@ class UserFieldNew extends React.PureComponent { )}

- { - this.handleChanged(event, 'country_code'); - }} - /> - { - this.handleChanged(event, 'phone'); - }} - /> +
+ + + + { + this.handleChanged(event, 'phone'); + }} + /> +
{cancelButton} diff --git a/src/renderer/scss/_vars.scss b/src/renderer/scss/_vars.scss index 15436a5b1..f05049912 100644 --- a/src/renderer/scss/_vars.scss +++ b/src/renderer/scss/_vars.scss @@ -79,6 +79,7 @@ $text-color: #000; /* Select */ --select-bg: var(--color-bg-alt); --select-color: var(--text-color); + --select-height: 30px; /* Button */ --button-bg: var(--color-bg-alt); diff --git a/src/renderer/scss/component/_form-field.scss b/src/renderer/scss/component/_form-field.scss index 042565611..944aa9730 100644 --- a/src/renderer/scss/component/_form-field.scss +++ b/src/renderer/scss/component/_form-field.scss @@ -5,6 +5,14 @@ margin-bottom: $spacing-vertical; } +.form-row-phone { + display: flex; + + select { + margin-right: 5px; + } +} + .form-row__label-row { margin-top: $spacing-vertical * 5/6; margin-bottom: 0px; @@ -32,7 +40,7 @@ box-sizing: border-box; padding-left: 5px; padding-right: 5px; - height: $spacing-vertical; + height: var(--select-height); background: var(--select-bg); color: var(--select-color); &:focus { From 705a74e2ae115e24f34cbe66d9954b1c7f389c48 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Sun, 21 Jan 2018 22:17:06 -0800 Subject: [PATCH 10/16] Functioning select phone input side by side with supposed emoji flag support --- package.json | 1 + src/renderer/component/userFieldNew/view.jsx | 30 ++++++++++++++++++-- src/renderer/scss/component/_form-field.scss | 5 ++-- yarn.lock | 15 ++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2e61b99cc..3906049d8 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "amplitude-js": "^4.0.0", "bluebird": "^3.5.1", "classnames": "^2.2.5", + "country-data": "^0.0.31", "electron-dl": "^1.6.0", "formik": "^0.10.4", "from2": "^2.3.0", diff --git a/src/renderer/component/userFieldNew/view.jsx b/src/renderer/component/userFieldNew/view.jsx index c9b7ceb34..1824359e8 100644 --- a/src/renderer/component/userFieldNew/view.jsx +++ b/src/renderer/component/userFieldNew/view.jsx @@ -2,6 +2,22 @@ import React from 'react'; import { Form, FormRow, Submit } from 'component/form.js'; import FormField from 'component/formField'; +const countryCodes = require('country-data') + .callingCountries.all.filter(_ => _.emoji) + .reduce( + (acc, cur) => acc.concat(cur.countryCallingCodes.map(_ => ({ ...cur, countryCallingCode: _ }))), + [] + ) + .sort((a, b) => { + if (a.countryCallingCodes[0] < b.countryCallingCodes[0]) { + return -1; + } + if (a.countryCallingCodes[0] > b.countryCallingCodes[0]) { + return 1; + } + return 0; + }); + class UserFieldNew extends React.PureComponent { constructor(props) { super(props); @@ -52,10 +68,14 @@ class UserFieldNew extends React.PureComponent { }); } + handleSelect(event) { + this.setState({ country_code: event.target.value }); + } + handleSubmit() { const { email, phone, country_code } = this.state; if (phone) { - this.props.addUserPhone(phone.replace(/\D/g, ''), country_code.replace(/\D/g, '')); + this.props.addUserPhone(phone.replace(/\D/g, ''), country_code.substring(1)); } else { this.props.addUserEmail(email); } @@ -73,8 +93,12 @@ class UserFieldNew extends React.PureComponent {

- - + + {countryCodes.map(country => ( + + ))} 1.4.4" + create-ecdh@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" @@ -2406,6 +2413,10 @@ csso@~2.3.1: clap "^1.0.9" source-map "^0.5.3" +currency-symbol-map@~2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/currency-symbol-map/-/currency-symbol-map-2.2.0.tgz#2b3c1872ff1ac2ce595d8273e58e1fff0272aea2" + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -8781,6 +8792,10 @@ unc-path-regex@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" +underscore@>1.4.4: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" From 99bdaa608efae8a4c6c2a4237884df22a1bcbdea Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Sun, 21 Jan 2018 22:30:20 -0800 Subject: [PATCH 11/16] Small fixes to country code select --- src/renderer/component/userFieldNew/view.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/component/userFieldNew/view.jsx b/src/renderer/component/userFieldNew/view.jsx index 1824359e8..1bcc03db6 100644 --- a/src/renderer/component/userFieldNew/view.jsx +++ b/src/renderer/component/userFieldNew/view.jsx @@ -9,10 +9,10 @@ const countryCodes = require('country-data') [] ) .sort((a, b) => { - if (a.countryCallingCodes[0] < b.countryCallingCodes[0]) { + if (a.countryCallingCode < b.countryCallingCode) { return -1; } - if (a.countryCallingCodes[0] > b.countryCallingCodes[0]) { + if (a.countryCallingCode > b.countryCallingCode) { return 1; } return 0; @@ -94,8 +94,8 @@ class UserFieldNew extends React.PureComponent {
- {countryCodes.map(country => ( - ))} From 9e2d82eac83bfac60dc6650ce128590e22dd6823 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Sun, 21 Jan 2018 23:09:11 -0800 Subject: [PATCH 12/16] Split userField... into userEmail... and userPhone... --- src/renderer/component/userEmailNew/index.js | 16 +++++ src/renderer/component/userEmailNew/view.jsx | 55 +++++++++++++++++ .../component/userEmailVerify/index.js | 22 +++++++ .../view.jsx | 36 ++++------- src/renderer/component/userFieldNew/index.js | 22 ------- .../component/userFieldVerify/index.js | 29 --------- src/renderer/component/userPhoneNew/index.js | 15 +++++ .../{userFieldNew => userPhoneNew}/view.jsx | 59 +++--------------- .../component/userPhoneVerify/index.js | 21 +++++++ .../component/userPhoneVerify/view.jsx | 60 +++++++++++++++++++ .../modal/modalPhoneCollection/view.jsx | 8 +-- src/renderer/page/auth/view.jsx | 8 +-- 12 files changed, 216 insertions(+), 135 deletions(-) create mode 100644 src/renderer/component/userEmailNew/index.js create mode 100644 src/renderer/component/userEmailNew/view.jsx create mode 100644 src/renderer/component/userEmailVerify/index.js rename src/renderer/component/{userFieldVerify => userEmailVerify}/view.jsx (60%) delete mode 100644 src/renderer/component/userFieldNew/index.js delete mode 100644 src/renderer/component/userFieldVerify/index.js create mode 100644 src/renderer/component/userPhoneNew/index.js rename src/renderer/component/{userFieldNew => userPhoneNew}/view.jsx (61%) create mode 100644 src/renderer/component/userPhoneVerify/index.js create mode 100644 src/renderer/component/userPhoneVerify/view.jsx diff --git a/src/renderer/component/userEmailNew/index.js b/src/renderer/component/userEmailNew/index.js new file mode 100644 index 000000000..0228a4aaa --- /dev/null +++ b/src/renderer/component/userEmailNew/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { doUserEmailNew, doUserInviteNew } from 'redux/actions/user'; +import { selectEmailNewIsPending, selectEmailNewErrorMessage } from 'redux/selectors/user'; +import UserEmailNew from './view'; + +const select = state => ({ + isPending: selectEmailNewIsPending(state), + errorMessage: selectEmailNewErrorMessage(state), +}); + +const perform = dispatch => ({ + addUserEmail: email => dispatch(doUserEmailNew(email)), +}); + +export default connect(select, perform)(UserEmailNew); diff --git a/src/renderer/component/userEmailNew/view.jsx b/src/renderer/component/userEmailNew/view.jsx new file mode 100644 index 000000000..661adb611 --- /dev/null +++ b/src/renderer/component/userEmailNew/view.jsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { Form, FormRow, Submit } from 'component/form.js'; + +class UserEmailNew extends React.PureComponent { + constructor(props) { + super(props); + + this.state = { + email: '', + }; + } + + handleEmailChanged(event) { + this.setState({ + email: event.target.value, + }); + } + + handleSubmit() { + const { email } = this.state; + this.props.addUserEmail(email); + } + + render() { + const { cancelButton, errorMessage, isPending } = this.props; + + return ( +
+

+ {__("We'll let you know about LBRY updates, security issues, and great new content.")} +

+

{__("We'll never sell your email, and you can unsubscribe at any time.")}

+ + { + this.handleEmailChanged(event); + }} + /> +
+ + {cancelButton} +
+ +
+ ); + } +} + +export default UserEmailNew; diff --git a/src/renderer/component/userEmailVerify/index.js b/src/renderer/component/userEmailVerify/index.js new file mode 100644 index 000000000..f8c854ca1 --- /dev/null +++ b/src/renderer/component/userEmailVerify/index.js @@ -0,0 +1,22 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { doUserEmailVerify, doUserEmailVerifyFailure } from 'redux/actions/user'; +import { + selectEmailVerifyIsPending, + selectEmailToVerify, + selectEmailVerifyErrorMessage, +} from 'redux/selectors/user'; +import UserEmailVerify from './view'; + +const select = state => ({ + isPending: selectEmailVerifyIsPending(state), + email: selectEmailToVerify(state), + errorMessage: selectEmailVerifyErrorMessage(state), +}); + +const perform = dispatch => ({ + verifyUserEmail: (code, recaptcha) => dispatch(doUserEmailVerify(code, recaptcha)), + verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)), +}); + +export default connect(select, perform)(UserEmailVerify); diff --git a/src/renderer/component/userFieldVerify/view.jsx b/src/renderer/component/userEmailVerify/view.jsx similarity index 60% rename from src/renderer/component/userFieldVerify/view.jsx rename to src/renderer/component/userEmailVerify/view.jsx index 56d78479e..3304730b9 100644 --- a/src/renderer/component/userFieldVerify/view.jsx +++ b/src/renderer/component/userEmailVerify/view.jsx @@ -2,7 +2,7 @@ import React from 'react'; import Link from 'component/link'; import { Form, FormRow, Submit } from 'component/form.js'; -class UserFieldVerify extends React.PureComponent { +class UserEmailVerify extends React.PureComponent { constructor(props) { super(props); @@ -19,35 +19,19 @@ class UserFieldVerify extends React.PureComponent { handleSubmit() { const { code } = this.state; - const { fieldType } = this.props; - if (fieldType === 'phone') { - this.props.verifyUserPhone(code); - } else { - try { - const verification = JSON.parse(atob(code)); - this.props.verifyUserEmail(verification.token, verification.recaptcha); - } catch (error) { - this.props.verifyUserEmailFailure('Invalid Verification Token'); - } + try { + const verification = JSON.parse(atob(code)); + this.props.verifyUserEmail(verification.token, verification.recaptcha); + } catch (error) { + this.props.verifyUserEmailFailure('Invalid Verification Token'); } } render() { - const { - cancelButton, - emailErrorMessage, - phoneErrorMessage, - email, - isPending, - phone, - countryCode, - } = this.props; + const { cancelButton, errorMessage, email, isPending } = this.props; return (
-

- Please enter the verification code sent to {countryCode ? `+${countryCode}` : ''} - {phone || email}. -

+

Please enter the verification code emailed to {email}.

{ this.handleCodeChanged(event); }} - errorMessage={emailErrorMessage || phoneErrorMessage} + errorMessage={errorMessage} /> {/* render help separately so it always shows */}
@@ -75,4 +59,4 @@ class UserFieldVerify extends React.PureComponent { } } -export default UserFieldVerify; +export default UserEmailVerify; diff --git a/src/renderer/component/userFieldNew/index.js b/src/renderer/component/userFieldNew/index.js deleted file mode 100644 index 2b2dd6b96..000000000 --- a/src/renderer/component/userFieldNew/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import { doUserEmailNew, doUserPhoneNew, doUserInviteNew } from 'redux/actions/user'; -import { - selectEmailNewIsPending, - selectEmailNewErrorMessage, - selectPhoneNewErrorMessage, -} from 'redux/selectors/user'; -import UserFieldNew from './view'; - -const select = state => ({ - isPending: selectEmailNewIsPending(state), - emailErrorMessage: selectEmailNewErrorMessage(state), - phoneErrorMessage: selectPhoneNewErrorMessage(state), -}); - -const perform = dispatch => ({ - addUserEmail: email => dispatch(doUserEmailNew(email)), - addUserPhone: (phone, country_code) => dispatch(doUserPhoneNew(phone, country_code)), -}); - -export default connect(select, perform)(UserFieldNew); diff --git a/src/renderer/component/userFieldVerify/index.js b/src/renderer/component/userFieldVerify/index.js deleted file mode 100644 index 12f160692..000000000 --- a/src/renderer/component/userFieldVerify/index.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import { doUserEmailVerify, doUserPhoneVerify, doUserEmailVerifyFailure } from 'redux/actions/user'; -import { - selectEmailVerifyIsPending, - selectEmailToVerify, - selectPhoneToVerify, - selectEmailVerifyErrorMessage, - selectPhoneVerifyErrorMessage, - selectUserCountryCode, -} from 'redux/selectors/user'; -import UserFieldVerify from './view'; - -const select = state => ({ - isPending: selectEmailVerifyIsPending(state), - email: selectEmailToVerify(state), - phone: selectPhoneToVerify(state), - countryCode: selectUserCountryCode(state), - emailErrorMessage: selectEmailVerifyErrorMessage(state), - phoneErrorMessage: selectPhoneVerifyErrorMessage(state), -}); - -const perform = dispatch => ({ - verifyUserEmail: (code, recaptcha) => dispatch(doUserEmailVerify(code, recaptcha)), - verifyUserPhone: code => dispatch(doUserPhoneVerify(code)), - verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)), -}); - -export default connect(select, perform)(UserFieldVerify); diff --git a/src/renderer/component/userPhoneNew/index.js b/src/renderer/component/userPhoneNew/index.js new file mode 100644 index 000000000..3033a3c2c --- /dev/null +++ b/src/renderer/component/userPhoneNew/index.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { doUserPhoneNew } from 'redux/actions/user'; +import { selectPhoneNewErrorMessage } from 'redux/selectors/user'; +import UserPhoneNew from './view'; + +const select = state => ({ + phoneErrorMessage: selectPhoneNewErrorMessage(state), +}); + +const perform = dispatch => ({ + addUserPhone: (phone, country_code) => dispatch(doUserPhoneNew(phone, country_code)), +}); + +export default connect(select, perform)(UserPhoneNew); diff --git a/src/renderer/component/userFieldNew/view.jsx b/src/renderer/component/userPhoneNew/view.jsx similarity index 61% rename from src/renderer/component/userFieldNew/view.jsx rename to src/renderer/component/userPhoneNew/view.jsx index 1bcc03db6..593fd17b9 100644 --- a/src/renderer/component/userFieldNew/view.jsx +++ b/src/renderer/component/userPhoneNew/view.jsx @@ -18,13 +18,12 @@ const countryCodes = require('country-data') return 0; }); -class UserFieldNew extends React.PureComponent { +class UserPhoneNew extends React.PureComponent { constructor(props) { super(props); this.state = { phone: '', - email: '', country_code: '+1', }; @@ -50,21 +49,9 @@ class UserFieldNew extends React.PureComponent { return value; } - formatCountryCode(value) { - if (value) { - return `+${value.replace(/\D/g, '')}`; - } - return '+1'; - } - - handleChanged(event, fieldType) { - const formatter = { - email: _ => _, - phone: this.formatPhone, - country_code: this.formatCountryCode, - }; + handleChanged(event) { this.setState({ - [fieldType]: formatter[fieldType](event.target.value), + phone: this.formatPhone(event.target.value), }); } @@ -73,18 +60,14 @@ class UserFieldNew extends React.PureComponent { } handleSubmit() { - const { email, phone, country_code } = this.state; - if (phone) { - this.props.addUserPhone(phone.replace(/\D/g, ''), country_code.substring(1)); - } else { - this.props.addUserEmail(email); - } + const { phone, country_code } = this.state; + this.props.addUserPhone(phone.replace(/\D/g, ''), country_code.substring(1)); } render() { - const { cancelButton, emailErrorMessage, phoneErrorMessage, isPending, fieldType } = this.props; + const { cancelButton, phoneErrorMessage, isPending } = this.props; - return fieldType === 'phone' ? ( + return (

{__( @@ -107,7 +90,7 @@ class UserFieldNew extends React.PureComponent { value={this.state.phone} errorMessage={phoneErrorMessage} onChange={event => { - this.handleChanged(event, 'phone'); + this.handleChanged(event); }} />

@@ -117,32 +100,8 @@ class UserFieldNew extends React.PureComponent {
- ) : ( -
-

- {__("We'll let you know about LBRY updates, security issues, and great new content.")} -

-

{__("We'll never sell your email, and you can unsubscribe at any time.")}

-
- { - this.handleChanged(event, 'email'); - }} - /> -
- - {cancelButton} -
- -
); } } -export default UserFieldNew; +export default UserPhoneNew; diff --git a/src/renderer/component/userPhoneVerify/index.js b/src/renderer/component/userPhoneVerify/index.js new file mode 100644 index 000000000..89b18a120 --- /dev/null +++ b/src/renderer/component/userPhoneVerify/index.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { doUserPhoneVerify } from 'redux/actions/user'; +import { + selectPhoneToVerify, + selectPhoneVerifyErrorMessage, + selectUserCountryCode, +} from 'redux/selectors/user'; +import UserPhoneVerify from './view'; + +const select = state => ({ + phone: selectPhoneToVerify(state), + countryCode: selectUserCountryCode(state), + phoneErrorMessage: selectPhoneVerifyErrorMessage(state), +}); + +const perform = dispatch => ({ + verifyUserPhone: code => dispatch(doUserPhoneVerify(code)), +}); + +export default connect(select, perform)(UserPhoneVerify); diff --git a/src/renderer/component/userPhoneVerify/view.jsx b/src/renderer/component/userPhoneVerify/view.jsx new file mode 100644 index 000000000..027b18c38 --- /dev/null +++ b/src/renderer/component/userPhoneVerify/view.jsx @@ -0,0 +1,60 @@ +import React from 'react'; +import Link from 'component/link'; +import { Form, FormRow, Submit } from 'component/form.js'; + +class UserPhoneVerify extends React.PureComponent { + constructor(props) { + super(props); + + this.state = { + code: '', + }; + } + + handleCodeChanged(event) { + this.setState({ + code: String(event.target.value).trim(), + }); + } + + handleSubmit() { + const { code } = this.state; + this.props.verifyUserPhone(code); + } + + render() { + const { cancelButton, phoneErrorMessage, phone, countryCode } = this.props; + return ( +
+

+ Please enter the verification code sent to {`+${countryCode}`} + {phone}. +

+ { + this.handleCodeChanged(event); + }} + errorMessage={phoneErrorMessage} + /> + {/* render help separately so it always shows */} +
+

+ {__('Email')} or join our{' '} + {' '} + {__('if you encounter any trouble with your code.')} +

+
+
+ + {cancelButton} +
+ + ); + } +} + +export default UserPhoneVerify; diff --git a/src/renderer/modal/modalPhoneCollection/view.jsx b/src/renderer/modal/modalPhoneCollection/view.jsx index 5074387db..bf1ead9f6 100644 --- a/src/renderer/modal/modalPhoneCollection/view.jsx +++ b/src/renderer/modal/modalPhoneCollection/view.jsx @@ -1,8 +1,8 @@ import React from 'react'; import { Modal } from 'modal/modal'; import Link from 'component/link/index'; -import UserFieldNew from 'component/userFieldNew'; -import UserFieldVerify from 'component/userFieldVerify'; +import UserPhoneNew from 'component/userPhoneNew'; +import UserPhoneVerify from 'component/userPhoneVerify'; class ModalPhoneCollection extends React.PureComponent { renderInner() { @@ -11,9 +11,9 @@ class ModalPhoneCollection extends React.PureComponent { const cancelButton = ; if (!user.phone_number && !phone) { - return ; + return ; } else if (!user.phone_number) { - return ; + return ; } closeModal(); } diff --git a/src/renderer/page/auth/view.jsx b/src/renderer/page/auth/view.jsx index 908431e26..423ce8597 100644 --- a/src/renderer/page/auth/view.jsx +++ b/src/renderer/page/auth/view.jsx @@ -1,8 +1,8 @@ import React from 'react'; import { BusyMessage } from 'component/common'; import Link from 'component/link'; -import UserFieldNew from 'component/userFieldNew'; -import UserFieldVerify from 'component/userFieldVerify'; +import UserEmailNew from 'component/userEmailNew'; +import UserEmailVerify from 'component/userEmailVerify'; import UserVerify from 'component/userVerify'; export class AuthPage extends React.PureComponent { @@ -45,9 +45,9 @@ export class AuthPage extends React.PureComponent { if (isPending) { return [, true]; } else if (user && !user.has_verified_email && !email) { - return [, true]; + return [, true]; } else if (user && !user.has_verified_email) { - return [, true]; + return [, true]; } else if (user && !user.is_identity_verified) { return [, false]; } From e0de34d43320864f33e4aa4cfea9afd9bff07b3b Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Sun, 21 Jan 2018 23:27:29 -0800 Subject: [PATCH 13/16] Readded email collection modal and trigger at startup --- src/renderer/constants/modal_types.js | 1 + .../modal/modalEmailCollection/index.js | 21 ++++++++++ .../modal/modalEmailCollection/view.jsx | 40 +++++++++++++++++++ src/renderer/modal/modalRouter/view.jsx | 24 +++++++++-- 4 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/renderer/modal/modalEmailCollection/index.js create mode 100644 src/renderer/modal/modalEmailCollection/view.jsx diff --git a/src/renderer/constants/modal_types.js b/src/renderer/constants/modal_types.js index 995060647..19b86238e 100644 --- a/src/renderer/constants/modal_types.js +++ b/src/renderer/constants/modal_types.js @@ -6,6 +6,7 @@ export const ERROR = 'error'; export const INSUFFICIENT_CREDITS = 'insufficient_credits'; export const UPGRADE = 'upgrade'; export const WELCOME = 'welcome'; +export const EMAIL_COLLECTION = 'email_collection'; export const PHONE_COLLECTION = 'phone_collection'; export const FIRST_REWARD = 'first_reward'; export const AUTHENTICATION_FAILURE = 'auth_failure'; diff --git a/src/renderer/modal/modalEmailCollection/index.js b/src/renderer/modal/modalEmailCollection/index.js new file mode 100644 index 000000000..242b9e509 --- /dev/null +++ b/src/renderer/modal/modalEmailCollection/index.js @@ -0,0 +1,21 @@ +import React from 'react'; +import * as settings from 'constants/settings'; +import { connect } from 'react-redux'; +import { doCloseModal } from 'redux/actions/app'; +import { doSetClientSetting } from 'redux/actions/settings'; +import { selectEmailToVerify, selectUser } from 'redux/selectors/user'; +import ModalEmailCollection from './view'; + +const select = state => ({ + email: selectEmailToVerify(state), + user: selectUser(state), +}); + +const perform = dispatch => () => ({ + closeModal: () => { + dispatch(doSetClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED, true)); + dispatch(doCloseModal()); + }, +}); + +export default connect(select, perform)(ModalEmailCollection); diff --git a/src/renderer/modal/modalEmailCollection/view.jsx b/src/renderer/modal/modalEmailCollection/view.jsx new file mode 100644 index 000000000..a17ecf7df --- /dev/null +++ b/src/renderer/modal/modalEmailCollection/view.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { Modal } from 'modal/modal'; +import Link from 'component/link/index'; +import UserEmailNew from 'component/userEmailNew'; +import UserEmailVerify from 'component/userEmailVerify'; + +class ModalEmailCollection extends React.PureComponent { + renderInner() { + const { closeModal, email, user } = this.props; + + const cancelButton = ; + + if (!user.has_verified_email && !email) { + return ; + } else if (!user.has_verified_email) { + return ; + } + closeModal(); + } + + render() { + const { user } = this.props; + + // this shouldn't happen + if (!user) { + return null; + } + + return ( + +
+

Can We Stay In Touch?

+ {this.renderInner()} +
+
+ ); + } +} + +export default ModalEmailCollection; diff --git a/src/renderer/modal/modalRouter/view.jsx b/src/renderer/modal/modalRouter/view.jsx index ac254ed6d..b84272a6c 100644 --- a/src/renderer/modal/modalRouter/view.jsx +++ b/src/renderer/modal/modalRouter/view.jsx @@ -12,6 +12,7 @@ import ModalTransactionFailed from 'modal/modalTransactionFailed'; import ModalFileTimeout from 'modal/modalFileTimeout'; import ModalAffirmPurchase from 'modal/modalAffirmPurchase'; import ModalRevokeClaim from 'modal/modalRevokeClaim'; +import ModalEmailCollection from '../modalEmailCollection'; import ModalPhoneCollection from '../modalPhoneCollection'; import * as modals from 'constants/modal_types'; @@ -40,10 +41,11 @@ class ModalRouter extends React.PureComponent { return; } - const transitionModal = [this.checkShowWelcome, this.checkShowCreditIntro].reduce( - (acc, func) => (!acc ? func.bind(this)(props) : acc), - false - ); + const transitionModal = [ + this.checkShowWelcome, + this.checkShowEmail, + this.checkShowCreditIntro, + ].reduce((acc, func) => (!acc ? func.bind(this)(props) : acc), false); if ( transitionModal && @@ -64,6 +66,18 @@ class ModalRouter extends React.PureComponent { } } + checkShowEmail(props) { + const { isEmailCollectionAcknowledged, isVerificationCandidate, user } = props; + if ( + !isEmailCollectionAcknowledged && + isVerificationCandidate && + user && + !user.has_verified_email + ) { + return modals.EMAIL_COLLECTION; + } + } + checkShowCreditIntro(props) { const { balance, page, isCreditIntroAcknowledged } = props; @@ -113,6 +127,8 @@ class ModalRouter extends React.PureComponent { return ; case modals.PHONE_COLLECTION: return ; + case modals.EMAIL_COLLECTION: + return ; default: return null; } From bdc49691f05156537e1ee92ab5540137c16d343a Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Mon, 22 Jan 2018 14:06:07 -0800 Subject: [PATCH 14/16] Remove unused reducers and action types --- src/renderer/constants/action_types.js | 2 -- src/renderer/redux/reducers/user.js | 6 ------ 2 files changed, 8 deletions(-) diff --git a/src/renderer/constants/action_types.js b/src/renderer/constants/action_types.js index 6e0f40344..a72669b55 100644 --- a/src/renderer/constants/action_types.js +++ b/src/renderer/constants/action_types.js @@ -108,10 +108,8 @@ export const USER_EMAIL_NEW_FAILURE = 'USER_EMAIL_NEW_FAILURE'; export const USER_EMAIL_VERIFY_STARTED = 'USER_EMAIL_VERIFY_STARTED'; export const USER_EMAIL_VERIFY_SUCCESS = 'USER_EMAIL_VERIFY_SUCCESS'; export const USER_EMAIL_VERIFY_FAILURE = 'USER_EMAIL_VERIFY_FAILURE'; -export const USER_PHONE_DECLINE = 'USER_PHONE_DECLINE'; export const USER_PHONE_NEW_STARTED = 'USER_PHONE_NEW_STARTED'; export const USER_PHONE_NEW_SUCCESS = 'USER_PHONE_NEW_SUCCESS'; -export const USER_PHONE_NEW_EXISTS = 'USER_PHONE_NEW_EXISTS'; export const USER_PHONE_NEW_FAILURE = 'USER_PHONE_NEW_FAILURE'; export const USER_PHONE_VERIFY_STARTED = 'USER_PHONE_VERIFY_STARTED'; export const USER_PHONE_VERIFY_SUCCESS = 'USER_PHONE_VERIFY_SUCCESS'; diff --git a/src/renderer/redux/reducers/user.js b/src/renderer/redux/reducers/user.js index 3d2ea165c..c74428896 100644 --- a/src/renderer/redux/reducers/user.js +++ b/src/renderer/redux/reducers/user.js @@ -71,12 +71,6 @@ reducers[ACTIONS.USER_PHONE_NEW_SUCCESS] = (state, action) => phoneNewIsPending: false, }); -reducers[ACTIONS.USER_PHONE_NEW_EXISTS] = (state, action) => - Object.assign({}, state, { - phoneToVerify: action.data.phone, - phoneNewIsPending: false, - }); - reducers[ACTIONS.USER_PHONE_NEW_FAILURE] = (state, action) => Object.assign({}, state, { phoneNewIsPending: false, From 23261d07590844cf34568be4d20d38897402ace9 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Mon, 22 Jan 2018 14:46:14 -0800 Subject: [PATCH 15/16] Removed emojis on Windows and Linux --- src/renderer/component/userPhoneNew/view.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/renderer/component/userPhoneNew/view.jsx b/src/renderer/component/userPhoneNew/view.jsx index 593fd17b9..b9999c746 100644 --- a/src/renderer/component/userPhoneNew/view.jsx +++ b/src/renderer/component/userPhoneNew/view.jsx @@ -2,6 +2,7 @@ import React from 'react'; import { Form, FormRow, Submit } from 'component/form.js'; import FormField from 'component/formField'; +const os = require('os').type(); const countryCodes = require('country-data') .callingCountries.all.filter(_ => _.emoji) .reduce( @@ -79,7 +80,8 @@ class UserPhoneNew extends React.PureComponent { {countryCodes.map((country, index) => ( ))} From ca9f67b240c253049b83b9753c91a0ad32366e21 Mon Sep 17 00:00:00 2001 From: Liam Cardenas Date: Mon, 22 Jan 2018 15:26:34 -0800 Subject: [PATCH 16/16] Added reset button on phone verification --- src/renderer/component/userPhoneVerify/index.js | 3 ++- src/renderer/component/userPhoneVerify/view.jsx | 13 +++++++++++-- src/renderer/constants/action_types.js | 1 + src/renderer/redux/actions/user.js | 6 ++++++ src/renderer/redux/reducers/user.js | 5 +++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/renderer/component/userPhoneVerify/index.js b/src/renderer/component/userPhoneVerify/index.js index 89b18a120..fea5e2893 100644 --- a/src/renderer/component/userPhoneVerify/index.js +++ b/src/renderer/component/userPhoneVerify/index.js @@ -1,6 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; -import { doUserPhoneVerify } from 'redux/actions/user'; +import { doUserPhoneVerify, doUserPhoneReset } from 'redux/actions/user'; import { selectPhoneToVerify, selectPhoneVerifyErrorMessage, @@ -15,6 +15,7 @@ const select = state => ({ }); const perform = dispatch => ({ + resetPhone: () => dispatch(doUserPhoneReset()), verifyUserPhone: code => dispatch(doUserPhoneVerify(code)), }); diff --git a/src/renderer/component/userPhoneVerify/view.jsx b/src/renderer/component/userPhoneVerify/view.jsx index 027b18c38..2ee39c1e8 100644 --- a/src/renderer/component/userPhoneVerify/view.jsx +++ b/src/renderer/component/userPhoneVerify/view.jsx @@ -22,13 +22,22 @@ class UserPhoneVerify extends React.PureComponent { this.props.verifyUserPhone(code); } + reset() { + const { resetPhone } = this.props; + resetPhone(); + } + render() { const { cancelButton, phoneErrorMessage, phone, countryCode } = this.props; return (

- Please enter the verification code sent to {`+${countryCode}`} - {phone}. + {__( + `Please enter the verification code sent to +${countryCode}${ + phone + }. Didn't receive it? ` + )} +

{ dispatch({ diff --git a/src/renderer/redux/reducers/user.js b/src/renderer/redux/reducers/user.js index c74428896..870eaee9e 100644 --- a/src/renderer/redux/reducers/user.js +++ b/src/renderer/redux/reducers/user.js @@ -71,6 +71,11 @@ reducers[ACTIONS.USER_PHONE_NEW_SUCCESS] = (state, action) => phoneNewIsPending: false, }); +reducers[ACTIONS.USER_PHONE_RESET] = state => + Object.assign({}, state, { + phoneToVerify: null, + }); + reducers[ACTIONS.USER_PHONE_NEW_FAILURE] = (state, action) => Object.assign({}, state, { phoneNewIsPending: false,