good chunk of progress towards auth and rewards refactor / degating
This commit is contained in:
parent
eb170b9720
commit
a17d19038e
18 changed files with 344 additions and 196 deletions
|
@ -26,20 +26,36 @@ export function doClaimReward(reward) {
|
||||||
type: types.CLAIM_REWARD_STARTED,
|
type: types.CLAIM_REWARD_STARTED,
|
||||||
data: { reward }
|
data: { reward }
|
||||||
})
|
})
|
||||||
try {
|
|
||||||
const success = (a) => {
|
const success = (a) => {
|
||||||
console.log(a)
|
console.log(a)
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.CLAIM_REWARD_COMPLETED,
|
type: types.CLAIM_REWARD_SUCCESS,
|
||||||
data: {
|
data: {
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
const failure = (a) => console.error(a)
|
|
||||||
rewards.claimReward(reward.reward_type).then(success, failure)
|
|
||||||
} catch(err) {
|
|
||||||
console.error(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const failure = (error) => {
|
||||||
|
dispatch({
|
||||||
|
type: types.CLAIM_REWARD_FAILURE,
|
||||||
|
data: {
|
||||||
|
reward,
|
||||||
|
error
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
rewards.claimReward(reward.reward_type).then(success, failure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doClaimRewardClearError(reward) {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
dispatch({
|
||||||
|
type: types.CLAIM_REWARD_CLEAR_ERROR,
|
||||||
|
data: { reward }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
import * as types from 'constants/action_types'
|
import * as types from 'constants/action_types'
|
||||||
import lbryio from 'lbryio'
|
import lbryio from 'lbryio'
|
||||||
|
import {
|
||||||
|
setLocal
|
||||||
|
} from 'utils'
|
||||||
|
import {
|
||||||
|
doFetchRewards
|
||||||
|
} from 'actions/rewards'
|
||||||
|
|
||||||
export function doAuthenticate() {
|
export function doAuthenticate() {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
|
@ -18,4 +24,39 @@ export function doAuthenticate() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doUserEmailNew(email) {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
dispatch({
|
||||||
|
type: types.USER_EMAIL_NEW_STARTED,
|
||||||
|
})
|
||||||
|
lbryio.call('user_email', 'new', { email }, 'post').then(() => {
|
||||||
|
dispatch({
|
||||||
|
type: types.USER_EMAIL_NEW_SUCCESS,
|
||||||
|
data: { email }
|
||||||
|
})
|
||||||
|
}, (error) => {
|
||||||
|
if (error.xhr && (error.xhr.status == 409 || error.message == "This email is already in use")) {
|
||||||
|
dispatch({
|
||||||
|
type: types.USER_EMAIL_NEW_EXISTS,
|
||||||
|
data: { email }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
dispatch({
|
||||||
|
type: types.USER_EMAIL_NEW_FAILURE,
|
||||||
|
data: { error: error.message }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doUserEmailDecline() {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
setLocal('user_email_declined', true)
|
||||||
|
dispatch({
|
||||||
|
type: types.USER_EMAIL_DECLINE,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,19 +3,23 @@ import {
|
||||||
connect
|
connect
|
||||||
} from 'react-redux'
|
} from 'react-redux'
|
||||||
import {
|
import {
|
||||||
doStartUpgrade,
|
doUserEmailDecline
|
||||||
doCancelUpgrade,
|
} from 'actions/user'
|
||||||
} from 'actions/app'
|
|
||||||
import {
|
import {
|
||||||
selectAuthenticationIsPending,
|
selectAuthenticationIsPending,
|
||||||
|
selectEmailNewDeclined,
|
||||||
|
selectUser,
|
||||||
} from 'selectors/user'
|
} from 'selectors/user'
|
||||||
import AuthOverlay from './view'
|
import AuthOverlay from './view'
|
||||||
|
|
||||||
const select = (state) => ({
|
const select = (state) => ({
|
||||||
isPending: selectAuthenticationIsPending(state)
|
isPending: selectAuthenticationIsPending(state),
|
||||||
|
isEmailDeclined: selectEmailNewDeclined(state),
|
||||||
|
user: selectUser(state),
|
||||||
})
|
})
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
|
userEmailDecline: () => dispatch(doUserEmailDecline())
|
||||||
})
|
})
|
||||||
|
|
||||||
export default connect(select, perform)(AuthOverlay)
|
export default connect(select, perform)(AuthOverlay)
|
||||||
|
|
|
@ -5,73 +5,34 @@ import Modal from "component/modal.js";
|
||||||
import ModalPage from "component/modal-page.js";
|
import ModalPage from "component/modal-page.js";
|
||||||
import Link from "component/link"
|
import Link from "component/link"
|
||||||
import {BusyMessage} from "component/common"
|
import {BusyMessage} from "component/common"
|
||||||
import {RewardLink} from 'component/reward-link';
|
import {RewardLink} from 'component/rewardLink';
|
||||||
|
import UserEmailNew from 'component/userEmailNew';
|
||||||
import {FormRow} from "component/form.js";
|
import {FormRow} from "component/form.js";
|
||||||
import {CreditAmount, Address} from "component/common.js";
|
import {CreditAmount, Address} from "component/common.js";
|
||||||
import {getLocal, setLocal} from 'utils.js';
|
import {getLocal, setLocal} from 'utils.js';
|
||||||
import rewards from 'rewards'
|
|
||||||
|
|
||||||
|
class EmailStage extends React.Component {
|
||||||
class SubmitEmailStage extends React.Component {
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
rewardType: null,
|
|
||||||
email: '',
|
|
||||||
showNoEmailConfirm: false,
|
showNoEmailConfirm: false,
|
||||||
submitting: false
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEmailChanged(event) {
|
|
||||||
this.setState({
|
|
||||||
email: event.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onEmailSaved(email) {
|
|
||||||
this.props.setStage("confirm", { email: email })
|
|
||||||
}
|
|
||||||
|
|
||||||
onEmailSkipClick() {
|
onEmailSkipClick() {
|
||||||
this.setState({ showNoEmailConfirm: true })
|
this.setState({ showNoEmailConfirm: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
onEmailSkipConfirm() {
|
onEmailSkipConfirm() {
|
||||||
setLocal('auth_bypassed', true);
|
this.props.userEmailDecline()
|
||||||
this.props.setStage(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSubmit(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
submitting: true,
|
|
||||||
});
|
|
||||||
lbryio.call('user_email', 'new', {email: this.state.email}, 'post').then(() => {
|
|
||||||
this.onEmailSaved(this.state.email);
|
|
||||||
}, (error) => {
|
|
||||||
if (error.xhr && (error.xhr.status == 409 || error.message == "This email is already in use")) {
|
|
||||||
this.onEmailSaved(this.state.email);
|
|
||||||
return;
|
|
||||||
} else if (this._emailRow) {
|
|
||||||
this._emailRow.showError(error.message)
|
|
||||||
}
|
|
||||||
this.setState({ submitting: false });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<form onSubmit={(event) => { this.handleSubmit(event) }}>
|
<UserEmailNew />
|
||||||
<FormRow ref={(ref) => { this._emailRow = ref }} type="text" label="Email" placeholder="scrwvwls@lbry.io"
|
<div className="form-row-submit">
|
||||||
name="email" value={this.state.email}
|
|
||||||
onChange={(event) => { this.handleEmailChanged(event) }} />
|
|
||||||
<div className="form-row-submit form-row-submit--with-footer">
|
|
||||||
<Link button="primary" label="Next" disabled={this.state.submitting} onClick={(event) => { this.handleSubmit(event) }} />
|
|
||||||
</div>
|
|
||||||
{ this.state.showNoEmailConfirm ?
|
{ this.state.showNoEmailConfirm ?
|
||||||
<div>
|
<div>
|
||||||
<p className="help form-input-width">If you continue without an email, you will be ineligible to earn free LBC rewards, as well as unable to receive security related communications.</p>
|
<p className="help form-input-width">If you continue without an email, you will be ineligible to earn free LBC rewards, as well as unable to receive security related communications.</p>
|
||||||
|
@ -80,7 +41,7 @@ class SubmitEmailStage extends React.Component {
|
||||||
:
|
:
|
||||||
<Link className="button-text-help" onClick={ () => { this.onEmailSkipClick() }} label="Do I have to?" />
|
<Link className="button-text-help" onClick={ () => { this.onEmailSkipClick() }} label="Do I have to?" />
|
||||||
}
|
}
|
||||||
</form>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +52,6 @@ class ConfirmEmailStage extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
rewardType: null,
|
|
||||||
code: '',
|
code: '',
|
||||||
submitting: false,
|
submitting: false,
|
||||||
errorMessage: null,
|
errorMessage: null,
|
||||||
|
@ -275,10 +235,8 @@ export class AuthOverlay extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this._stages = {
|
this._stages = {
|
||||||
pending: PendingStage,
|
|
||||||
error: ErrorStage,
|
error: ErrorStage,
|
||||||
nocode: CodeRequiredStage,
|
nocode: CodeRequiredStage,
|
||||||
email: SubmitEmailStage,
|
|
||||||
confirm: ConfirmEmailStage,
|
confirm: ConfirmEmailStage,
|
||||||
welcome: WelcomeStage
|
welcome: WelcomeStage
|
||||||
}
|
}
|
||||||
|
@ -320,21 +278,35 @@ export class AuthOverlay extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let StageContent
|
let stageContent
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isPending,
|
isPending,
|
||||||
|
isEmailDeclined,
|
||||||
|
user,
|
||||||
|
userEmailDecline
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
if (isPending) {
|
console.log('auth overlay render')
|
||||||
StageContent = PendingStage;
|
console.log(user)
|
||||||
} else {
|
|
||||||
|
if (isEmailDeclined) {
|
||||||
return null
|
return null
|
||||||
StageContent = this._stages[this.state.stage];
|
} else if (isPending) {
|
||||||
|
stageContent = <PendingStage />;
|
||||||
|
} else if (!user.has_email) {
|
||||||
|
stageContent = <EmailStage userEmailDecline={userEmailDecline} />;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null
|
||||||
|
//StageContent = this._stages[this.state.stage];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StageContent) {
|
return <ModalPage className="modal-page--full" isOpen={true} contentLabel="Authentication">
|
||||||
return <span className="empty">Unknown authentication step.</span>
|
<h1>LBRY Early Access</h1>
|
||||||
}
|
{stageContent}
|
||||||
|
</ModalPage>;
|
||||||
|
|
||||||
//setStage={(stage, stageProps) => { this.setStage(stage, stageProps) }} {...this.state.stageProps}
|
//setStage={(stage, stageProps) => { this.setStage(stage, stageProps) }} {...this.state.stageProps}
|
||||||
return (
|
return (
|
||||||
true || this.state.stage != "welcome" ?
|
true || this.state.stage != "welcome" ?
|
||||||
|
|
|
@ -179,8 +179,8 @@ export class FormRow extends React.Component {
|
||||||
this._fieldRequiredText = __("This field is required");
|
this._fieldRequiredText = __("This field is required");
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isError: false,
|
isError: !!props.errorMessage,
|
||||||
errorMessage: null,
|
errorMessage: typeof props.errorMessage === "string" ? props.errorMessage : '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +225,7 @@ export class FormRow extends React.Component {
|
||||||
delete fieldProps.label;
|
delete fieldProps.label;
|
||||||
}
|
}
|
||||||
delete fieldProps.helper;
|
delete fieldProps.helper;
|
||||||
|
delete fieldProps.errorMessage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
|
|
|
@ -4,17 +4,24 @@ import {
|
||||||
} from 'react-redux'
|
} from 'react-redux'
|
||||||
import {
|
import {
|
||||||
makeSelectHasClaimedReward,
|
makeSelectHasClaimedReward,
|
||||||
|
makeSelectClaimRewardError,
|
||||||
|
makeSelectIsRewardClaimPending
|
||||||
} from 'selectors/rewards'
|
} from 'selectors/rewards'
|
||||||
import {
|
import {
|
||||||
doClaimReward,
|
doClaimReward,
|
||||||
|
doClaimRewardClearError
|
||||||
} from 'actions/rewards'
|
} from 'actions/rewards'
|
||||||
import RewardLink from './view'
|
import RewardLink from './view'
|
||||||
|
|
||||||
const makeSelect = () => {
|
const makeSelect = () => {
|
||||||
const selectHasClaimedReward = makeSelectHasClaimedReward()
|
const selectHasClaimedReward = makeSelectHasClaimedReward()
|
||||||
|
const selectIsPending = makeSelectIsRewardClaimPending()
|
||||||
|
const selectError = makeSelectClaimRewardError()
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
claimed: selectHasClaimedReward(state, props)
|
isClaimed: selectHasClaimedReward(state, props),
|
||||||
|
errorMessage: selectError(state, props),
|
||||||
|
isPending: selectIsPending(state, props)
|
||||||
})
|
})
|
||||||
|
|
||||||
return select
|
return select
|
||||||
|
@ -22,6 +29,7 @@ const makeSelect = () => {
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
claimReward: (reward) => dispatch(doClaimReward(reward)),
|
claimReward: (reward) => dispatch(doClaimReward(reward)),
|
||||||
|
clearError: (reward) => dispatch(doClaimRewardClearError(reward))
|
||||||
})
|
})
|
||||||
|
|
||||||
export default connect(makeSelect, perform)(RewardLink)
|
export default connect(makeSelect, perform)(RewardLink)
|
||||||
|
|
|
@ -1,116 +1,27 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import lbry from 'lbry'
|
|
||||||
import {Icon} from 'component/common';
|
import {Icon} from 'component/common';
|
||||||
import Modal from 'component/modal';
|
import Modal from 'component/modal';
|
||||||
import rewards from 'rewards';
|
|
||||||
import Link from 'component/link'
|
import Link from 'component/link'
|
||||||
|
|
||||||
// class RewardLink extends React.Component {
|
|
||||||
// static propTypes = {
|
|
||||||
// type: React.PropTypes.string.isRequired,
|
|
||||||
// claimed: React.PropTypes.bool,
|
|
||||||
// onRewardClaim: React.PropTypes.func,
|
|
||||||
// onRewardFailure: React.PropTypes.func
|
|
||||||
// }
|
|
||||||
|
|
||||||
// constructor(props) {
|
|
||||||
// super(props);
|
|
||||||
|
|
||||||
// this.state = {
|
|
||||||
// claimable: true,
|
|
||||||
// pending: false,
|
|
||||||
// errorMessage: null
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// refreshClaimable() {
|
|
||||||
// switch(this.props.type) {
|
|
||||||
// case 'new_user':
|
|
||||||
// this.setState({ claimable: true });
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// case 'first_publish':
|
|
||||||
// lbry.claim_list_mine().then((list) => {
|
|
||||||
// this.setState({
|
|
||||||
// claimable: list.length > 0
|
|
||||||
// })
|
|
||||||
// });
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// componentWillMount() {
|
|
||||||
// this.refreshClaimable();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// claimReward() {
|
|
||||||
// this.setState({
|
|
||||||
// pending: true
|
|
||||||
// })
|
|
||||||
|
|
||||||
// rewards.claimReward(this.props.type).then((reward) => {
|
|
||||||
// this.setState({
|
|
||||||
// pending: false,
|
|
||||||
// errorMessage: null
|
|
||||||
// })
|
|
||||||
// if (this.props.onRewardClaim) {
|
|
||||||
// this.props.onRewardClaim(reward);
|
|
||||||
// }
|
|
||||||
// }).catch((error) => {
|
|
||||||
// this.setState({
|
|
||||||
// errorMessage: error.message,
|
|
||||||
// pending: false
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// clearError() {
|
|
||||||
// if (this.props.onRewardFailure) {
|
|
||||||
// this.props.onRewardFailure()
|
|
||||||
// }
|
|
||||||
// this.setState({
|
|
||||||
// errorMessage: null
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// render() {
|
|
||||||
// return (
|
|
||||||
// <div className="reward-link">
|
|
||||||
// {this.props.claimed
|
|
||||||
// ? <span><Icon icon="icon-check" /> Reward claimed.</span>
|
|
||||||
// : <Link button={this.props.button ? this.props.button : 'alt'} disabled={this.state.pending || !this.state.claimable }
|
|
||||||
// label={ this.state.pending ? "Claiming..." : "Claim Reward"} onClick={() => { this.claimReward() }} />}
|
|
||||||
// {this.state.errorMessage ?
|
|
||||||
// <Modal isOpen={true} contentLabel="Reward Claim Error" className="error-modal" onConfirmed={() => { this.clearError() }}>
|
|
||||||
// {this.state.errorMessage}
|
|
||||||
// </Modal>
|
|
||||||
// : ''}
|
|
||||||
// </div>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
const RewardLink = (props) => {
|
const RewardLink = (props) => {
|
||||||
const {
|
const {
|
||||||
reward,
|
reward,
|
||||||
claimed,
|
|
||||||
button,
|
button,
|
||||||
pending,
|
|
||||||
claimable = true,
|
|
||||||
claimReward,
|
claimReward,
|
||||||
errorMessage,
|
|
||||||
clearError,
|
clearError,
|
||||||
|
errorMessage,
|
||||||
|
isClaimed,
|
||||||
|
isPending
|
||||||
} = props
|
} = props
|
||||||
|
console.log(props)
|
||||||
return (
|
return (
|
||||||
<div className="reward-link">
|
<div className="reward-link">
|
||||||
{claimed
|
{isClaimed
|
||||||
? <span><Icon icon="icon-check" /> Reward claimed.</span>
|
? <span><Icon icon="icon-check" /> Reward claimed.</span>
|
||||||
: <Link button={button ? button : 'alt'} disabled={pending || !claimable }
|
: <Link button={button ? button : 'alt'} disabled={isPending}
|
||||||
label={ pending ? "Claiming..." : "Claim Reward"} onClick={() => { claimReward(reward) }} />}
|
label={ isPending ? "Claiming..." : "Claim Reward"} onClick={() => { claimReward(reward) }} />}
|
||||||
{errorMessage ?
|
{errorMessage ?
|
||||||
<Modal isOpen={true} contentLabel="Reward Claim Error" className="error-modal" onConfirmed={() => { clearError() }}>
|
<Modal isOpen={true} contentLabel="Reward Claim Error" className="error-modal" onConfirmed={() => { clearError(reward) }}>
|
||||||
{errorMessage}
|
{errorMessage}
|
||||||
</Modal>
|
</Modal>
|
||||||
: ''}
|
: ''}
|
||||||
|
|
23
ui/js/component/userEmailNew/index.jsx
Normal file
23
ui/js/component/userEmailNew/index.jsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {
|
||||||
|
connect
|
||||||
|
} from 'react-redux'
|
||||||
|
import {
|
||||||
|
doUserEmailNew
|
||||||
|
} from 'actions/user'
|
||||||
|
import {
|
||||||
|
selectEmailNewIsPending,
|
||||||
|
selectEmailNewErrorMessage,
|
||||||
|
} from '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)
|
43
ui/js/component/userEmailNew/view.jsx
Normal file
43
ui/js/component/userEmailNew/view.jsx
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Link from 'component/link';
|
||||||
|
import {FormRow} from 'component/form.js';
|
||||||
|
|
||||||
|
class UserEmailNew extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
email: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEmailChanged(event) {
|
||||||
|
this.setState({
|
||||||
|
email: event.target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.props.addUserEmail(this.state.email)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
errorMessage,
|
||||||
|
isPending
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return <form onSubmit={(event) => { this.handleSubmit(event) }}>
|
||||||
|
<FormRow type="text" label="Email" placeholder="scrwvwls@lbry.io"
|
||||||
|
name="email" value={this.state.email}
|
||||||
|
errorMessage={errorMessage}
|
||||||
|
onChange={(event) => { this.handleEmailChanged(event) }} />
|
||||||
|
<div className="form-row-submit">
|
||||||
|
<Link button="primary" label="Next" disabled={isPending} onClick={(event) => { this.handleSubmit(event) }} />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserEmailNew
|
|
@ -74,10 +74,16 @@ export const DAEMON_SETTINGS_RECEIVED = "DAEMON_SETTINGS_RECEIVED";
|
||||||
export const AUTHENTICATION_STARTED = 'AUTHENTICATION_STARTED'
|
export const AUTHENTICATION_STARTED = 'AUTHENTICATION_STARTED'
|
||||||
export const AUTHENTICATION_SUCCESS = 'AUTHENTICATION_SUCCESS'
|
export const AUTHENTICATION_SUCCESS = 'AUTHENTICATION_SUCCESS'
|
||||||
export const AUTHENTICATION_FAILURE = 'AUTHENTICATION_FAILURE'
|
export const AUTHENTICATION_FAILURE = 'AUTHENTICATION_FAILURE'
|
||||||
|
export const USER_EMAIL_DECLINE = 'USER_EMAIL_DECLINE'
|
||||||
|
export const USER_EMAIL_NEW_STARTED = 'USER_EMAIL_NEW_STARTED'
|
||||||
|
export const USER_EMAIL_NEW_SUCCESS = 'USER_EMAIL_NEW_SUCCESS'
|
||||||
|
export const USER_EMAIL_NEW_EXISTS = 'USER_EMAIL_NEW_EXISTS'
|
||||||
|
export const USER_EMAIL_NEW_FAILURE = 'USER_EMAIL_NEW_FAILURE'
|
||||||
|
|
||||||
// Rewards
|
// Rewards
|
||||||
export const FETCH_REWARDS_STARTED = 'FETCH_REWARDS_STARTED'
|
export const FETCH_REWARDS_STARTED = 'FETCH_REWARDS_STARTED'
|
||||||
export const FETCH_REWARDS_COMPLETED = 'FETCH_REWARDS_COMPLETED'
|
export const FETCH_REWARDS_COMPLETED = 'FETCH_REWARDS_COMPLETED'
|
||||||
export const CLAIM_REWARD_STARTED = 'CLAIM_REWARD_STARTED'
|
export const CLAIM_REWARD_STARTED = 'CLAIM_REWARD_STARTED'
|
||||||
export const CLAIM_REWARD_COMPLETED = 'CLAIM_REWARD_COMPLETED'
|
export const CLAIM_REWARD_SUCCESS = 'CLAIM_REWARD_SUCCESS'
|
||||||
|
export const CLAIM_REWARD_FAILURE = 'CLAIM_REWARD_FAILURE'
|
||||||
|
export const CLAIM_REWARD_CLEAR_ERROR = 'CLAIM_REWARD_CLEAR_ERROR'
|
||||||
|
|
|
@ -144,7 +144,7 @@ lbryio.authenticate = function() {
|
||||||
lbryio._authenticationPromise = new Promise((resolve, reject) => {
|
lbryio._authenticationPromise = new Promise((resolve, reject) => {
|
||||||
lbry.status().then((response) => {
|
lbry.status().then((response) => {
|
||||||
|
|
||||||
let installation_id = response.installation_id.substring(0, response.installation_id.length - 6) + "C";
|
let installation_id = response.installation_id.substring(0, response.installation_id.length - 2) + "D";
|
||||||
|
|
||||||
function setCurrentUser() {
|
function setCurrentUser() {
|
||||||
lbryio.call('user', 'me').then((data) => {
|
lbryio.call('user', 'me').then((data) => {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
} from 'react-redux'
|
} from 'react-redux'
|
||||||
import {
|
import {
|
||||||
selectFetchingRewards,
|
selectFetchingRewards,
|
||||||
|
selectIsRewardEligible,
|
||||||
selectRewards,
|
selectRewards,
|
||||||
} from 'selectors/rewards'
|
} from 'selectors/rewards'
|
||||||
import RewardsPage from './view'
|
import RewardsPage from './view'
|
||||||
|
|
|
@ -16,7 +16,7 @@ const RewardTile = (props) => {
|
||||||
<div className="card__inner">
|
<div className="card__inner">
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<CreditAmount amount={reward.reward_amount} />
|
<CreditAmount amount={reward.reward_amount} />
|
||||||
<h3>{reward.title}</h3>
|
<h3>{reward.reward_title}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__actions">
|
<div className="card__actions">
|
||||||
{claimed
|
{claimed
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import * as types from "constants/action_types";
|
import * as types from "constants/action_types";
|
||||||
|
|
||||||
const reducers = {};
|
const reducers = {}
|
||||||
const defaultState = {};
|
const defaultState = {
|
||||||
|
fetching: false,
|
||||||
|
claimPendingByType: {},
|
||||||
|
claimErrorsByType: {}
|
||||||
|
};
|
||||||
|
|
||||||
reducers[types.FETCH_REWARDS_STARTED] = function(state, action) {
|
reducers[types.FETCH_REWARDS_STARTED] = function(state, action) {
|
||||||
const newRewards = Object.assign({}, state.rewards, {
|
const newRewards = Object.assign({}, state.rewards, {
|
||||||
|
@ -26,28 +30,49 @@ reducers[types.FETCH_REWARDS_COMPLETED] = function(state, action) {
|
||||||
return Object.assign({}, state, newRewards)
|
return Object.assign({}, state, newRewards)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setClaimRewardState(state, reward, isClaiming, errorMessage="") {
|
||||||
|
const newClaimPendingByType = Object.assign({}, state.claimPendingByType)
|
||||||
|
const newClaimErrorsByType = Object.assign({}, state.claimErrorsByType)
|
||||||
|
newClaimPendingByType[reward.reward_type] = isClaiming
|
||||||
|
newClaimErrorsByType[reward.reward_type] = errorMessage
|
||||||
|
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
claimPendingByType: newClaimPendingByType,
|
||||||
|
claimErrorsByType: newClaimErrorsByType,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
reducers[types.CLAIM_REWARD_STARTED] = function(state, action) {
|
reducers[types.CLAIM_REWARD_STARTED] = function(state, action) {
|
||||||
const {
|
const {
|
||||||
reward,
|
reward,
|
||||||
} = action.data
|
} = action.data
|
||||||
|
|
||||||
const newRewards = Object.assign({}, state, {
|
return setClaimRewardState(state, reward, true, "")
|
||||||
claiming: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
return Object.assign({}, state, newRewards)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reducers[types.CLAIM_REWARD_COMPLETED] = function(state, action) {
|
reducers[types.CLAIM_REWARD_SUCCESS] = function(state, action) {
|
||||||
const {
|
const {
|
||||||
reward,
|
reward,
|
||||||
} = action.data
|
} = action.data
|
||||||
|
|
||||||
const newRewards = Object.assign({}, state, {
|
return setClaimRewardState(state, reward, false, "")
|
||||||
claiming: false,
|
}
|
||||||
})
|
|
||||||
|
|
||||||
return Object.assign({}, state, newRewards)
|
reducers[types.CLAIM_REWARD_FAILURE] = function(state, action) {
|
||||||
|
const {
|
||||||
|
reward,
|
||||||
|
error
|
||||||
|
} = action.data
|
||||||
|
|
||||||
|
return setClaimRewardState(state, reward, false, error.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
reducers[types.CLAIM_REWARD_CLEAR_ERROR] = function(state, action) {
|
||||||
|
const {
|
||||||
|
reward
|
||||||
|
} = action.data
|
||||||
|
|
||||||
|
return setClaimRewardState(state, reward, state.claimPendingByType[reward.reward_type], "")
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function reducer(state = defaultState, action) {
|
export default function reducer(state = defaultState, action) {
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
import * as types from 'constants/action_types'
|
import * as types from 'constants/action_types'
|
||||||
|
import {
|
||||||
|
getLocal
|
||||||
|
} from 'utils'
|
||||||
|
|
||||||
const reducers = {}
|
const reducers = {}
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
authenticationIsPending: false,
|
authenticationIsPending: false,
|
||||||
|
emailNewIsPending: false,
|
||||||
|
emailNewErrorMessage: '',
|
||||||
|
emailNewDeclined: getLocal('user_email_declined', false),
|
||||||
user: undefined
|
user: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +33,40 @@ reducers[types.AUTHENTICATION_FAILURE] = function(state, action) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reducers[types.USER_EMAIL_DECLINE] = function(state, action) {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
emailNewDeclined: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
reducers[types.USER_EMAIL_NEW_STARTED] = function(state, action) {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
emailNewIsPending: true,
|
||||||
|
emailNewErrorMessage: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
reducers[types.USER_EMAIL_NEW_SUCCESS] = function(state, action) {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
emailNewIsPending: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
reducers[types.USER_EMAIL_NEW_EXISTS] = function(state, action) {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
emailNewIsPending: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
reducers[types.USER_EMAIL_NEW_FAILURE] = function(state, action) {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
emailNewIsPending: false,
|
||||||
|
emailNewErrorMessage: action.data.error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default function reducer(state = defaultState, action) {
|
export default function reducer(state = defaultState, action) {
|
||||||
const handler = reducers[action.type];
|
const handler = reducers[action.type];
|
||||||
if (handler) return handler(state, action);
|
if (handler) return handler(state, action);
|
||||||
|
|
|
@ -93,7 +93,7 @@ rewards.TYPE_FEATURED_DOWNLOAD = 'featured_download';
|
||||||
|
|
||||||
rewards.claimReward = function(type) {
|
rewards.claimReward = function(type) {
|
||||||
function requestReward(resolve, reject, params) {
|
function requestReward(resolve, reject, params) {
|
||||||
if (!lbryio.enabled) {
|
if (!lbryio.enabled || !lbryio.getAccessToken()) {
|
||||||
reject(new Error(__('Rewards are not enabled.')));
|
reject(new Error(__('Rewards are not enabled.')));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,10 @@ rewards.claimReward = function(type) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
rewards.claimEligiblePurchaseRewards = function() {
|
rewards.claimEligiblePurchaseRewards = () => {
|
||||||
|
if (!lbryio.enabled || !lbryio.getAccessToken()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let types = {};
|
let types = {};
|
||||||
types[rewards.TYPE_FIRST_STREAM] = false;
|
types[rewards.TYPE_FIRST_STREAM] = false;
|
||||||
types[rewards.TYPE_FEATURED_DOWNLOAD] = false;
|
types[rewards.TYPE_FEATURED_DOWNLOAD] = false;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { createSelector } from "reselect";
|
import { createSelector } from "reselect";
|
||||||
|
import { selectUser } from "selectors/user";
|
||||||
|
|
||||||
const _selectState = state => state.rewards || {};
|
const _selectState = state => state.rewards || {};
|
||||||
|
|
||||||
|
@ -12,6 +13,11 @@ export const selectRewards = createSelector(
|
||||||
(byType) => Object.values(byType) || []
|
(byType) => Object.values(byType) || []
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const selectIsRewardEligible = createSelector(
|
||||||
|
selectUser,
|
||||||
|
(user) => user.can_claim_rewards
|
||||||
|
)
|
||||||
|
|
||||||
export const selectClaimedRewards = createSelector(
|
export const selectClaimedRewards = createSelector(
|
||||||
selectRewards,
|
selectRewards,
|
||||||
(rewards) => rewards.filter(reward => reward.transaction_id !== "")
|
(rewards) => rewards.filter(reward => reward.transaction_id !== "")
|
||||||
|
@ -20,7 +26,7 @@ export const selectClaimedRewards = createSelector(
|
||||||
export const selectClaimedRewardsByType = createSelector(
|
export const selectClaimedRewardsByType = createSelector(
|
||||||
selectClaimedRewards,
|
selectClaimedRewards,
|
||||||
(claimedRewards) => {
|
(claimedRewards) => {
|
||||||
const byType = []
|
const byType = {}
|
||||||
claimedRewards.forEach(reward => byType[reward.reward_type] = reward)
|
claimedRewards.forEach(reward => byType[reward.reward_type] = reward)
|
||||||
return byType
|
return byType
|
||||||
}
|
}
|
||||||
|
@ -42,6 +48,39 @@ export const makeSelectHasClaimedReward = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const selectClaimsPendingByType = createSelector(
|
||||||
|
_selectState,
|
||||||
|
(state) => state.claimPendingByType
|
||||||
|
)
|
||||||
|
|
||||||
|
const selectIsClaimRewardPending = (state, props) => {
|
||||||
|
return selectClaimsPendingByType(state, props)[props.reward.reward_type]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeSelectIsRewardClaimPending = () => {
|
||||||
|
return createSelector(
|
||||||
|
selectIsClaimRewardPending,
|
||||||
|
(isClaiming) => isClaiming
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const selectClaimErrorsByType = createSelector(
|
||||||
|
_selectState,
|
||||||
|
(state) => state.claimErrorsByType
|
||||||
|
)
|
||||||
|
|
||||||
|
const selectClaimRewardError = (state, props) => {
|
||||||
|
console.log(selectClaimErrorsByType(state, props));
|
||||||
|
return selectClaimErrorsByType(state, props)[props.reward.reward_type]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeSelectClaimRewardError = () => {
|
||||||
|
return createSelector(
|
||||||
|
selectClaimRewardError,
|
||||||
|
(errorMessage) => errorMessage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const selectRewardByType = (state, props) => {
|
const selectRewardByType = (state, props) => {
|
||||||
return selectRewardsByType(state)[props.reward_type]
|
return selectRewardsByType(state)[props.reward_type]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,22 @@ export const selectAuthenticationIsPending = createSelector(
|
||||||
(state) => state.authenticationIsPending
|
(state) => state.authenticationIsPending
|
||||||
)
|
)
|
||||||
|
|
||||||
export const selectAuthenticationIsFailed = createSelector(
|
export const selectUser = createSelector(
|
||||||
_selectState,
|
_selectState,
|
||||||
(state) => state.user === null
|
(state) => state.user
|
||||||
|
)
|
||||||
|
|
||||||
|
export const selectEmailNewIsPending = createSelector(
|
||||||
|
_selectState,
|
||||||
|
(state) => state.emailNewIsPending
|
||||||
|
)
|
||||||
|
|
||||||
|
export const selectEmailNewErrorMessage = createSelector(
|
||||||
|
_selectState,
|
||||||
|
(state) => state.emailNewErrorMessage
|
||||||
|
)
|
||||||
|
|
||||||
|
export const selectEmailNewDeclined = createSelector(
|
||||||
|
_selectState,
|
||||||
|
(state) => state.emailNewDeclined
|
||||||
)
|
)
|
Loading…
Reference in a new issue