commit
f47108c4c0
18 changed files with 498 additions and 5 deletions
|
@ -36,6 +36,7 @@
|
||||||
"amplitude-js": "^4.0.0",
|
"amplitude-js": "^4.0.0",
|
||||||
"bluebird": "^3.5.1",
|
"bluebird": "^3.5.1",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
|
"country-data": "^0.0.31",
|
||||||
"electron-dl": "^1.6.0",
|
"electron-dl": "^1.6.0",
|
||||||
"formik": "^0.10.4",
|
"formik": "^0.10.4",
|
||||||
"from2": "^2.3.0",
|
"from2": "^2.3.0",
|
||||||
|
|
15
src/renderer/component/userPhoneNew/index.js
Normal file
15
src/renderer/component/userPhoneNew/index.js
Normal file
|
@ -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);
|
109
src/renderer/component/userPhoneNew/view.jsx
Normal file
109
src/renderer/component/userPhoneNew/view.jsx
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
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(
|
||||||
|
(acc, cur) => acc.concat(cur.countryCallingCodes.map(_ => ({ ...cur, countryCallingCode: _ }))),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.countryCallingCode < b.countryCallingCode) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.countryCallingCode > b.countryCallingCode) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
class UserPhoneNew extends React.PureComponent {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
phone: '',
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChanged(event) {
|
||||||
|
this.setState({
|
||||||
|
phone: this.formatPhone(event.target.value),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSelect(event) {
|
||||||
|
this.setState({ country_code: event.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit() {
|
||||||
|
const { phone, country_code } = this.state;
|
||||||
|
this.props.addUserPhone(phone.replace(/\D/g, ''), country_code.substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { cancelButton, phoneErrorMessage, isPending } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
'Enter your phone number and we will send you a verification code. We will not share your phone number with third parties.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<Form onSubmit={this.handleSubmit.bind(this)}>
|
||||||
|
<div className="form-row-phone">
|
||||||
|
<FormField type="select" onChange={this.handleSelect.bind(this)}>
|
||||||
|
{countryCodes.map((country, index) => (
|
||||||
|
<option key={index} value={country.countryCallingCode}>
|
||||||
|
{os === 'Darwin' ? country.emoji : `(${country.alpha2})`}{' '}
|
||||||
|
{country.countryCallingCode}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</FormField>
|
||||||
|
<FormRow
|
||||||
|
type="text"
|
||||||
|
placeholder={this.state.country_code === '+1' ? '(555) 555-5555' : '5555555555'}
|
||||||
|
name="phone"
|
||||||
|
value={this.state.phone}
|
||||||
|
errorMessage={phoneErrorMessage}
|
||||||
|
onChange={event => {
|
||||||
|
this.handleChanged(event);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-row-submit">
|
||||||
|
<Submit label="Submit" disabled={isPending} />
|
||||||
|
{cancelButton}
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserPhoneNew;
|
22
src/renderer/component/userPhoneVerify/index.js
Normal file
22
src/renderer/component/userPhoneVerify/index.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doUserPhoneVerify, doUserPhoneReset } 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 => ({
|
||||||
|
resetPhone: () => dispatch(doUserPhoneReset()),
|
||||||
|
verifyUserPhone: code => dispatch(doUserPhoneVerify(code)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(UserPhoneVerify);
|
69
src/renderer/component/userPhoneVerify/view.jsx
Normal file
69
src/renderer/component/userPhoneVerify/view.jsx
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
const { resetPhone } = this.props;
|
||||||
|
resetPhone();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { cancelButton, phoneErrorMessage, phone, countryCode } = this.props;
|
||||||
|
return (
|
||||||
|
<Form onSubmit={this.handleSubmit.bind(this)}>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
`Please enter the verification code sent to +${countryCode}${
|
||||||
|
phone
|
||||||
|
}. Didn't receive it? `
|
||||||
|
)}
|
||||||
|
<Link onClick={this.reset.bind(this)} label="Go back." />
|
||||||
|
</p>
|
||||||
|
<FormRow
|
||||||
|
type="text"
|
||||||
|
label={__('Verification Code')}
|
||||||
|
name="code"
|
||||||
|
value={this.state.code}
|
||||||
|
onChange={event => {
|
||||||
|
this.handleCodeChanged(event);
|
||||||
|
}}
|
||||||
|
errorMessage={phoneErrorMessage}
|
||||||
|
/>
|
||||||
|
{/* render help separately so it always shows */}
|
||||||
|
<div className="form-field__helper">
|
||||||
|
<p>
|
||||||
|
{__('Email')} <Link href="mailto:help@lbry.io" label="help@lbry.io" /> or join our{' '}
|
||||||
|
<Link href="https://chat.lbry.io" label="chat" />{' '}
|
||||||
|
{__('if you encounter any trouble with your code.')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="form-row-submit">
|
||||||
|
<Submit label={__('Verify')} />
|
||||||
|
{cancelButton}
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserPhoneVerify;
|
|
@ -9,6 +9,9 @@ import {
|
||||||
selectIdentityVerifyErrorMessage,
|
selectIdentityVerifyErrorMessage,
|
||||||
} from 'redux/selectors/user';
|
} from 'redux/selectors/user';
|
||||||
import UserVerify from './view';
|
import UserVerify from './view';
|
||||||
|
import { selectCurrentModal } from 'redux/selectors/app';
|
||||||
|
import { doOpenModal } from 'redux/actions/app';
|
||||||
|
import { PHONE_COLLECTION } from 'constants/modal_types';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const selectReward = makeSelectRewardByType();
|
const selectReward = makeSelectRewardByType();
|
||||||
|
@ -17,12 +20,14 @@ const select = (state, props) => {
|
||||||
isPending: selectIdentityVerifyIsPending(state),
|
isPending: selectIdentityVerifyIsPending(state),
|
||||||
errorMessage: selectIdentityVerifyErrorMessage(state),
|
errorMessage: selectIdentityVerifyErrorMessage(state),
|
||||||
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
||||||
|
modal: selectCurrentModal(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: uri => dispatch(doNavigate(uri)),
|
navigate: uri => dispatch(doNavigate(uri)),
|
||||||
verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)),
|
verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)),
|
||||||
|
verifyPhone: () => dispatch(doOpenModal(PHONE_COLLECTION)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(UserVerify);
|
export default connect(select, perform)(UserVerify);
|
||||||
|
|
|
@ -23,7 +23,7 @@ class UserVerify extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { errorMessage, isPending, navigate } = this.props;
|
const { errorMessage, isPending, navigate, verifyPhone, modal } = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<section className="card card--form">
|
<section className="card card--form">
|
||||||
|
@ -66,7 +66,30 @@ class UserVerify extends React.PureComponent {
|
||||||
</section>
|
</section>
|
||||||
<section className="card card--form">
|
<section className="card card--form">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('2) Proof via YouTube')}</h3>
|
<h3>{__('2) Proof via Phone')}</h3>
|
||||||
|
</div>
|
||||||
|
<div className="card__content">
|
||||||
|
{`${__(
|
||||||
|
'You will receive an SMS text message confirming that your phone number is correct.'
|
||||||
|
)}`}
|
||||||
|
</div>
|
||||||
|
<div className="card__actions">
|
||||||
|
<Link
|
||||||
|
onClick={() => {
|
||||||
|
verifyPhone();
|
||||||
|
}}
|
||||||
|
button="alt"
|
||||||
|
icon="icon-phone"
|
||||||
|
label={__('Submit Phone Number')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="card__content">
|
||||||
|
<div className="meta">{__('Standard messaging rates apply.')} </div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section className="card card--form">
|
||||||
|
<div className="card__title-primary">
|
||||||
|
<h3>{__('3) Proof via YouTube')}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<p>
|
<p>
|
||||||
|
@ -96,7 +119,7 @@ class UserVerify extends React.PureComponent {
|
||||||
</section>
|
</section>
|
||||||
<section className="card card--form">
|
<section className="card card--form">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('3) Proof via Chat')}</h3>
|
<h3>{__('4) Proof via Chat')}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -109,6 +109,13 @@ 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_STARTED = 'USER_EMAIL_VERIFY_STARTED';
|
||||||
export const USER_EMAIL_VERIFY_SUCCESS = 'USER_EMAIL_VERIFY_SUCCESS';
|
export const USER_EMAIL_VERIFY_SUCCESS = 'USER_EMAIL_VERIFY_SUCCESS';
|
||||||
export const USER_EMAIL_VERIFY_FAILURE = 'USER_EMAIL_VERIFY_FAILURE';
|
export const USER_EMAIL_VERIFY_FAILURE = 'USER_EMAIL_VERIFY_FAILURE';
|
||||||
|
export const USER_PHONE_RESET = 'USER_PHONE_RESET';
|
||||||
|
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_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_STARTED = 'USER_IDENTITY_VERIFY_STARTED';
|
||||||
export const USER_IDENTITY_VERIFY_SUCCESS = 'USER_IDENTITY_VERIFY_SUCCESS';
|
export const USER_IDENTITY_VERIFY_SUCCESS = 'USER_IDENTITY_VERIFY_SUCCESS';
|
||||||
export const USER_IDENTITY_VERIFY_FAILURE = 'USER_IDENTITY_VERIFY_FAILURE';
|
export const USER_IDENTITY_VERIFY_FAILURE = 'USER_IDENTITY_VERIFY_FAILURE';
|
||||||
|
|
|
@ -7,6 +7,7 @@ export const INSUFFICIENT_CREDITS = 'insufficient_credits';
|
||||||
export const UPGRADE = 'upgrade';
|
export const UPGRADE = 'upgrade';
|
||||||
export const WELCOME = 'welcome';
|
export const WELCOME = 'welcome';
|
||||||
export const EMAIL_COLLECTION = 'email_collection';
|
export const EMAIL_COLLECTION = 'email_collection';
|
||||||
|
export const PHONE_COLLECTION = 'phone_collection';
|
||||||
export const FIRST_REWARD = 'first_reward';
|
export const FIRST_REWARD = 'first_reward';
|
||||||
export const AUTHENTICATION_FAILURE = 'auth_failure';
|
export const AUTHENTICATION_FAILURE = 'auth_failure';
|
||||||
export const TRANSACTION_FAILED = 'transaction_failed';
|
export const TRANSACTION_FAILED = 'transaction_failed';
|
||||||
|
|
22
src/renderer/modal/modalPhoneCollection/index.js
Normal file
22
src/renderer/modal/modalPhoneCollection/index.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
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 { selectPhoneToVerify, selectUser } from 'redux/selectors/user';
|
||||||
|
import ModalPhoneCollection from './view';
|
||||||
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
phone: selectPhoneToVerify(state),
|
||||||
|
user: selectUser(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => () => ({
|
||||||
|
closeModal: () => {
|
||||||
|
dispatch(doCloseModal());
|
||||||
|
dispatch(doNavigate('/rewards'));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(ModalPhoneCollection);
|
40
src/renderer/modal/modalPhoneCollection/view.jsx
Normal file
40
src/renderer/modal/modalPhoneCollection/view.jsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Modal } from 'modal/modal';
|
||||||
|
import Link from 'component/link/index';
|
||||||
|
import UserPhoneNew from 'component/userPhoneNew';
|
||||||
|
import UserPhoneVerify from 'component/userPhoneVerify';
|
||||||
|
|
||||||
|
class ModalPhoneCollection extends React.PureComponent {
|
||||||
|
renderInner() {
|
||||||
|
const { closeModal, phone, user } = this.props;
|
||||||
|
|
||||||
|
const cancelButton = <Link button="text" onClick={closeModal} label={__('Not Now')} />;
|
||||||
|
|
||||||
|
if (!user.phone_number && !phone) {
|
||||||
|
return <UserPhoneNew cancelButton={cancelButton} />;
|
||||||
|
} else if (!user.phone_number) {
|
||||||
|
return <UserPhoneVerify cancelButton={cancelButton} />;
|
||||||
|
}
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { user } = this.props;
|
||||||
|
|
||||||
|
// this shouldn't happen
|
||||||
|
if (!user) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal type="custom" isOpen contentLabel="Phone">
|
||||||
|
<section>
|
||||||
|
<h3 className="modal__header">Verify Your Phone</h3>
|
||||||
|
{this.renderInner()}
|
||||||
|
</section>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalPhoneCollection;
|
|
@ -13,6 +13,7 @@ import ModalFileTimeout from 'modal/modalFileTimeout';
|
||||||
import ModalAffirmPurchase from 'modal/modalAffirmPurchase';
|
import ModalAffirmPurchase from 'modal/modalAffirmPurchase';
|
||||||
import ModalRevokeClaim from 'modal/modalRevokeClaim';
|
import ModalRevokeClaim from 'modal/modalRevokeClaim';
|
||||||
import ModalEmailCollection from '../modalEmailCollection';
|
import ModalEmailCollection from '../modalEmailCollection';
|
||||||
|
import ModalPhoneCollection from '../modalPhoneCollection';
|
||||||
import * as modals from 'constants/modal_types';
|
import * as modals from 'constants/modal_types';
|
||||||
|
|
||||||
class ModalRouter extends React.PureComponent {
|
class ModalRouter extends React.PureComponent {
|
||||||
|
@ -124,6 +125,8 @@ class ModalRouter extends React.PureComponent {
|
||||||
return <ModalAffirmPurchase {...modalProps} />;
|
return <ModalAffirmPurchase {...modalProps} />;
|
||||||
case modals.CONFIRM_CLAIM_REVOKE:
|
case modals.CONFIRM_CLAIM_REVOKE:
|
||||||
return <ModalRevokeClaim {...modalProps} />;
|
return <ModalRevokeClaim {...modalProps} />;
|
||||||
|
case modals.PHONE_COLLECTION:
|
||||||
|
return <ModalPhoneCollection {...modalProps} />;
|
||||||
case modals.EMAIL_COLLECTION:
|
case modals.EMAIL_COLLECTION:
|
||||||
return <ModalEmailCollection {...modalProps} />;
|
return <ModalEmailCollection {...modalProps} />;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -3,7 +3,11 @@ import * as MODALS from 'constants/modal_types';
|
||||||
import Lbryio from 'lbryio';
|
import Lbryio from 'lbryio';
|
||||||
import { doOpenModal, doShowSnackBar } from 'redux/actions/app';
|
import { doOpenModal, doShowSnackBar } from 'redux/actions/app';
|
||||||
import { doClaimRewardType, doRewardList } from 'redux/actions/rewards';
|
import { doClaimRewardType, doRewardList } from 'redux/actions/rewards';
|
||||||
import { selectEmailToVerify } from 'redux/selectors/user';
|
import {
|
||||||
|
selectEmailToVerify,
|
||||||
|
selectPhoneToVerify,
|
||||||
|
selectUserCountryCode,
|
||||||
|
} from 'redux/selectors/user';
|
||||||
import rewards from 'rewards';
|
import rewards from 'rewards';
|
||||||
|
|
||||||
export function doFetchInviteStatus() {
|
export function doFetchInviteStatus() {
|
||||||
|
@ -78,6 +82,78 @@ export function doUserFetch() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doUserPhoneReset() {
|
||||||
|
return {
|
||||||
|
type: ACTIONS.USER_PHONE_RESET,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doUserPhoneNew(phone, country_code) {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.USER_PHONE_NEW_STARTED,
|
||||||
|
data: { phone, country_code },
|
||||||
|
});
|
||||||
|
|
||||||
|
const success = () => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.USER_PHONE_NEW_SUCCESS,
|
||||||
|
data: { phone },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const failure = () => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.USER_PHONE_NEW_FAILURE,
|
||||||
|
data: { error: 'An error occurred while processing this phone number.' },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Lbryio.call('user', 'phone_number_new', { phone_number: phone, country_code }, '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 phoneNumber = selectPhoneToVerify(getState());
|
||||||
|
const countryCode = selectUserCountryCode(getState());
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.USER_PHONE_VERIFY_STARTED,
|
||||||
|
code: verificationCode,
|
||||||
|
});
|
||||||
|
|
||||||
|
Lbryio.call(
|
||||||
|
'user',
|
||||||
|
'phone_number_confirm',
|
||||||
|
{
|
||||||
|
verification_code: verificationCode,
|
||||||
|
phone_number: phoneNumber,
|
||||||
|
country_code: countryCode,
|
||||||
|
},
|
||||||
|
'post'
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.USER_PHONE_VERIFY_SUCCESS,
|
||||||
|
data: { phone_number: phoneNumber },
|
||||||
|
});
|
||||||
|
dispatch(doUserFetch());
|
||||||
|
})
|
||||||
|
.catch(error => dispatch(doUserPhoneVerifyFailure(error)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function doUserEmailNew(email) {
|
export function doUserEmailNew(email) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -55,6 +55,55 @@ reducers[ACTIONS.USER_FETCH_FAILURE] = state =>
|
||||||
user: null,
|
user: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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, {
|
||||||
|
phoneToVerify: action.data.phone,
|
||||||
|
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,
|
||||||
|
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 =>
|
reducers[ACTIONS.USER_EMAIL_NEW_STARTED] = state =>
|
||||||
Object.assign({}, state, {
|
Object.assign({}, state, {
|
||||||
emailNewIsPending: true,
|
emailNewIsPending: true,
|
||||||
|
|
|
@ -16,12 +16,28 @@ export const selectUserEmail = createSelector(
|
||||||
user => (user ? user.primary_email : null)
|
user => (user ? user.primary_email : null)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectUserPhone = createSelector(
|
||||||
|
selectUser,
|
||||||
|
user => (user ? user.phone_number : null)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectUserCountryCode = createSelector(
|
||||||
|
selectUser,
|
||||||
|
user => (user ? user.country_code : null)
|
||||||
|
);
|
||||||
|
|
||||||
export const selectEmailToVerify = createSelector(
|
export const selectEmailToVerify = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
selectUserEmail,
|
selectUserEmail,
|
||||||
(state, userEmail) => state.emailToVerify || userEmail
|
(state, userEmail) => state.emailToVerify || userEmail
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectPhoneToVerify = createSelector(
|
||||||
|
selectState,
|
||||||
|
selectUserPhone,
|
||||||
|
(state, userPhone) => state.phoneToVerify || userPhone
|
||||||
|
);
|
||||||
|
|
||||||
export const selectUserIsRewardApproved = createSelector(
|
export const selectUserIsRewardApproved = createSelector(
|
||||||
selectUser,
|
selectUser,
|
||||||
user => user && user.is_reward_approved
|
user => user && user.is_reward_approved
|
||||||
|
@ -37,6 +53,11 @@ export const selectEmailNewErrorMessage = createSelector(
|
||||||
state => state.emailNewErrorMessage
|
state => state.emailNewErrorMessage
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectPhoneNewErrorMessage = createSelector(
|
||||||
|
selectState,
|
||||||
|
state => state.phoneNewErrorMessage
|
||||||
|
);
|
||||||
|
|
||||||
export const selectEmailVerifyIsPending = createSelector(
|
export const selectEmailVerifyIsPending = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
state => state.emailVerifyIsPending
|
state => state.emailVerifyIsPending
|
||||||
|
@ -47,6 +68,11 @@ export const selectEmailVerifyErrorMessage = createSelector(
|
||||||
state => state.emailVerifyErrorMessage
|
state => state.emailVerifyErrorMessage
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectPhoneVerifyErrorMessage = createSelector(
|
||||||
|
selectState,
|
||||||
|
state => state.phoneVerifyErrorMessage
|
||||||
|
);
|
||||||
|
|
||||||
export const selectIdentityVerifyIsPending = createSelector(
|
export const selectIdentityVerifyIsPending = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
state => state.identityVerifyIsPending
|
state => state.identityVerifyIsPending
|
||||||
|
|
|
@ -79,6 +79,7 @@ $text-color: #000;
|
||||||
/* Select */
|
/* Select */
|
||||||
--select-bg: var(--color-bg-alt);
|
--select-bg: var(--color-bg-alt);
|
||||||
--select-color: var(--text-color);
|
--select-color: var(--text-color);
|
||||||
|
--select-height: 30px;
|
||||||
|
|
||||||
/* Button */
|
/* Button */
|
||||||
--button-bg: var(--color-bg-alt);
|
--button-bg: var(--color-bg-alt);
|
||||||
|
|
|
@ -5,6 +5,15 @@
|
||||||
margin-bottom: $spacing-vertical;
|
margin-bottom: $spacing-vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-row-phone {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.form-field__input-text {
|
||||||
|
margin-left: 5px;
|
||||||
|
width: calc(0.85 * var(--input-width));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.form-row__label-row {
|
.form-row__label-row {
|
||||||
margin-top: $spacing-vertical * 5/6;
|
margin-top: $spacing-vertical * 5/6;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
|
@ -32,7 +41,7 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
height: $spacing-vertical;
|
height: var(--select-height);
|
||||||
background: var(--select-bg);
|
background: var(--select-bg);
|
||||||
color: var(--select-color);
|
color: var(--select-color);
|
||||||
&:focus {
|
&:focus {
|
||||||
|
|
15
yarn.lock
15
yarn.lock
|
@ -2213,6 +2213,13 @@ cosmiconfig@^3.1.0:
|
||||||
parse-json "^3.0.0"
|
parse-json "^3.0.0"
|
||||||
require-from-string "^2.0.1"
|
require-from-string "^2.0.1"
|
||||||
|
|
||||||
|
country-data@^0.0.31:
|
||||||
|
version "0.0.31"
|
||||||
|
resolved "https://registry.yarnpkg.com/country-data/-/country-data-0.0.31.tgz#80966b8e1d147fa6d6a589d32933f8793774956d"
|
||||||
|
dependencies:
|
||||||
|
currency-symbol-map "~2"
|
||||||
|
underscore ">1.4.4"
|
||||||
|
|
||||||
create-ecdh@^4.0.0:
|
create-ecdh@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
|
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"
|
clap "^1.0.9"
|
||||||
source-map "^0.5.3"
|
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:
|
currently-unhandled@^0.4.1:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
|
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
|
||||||
|
@ -8812,6 +8823,10 @@ unc-path-regex@^0.1.0:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
|
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:
|
uniq@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
|
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
|
||||||
|
|
Loading…
Add table
Reference in a new issue